<commit_before>$(document).ready(function() {
    var centerX = ($(window).width() / 2) - 250;
    var centerY = ($(window).height() / 2) - 250;
    var scale = scalefactor();
    var anglesNow = [0,0,0,0,0,0];
    var count = 0;
    var winWidth = $(window).width();
    var winHeight = $(window).height();
    $(document).mousemove(function(e) {
        var x = e.pageX;
        var y = e.pageY;
        var rotateY = (360 / winWidth) * y;
        var rotateX = (360 / winHeight) * x;
        if (count === 0) {
            $('.cube').css({
                'transform': '  translate3d(50%, 50%, -1000px)   rotateY(' + rotateX + 'deg) rotateX(' + rotateY + 'deg)',
            });
        }
    });
    if (count === 0) {
        $(".cube").click(function() {
            $('.side.top, .side.left, .side.right,.side.bottom,.side.back,.side.front,.cube').addClass('flat');
            count += 1;
            $('.cube').css({
                'transform': ' translate3d(50%, 30%, -1000px) rotateY(' + '0' + 'deg) rotateX(' + '0' + 'deg) ',
                'transition': ' all 1.8s ease',
                cursor: 'default'
            });
            $(".cube .bottom .back").css("background","#fff");
            $(this).off();
            setTimeout(function() {
                $('.cube, .cube .side').css('-webkit-transform-style','flat').css('transform','none');
                transform(2, 'translate');
            }, 1800);
            setTimeout(function(){
                $(".unfolded").css({
                    display: 'inline'
                });
                $(".cube").css("background","#fff");
            },2000);
        });
    }
    var angleCount = 3;

    function transform(face, transformType) {
        //rotation matrix, with scale according to scale factor
        var value = [
            [0, -scale, scale, 0],
            [-scale, 0, 0, -scale],
            [0, scale, -scale, 0],
            [scale, 0, 0, scale]
        ];
        var moveTo = [
            [centerX, centerY + 480, '50% -46% 0'],
            [centerX + 480, centerY, '-46% 50% 0'],
            [centerX, centerY, '50% 50% 0'],
            [centerX - 480, centerY, '146% 50% 0'],
            [centerX, centerY - 480, '50% 146% 0'],
            [centerX, centerY - 960, '50% 242% 0']
        ];
        if (transformType == 'rotate') {
            //add one to the rotation counter
            angleCount += 1;
            if (angleCount > 3) {
                angleCount = 0;
            }
            //if not, just preserve previous rotation and translate
        }
        // transformation matrices for rotating around the face at position moveTo[]
        $('.cube').css({
            transform: 'matrix(' + value[3] + ','
            					 + moveTo[face][0] + ','
            					 + moveTo[face][1] + ')',
            transition: "all 0.3s ease",
            'transform-origin': moveTo[face][2]
        });
    }
    var $elem = $('#page-content3');
    $('div.rotate-button').click(function() {
        var id = $(this).attr('id');
        // transform(id, 'rotate');

        // caching the object for performance reasons

        switch(id){
            case '0':
                $elem = $('#page-content3');
                break;
            case '1':
                $elem = $('#page-content5');
                break;
            case '2':
                $elem = $('#page-content0');
                break;
            case '3':
                $elem = $('#page-content4');
                break;
            case '4':
                $elem = $('#page-content2');
                break;
            case '5':
                $elem = $('#page-content1');
                break;
        }

        // we use a pseudo object for the animation
        // (starts from `0` to `angle`), you can name it as you want
        $({deg: anglesNow[id]}).animate({deg: anglesNow[id]+90}, {
            duration: 500,
            step: function(now) {
                // in the step-callback (that is fired each step of the animation),
                // you can use the `now` paramter which contains the current
                // animation-position (`0` up to `angle`)
                $elem.css({
                     transform: 'rotate(' + now + 'deg)'
                });
            }
        });
        anglesNow[id]=anglesNow[id]+90;
    });
    $('div.translate').click(function() {
        var id = $(this).attr('id');
        transform(id, 'translate');
    });
});
//helper function to find window width
function orienttest() {
    var w = $(window).width();
    var h = $(window).height();
    if (w > h) {
        return h;
    } else {
        return w;
    }
}
//helper function find max zoom factor
function scalefactor() {
    var cube = $('.cube').width();
    var sf = orienttest() / cube;
    return sf;
}

// By Kenneth Lim
$(document).ready(function(){
    var list1 = "",
        list2 = "",
        list3 = "",
        list4 = "";

    var studentNames = [
        'Adam Willis',
        'Adhiraj Singh',
        'Aisha A Olatokunbo Tijani',
        'Amy Chau',
        'Amy Louise Elms',
        'Angele T A M Delajoux',
        'Anh Thu Dam',
        'Atikhun Jansanjai',
        'Barnaby Pau Jury Morgan',
        'Benjamin Ezekiel Sing',
        'ChinHwee Tan',
        'Claire Ann Köster',
        'Clara Alicia Metter',
        'Connor Daly',
        'Eftal Soral',
        'Emilien Malo Rabin',
        'Emily Schofield',
        'Gaetan Bernede',
        'Gautam Tankaria',
        'Georgia Cranstoun',
        'Hannah Nightingale',
        'Hattie Wade',
        'Ho Yiu Frankie Leung',
        'Hortense Franc',
        'Isobel Ann Lily Orton',
        'Jack Smith',
        'Jasmine Kurino',
        'Jillian Ostek',
        'Jiwon Song (Sophia)',
        'John Cubillan',
        'Jordan DeVos',
        'Jordan Woodage',
        'Joshua James Smith',
        'Kateryna Kotikhina',
        'Katie Lambe',
        'Ke Fan',
        'Kerry McGranaghan',
        'Lara Bashar Arafeh',
        'Lars Høie',
        'Liisa Roll',
        'Louisa Luk',
        'Louise Carolina Dyhrfort',
        'Luying Xu',
        'Melissa Zee',
        'Michael Sierra',
        'Mika Hosono',
        'Natalie Preston',
        'Navjot Singh Chana',
        'Nikki Johanna Ritmeijer',
        'Oi Kei Elky Li',
        'Olga Bagaeva',
        'Olga Carpenco',
        'Philippine M C Sohet',
        'Pui Sang Wu',
        'Rafael Bruni De Lima',
        'Raymond Hui',
        'Rebecca Bartola',
        'Rebecca Lardeur',
        'Satoko Furusawa',
        'Sean Wei Jun Song',
        'Shannon Swinburn',
        'Shiau Hui Choy, Amanda',
        'Stephanie Nadine Kaiser',
        'Su Jung Choi',
        'Ta-Chun Hung',
        'Tatiana Ermolaeva',
        'Theo Bernard',
        'Therese Cappelen',
        'Varvara Zelenko',
        'Vorathap Kiathapkajon',
        'Xinxin Zheng',
        'Yangzi Wang',
        'Yi Lin Kezia Kong',
        'Yi-Hsuan Chen',
        'Yuli Serfaty',
        'Kenneth Lim'];

    for(i=0; i<19; i++){
            list1 = list1 + "
" + studentNames[i] + "
";
            list2 = list2 + "
" + studentNames[i+19] + "
";
            list3 = list3 + "
" + studentNames[i+38] + "
";
            list4 = list4 + "
" + studentNames[i+57] + "
";
    }
    $("#page-content1 #nameList1").html(list1);
    $("#page-content2 #nameList2").html(list2);
    $("#page-content2 #nameList3").html(list3);
    $("#page-content1 #nameList4").html(list4);

    $(".navigation").hover(function(){
        $(this).css("opacity", "1");
    },function(){
        $(this).css("opacity", "0.3");
    })

    // $(window).click(function(e){
    //     // caching the object for performance reasons
    //     var $elem = $('.page-content');

    //     // we use a pseudo object for the animation
    //     // (starts from `0` to `angle`), you can name it as you want
    //     $({deg: anglesNow}).animate({deg: anglesNow+90}, {
    //         duration: 500,
    //         step: function(now) {
    //             // in the step-callback (that is fired each step of the animation),
    //             // you can use the `now` paramter which contains the current
    //             // animation-position (`0` up to `angle`)
    //             $elem.css({
    //                  transform: 'rotate(' + now + 'deg)'
    //             });
    //         }
    //     });
    //     anglesNow=anglesNow+90;
    // });
});<commit_msg>Updated student list<commit_after>$(document).ready(function() {
    var centerX = ($(window).width() / 2) - 250;
    var centerY = ($(window).height() / 2) - 250;
    var scale = scalefactor();
    var anglesNow = [0,0,0,0,0,0];
    var count = 0;
    var winWidth = $(window).width();
    var winHeight = $(window).height();
    $(document).mousemove(function(e) {
        var x = e.pageX;
        var y = e.pageY;
        var rotateY = (360 / winWidth) * y;
        var rotateX = (360 / winHeight) * x;
        if (count === 0) {
            $('.cube').css({
                'transform': '  translate3d(50%, 50%, -1000px)   rotateY(' + rotateX + 'deg) rotateX(' + rotateY + 'deg)',
            });
        }
    });
    if (count === 0) {
        $(".cube").click(function() {
            $('.side.top, .side.left, .side.right,.side.bottom,.side.back,.side.front,.cube').addClass('flat');
            count += 1;
            $('.cube').css({
                'transform': ' translate3d(50%, 30%, -1000px) rotateY(' + '0' + 'deg) rotateX(' + '0' + 'deg) ',
                'transition': ' all 1.8s ease',
                cursor: 'default'
            });
            $(".cube .bottom .back").css("background","#fff");
            $(this).off();
            setTimeout(function() {
                $('.cube, .cube .side').css('-webkit-transform-style','flat').css('transform','none');
                transform(2, 'translate');
            }, 1800);
            setTimeout(function(){
                $(".unfolded").css({
                    display: 'inline'
                });
                $(".cube").css("background","#fff");
            },2000);
        });
    }
    var angleCount = 3;

    function transform(face, transformType) {
        //rotation matrix, with scale according to scale factor
        var value = [
            [0, -scale, scale, 0],
            [-scale, 0, 0, -scale],
            [0, scale, -scale, 0],
            [scale, 0, 0, scale]
        ];
        var moveTo = [
            [centerX, centerY + 480, '50% -46% 0'],
            [centerX + 480, centerY, '-46% 50% 0'],
            [centerX, centerY, '50% 50% 0'],
            [centerX - 480, centerY, '146% 50% 0'],
            [centerX, centerY - 480, '50% 146% 0'],
            [centerX, centerY - 960, '50% 242% 0']
        ];
        if (transformType == 'rotate') {
            //add one to the rotation counter
            angleCount += 1;
            if (angleCount > 3) {
                angleCount = 0;
            }
            //if not, just preserve previous rotation and translate
        }
        // transformation matrices for rotating around the face at position moveTo[]
        $('.cube').css({
            transform: 'matrix(' + value[3] + ','
            					 + moveTo[face][0] + ','
            					 + moveTo[face][1] + ')',
            transition: "all 0.3s ease",
            'transform-origin': moveTo[face][2]
        });
    }
    var $elem = $('#page-content3');
    $('div.rotate-button').click(function() {
        var id = $(this).attr('id');
        // transform(id, 'rotate');

        // caching the object for performance reasons

        switch(id){
            case '0':
                $elem = $('#page-content3');
                break;
            case '1':
                $elem = $('#page-content5');
                break;
            case '2':
                $elem = $('#page-content0');
                break;
            case '3':
                $elem = $('#page-content4');
                break;
            case '4':
                $elem = $('#page-content2');
                break;
            case '5':
                $elem = $('#page-content1');
                break;
        }

        // we use a pseudo object for the animation
        // (starts from `0` to `angle`), you can name it as you want
        $({deg: anglesNow[id]}).animate({deg: anglesNow[id]+90}, {
            duration: 500,
            step: function(now) {
                // in the step-callback (that is fired each step of the animation),
                // you can use the `now` paramter which contains the current
                // animation-position (`0` up to `angle`)
                $elem.css({
                     transform: 'rotate(' + now + 'deg)'
                });
            }
        });
        anglesNow[id]=anglesNow[id]+90;
    });
    $('div.translate').click(function() {
        var id = $(this).attr('id');
        transform(id, 'translate');
    });
});
//helper function to find window width
function orienttest() {
    var w = $(window).width();
    var h = $(window).height();
    if (w > h) {
        return h;
    } else {
        return w;
    }
}
//helper function find max zoom factor
function scalefactor() {
    var cube = $('.cube').width();
    var sf = orienttest() / cube;
    return sf;
}

// By Kenneth Lim
$(document).ready(function(){
    var list1 = "",
        list2 = "",
        list3 = "",
        list4 = "";

    var studentNames = [
        'Adam Willis',
        'Adhiraj Singh',
        'Aisha Tijani',
        'Amy Chau',
        'Amy Louise Elms',
        'Angele T A M Delajoux',
        'Anh Thu Dam',
        'Atikhun Jansanjai',
        'Barnaby Pau Jury Morgan',
        'Benjamin Ezekiel Sing',
        'ChinHwee Tan',
        'Claire Ann Köster',
        'Clara Alicia Metter',
        'Connor Daly',
        'Eftal Soral',
        'Emilien Malo Rabin',
        'Emily Schofield',
        'Gaetan Bernede',
        'Gautam Tankaria',
        'Georgia Cranstoun',
        'Hannah Nightingale',
        'Hattie Wade',
        'Ho Yiu Frankie Leung',
        'Hortense Franc',
        'Isobel Ann Lily Orton',
        'Jack Smith',
        'Jasmine Kurino',
        'Jillian Ostek',
        'Jiwon Song (Sophia)',
        'John Cubillan',
        'Jordan DeVos',
        'Jordan Woodage',
        'Joshua James Smith',
        'Kateryna Kotikhina',
        'Katie Lambe',
        'Ke Fan',
        'Kerry McGranaghan',
        'Lara Bashar Arafeh',
        'Lars Høie',
        'Liisa Roll',
        'Louisa Luk',
        'Louise Carolina Dyhrfort',
        'Luying Xu',
        'Melissa Zee',
        'Michael Sierra',
        'Mika Hosono',
        'Natalie Preston',
        'Navjot Singh Chana',
        'Nikki Johanna Ritmeijer',
        'Elky Li',
        'Olga Bagaeva',
        'Olga Carpenco',
        'Philippine Sohet',
        'Pui Sang Wu',
        'Rafael Bruni De Lima',
        'Raymond Hui',
        'Rebecca Bartola',
        'Rebecca Lardeur',
        'Satoko Furusawa',
        'Sean Wei Jun Song',
        'Shannon Swinburn',
        'Shiau Hui Choy, Amanda',
        'Stephanie Nadine Kaiser',
        'Su Jung Choi',
        'Ta-Chun Hung',
        'Tatiana Ermolaeva',
        'Theo Bernard',
        'Therese Cappelen',
        'Varvara Zelenko',
        'Vorathap Kiathapkajon',
        'Xinxin Zheng',
        'Yangzi Wang',
        'Yi Lin Kezia Kong',
        'Mia Chen',
        'Yuli Serfaty',
        'Kenneth Lim',
        'Bernardita Rodriguez'];

    for(i=0; i<19; i++){
            list1 = list1 + "
" + studentNames[i] + "
";
            list2 = list2 + "
" + studentNames[i+19] + "
";
            list3 = list3 + "
" + studentNames[i+38] + "
";
            list4 = list4 + "
" + studentNames[i+57] + "
";
    }
    $("#page-content1 #nameList1").html(list1);
    $("#page-content2 #nameList2").html(list2);
    $("#page-content2 #nameList3").html(list3);
    $("#page-content1 #nameList4").html(list4);

    $(".navigation").hover(function(){
        $(this).css("opacity", "1");
    },function(){
        $(this).css("opacity", "0.3");
    })

    // $(window).click(function(e){
    //     // caching the object for performance reasons
    //     var $elem = $('.page-content');

    //     // we use a pseudo object for the animation
    //     // (starts from `0` to `angle`), you can name it as you want
    //     $({deg: anglesNow}).animate({deg: anglesNow+90}, {
    //         duration: 500,
    //         step: function(now) {
    //             // in the step-callback (that is fired each step of the animation),
    //             // you can use the `now` paramter which contains the current
    //             // animation-position (`0` up to `angle`)
    //             $elem.css({
    //                  transform: 'rotate(' + now + 'deg)'
    //             });
    //         }
    //     });
    //     anglesNow=anglesNow+90;
    // });
});<|endoftext|>


<commit_before>var Suppliers = require('../../models/Supplier');

var mongoose = require('mongoose');
var EVResponse = require('./../EVResponse.js');
var Rx = require('rxjs/Rx');
var RxMongo = require('./../RxMongo.js');
var EVBody = require('./../EVBody.js');

module.exports = {

  /**
   * @api {get} locations/:location_id GetDetail
   * @apiParam {string} location_id Location_ID want to get detail
   * @apiVersion 0.1.0
   * @apiName GetDetail
   * @apiGroup Locations
   * @apiPermission none
   *
   * @apiDescription  Read location detail info
   *
   *
   * @apiExample Example usage:
   * GET /locations/dasdsadsad
   *
   * @apiSuccess {Number} code                Code Success
   * @apiSuccess {Object} data                Location detail
   * @apiSuccessExample {json} Success-Response:
   *     HTTP/1.1 200 OK
   *     {
     *       code: 200,
     *       data: {
     *        location_id: string,
     *        supplier_id: string,
     *        name: string,
     *        detail: string,
     *        address: string,
     *        link: [string],
     *        image_url: string,
     *        created_date: Number,
     *        location_info: {Object Location},
     *        tags: [string]
     *        status: string,
     *       }
     *     }
   *
   *
   * @apiErrorExample Get locations failure:
   *     HTTP/1.1 402 Get locations failure
   *     {
   *       code : 402
   *       error: "Get locations failure"
  *     }
   */
  getDetail: function(req,res,next) {

    var location_id = req.params.location_id;
    var rx = RxMongo.findOne(Locations,{
      "_id": location_id,
    }, false);

    rx.subscribe(function(doc){
      EVResponse.success(res,doc);
    }, function(error) {
      EVResponse.failure(res,402,error);
    });
  },

  /**
   * @api {post} locations?access_token Create Location
   * @apiParam {string} access_token Authorized access_token
   * @apiVersion 0.1.0
   * @apiName CreateLocation
   * @apiGroup Locations
   * @apiPermission supplier or admin
   *
   * @apiDescription  Create Location
   *
   * @apiParamExample {json} Request-Example-InBody-Required:
   * {
     *        name: string,
     *        detail: string,
     *        address: string,
     *        link: [string],
     *        image_url: string,
     *        created_date: Number,
     *        location_info: {Object Location},
     *        tags: [string]
     *        status: string,
     * }
   *
   *
   * @apiExample Example usage:
   * POST /locations?access_token=asdsad
   *
   * @apiSuccess {Number} code                Code Success
   * @apiSuccess {Object} data                Location detail
   * @apiSuccessExample {json} Success-Response:
   *     HTTP/1.1 200 OK
   *     {
     *       code: 200,
     *       data: {
     *        location_id: string,
     *        supplier_id: string,
     *        name: string,
     *        detail: string,
     *        address: string,
     *        link: [string],
     *        image_url: string,
     *        created_date: Number,
     *        location_info: {Object Location},
     *        tags: [string]
     *        status: string,
     *       }
     *     }
   *
   *
   * @apiErrorExample Access token not true:
   *     HTTP/1.1 401 Access token not true
   *     {
   *       code : 401
   *       error: "Access token not true"
   *     }
   * @apiErrorExample Create location failure:
   *     HTTP/1.1 402 Create location failure
   *     {
   *       code : 402
   *       error: "Create location failure"
   *     }
   */
  create: function(req,res,next) {

    var supplier_id = EVResponse.verifiyAccessToken(req,"supplier_id");
    if (supplier_id == null) {
      EVResponse.failure(res,401,"Access token not true");
      return;
    }
    var LocationInfo = EVBody(req.body);
    LocationInfo.supplier_id = supplier_id;

    var newItem = new Locations(LocationInfo);

    RxMongo.save(newItem).subscribe(function() {
      EVResponse.success(res,newItem);
    }, function(err) {
      EVResponse.failure(res,402, "Create Location failure");
    });
  },

  /**
   * @api {put} locations/:location_id?access_token Update Location
   * @apiParam {string} location_id Location_ID want to update
   * @apiParam {string} access_token Authorized access_token
   * @apiVersion 0.1.0
   * @apiName UpdateLocation
   * @apiGroup Locations
   * @apiPermission supplier or admin
   *
   * @apiDescription  Update Location
   *
   * @apiParamExample {json} Request-Example-InBody-Required:
   * {
     *        name: string,
     *        detail: string,
     *        address: string,
     *        link: [string],
     *        image_url: string,
     *        created_date: Number,
     *        location_info: {Object Location},
     *        tags: [string]
     *        status: string,
     * }
   *
   *
   * @apiExample Example usage:
   * PUT /locations/sdfdsafa?access_token=?
   *
   * @apiSuccess {Number} code                Code Success
   * @apiSuccess {Object} data                Location detail
   * @apiSuccessExample {json} Success-Response:
   *     HTTP/1.1 200 OK
   *     {
     *       code: 200,
     *       data: {
     *        location_id: string,
     *        supplier_id: string,
     *        name: string,
     *        detail: string,
     *        address: string,
     *        link: [string],
     *        image_url: string,
     *        created_date: Number,
     *        location_info: {Object Location},
     *        tags: [string]
     *        status: string,
     *       }
     *     }
   *
   *
   * @apiErrorExample Access token not true:
   *     HTTP/1.1 401 Access token not true
   *     {
   *       code : 401
   *       error: "Access token not true"
   *     }
   * @apiErrorExample Update fail:
   *     HTTP/1.1 402 Update fail
   *     {
   *       code : 402
   *       error: "Update fail with error"
   *     }
   */
  update: function(req,res,next) {

    var supplier_id = EVResponse.verifiyAccessToken(req,"supplier_id");
    if (supplier_id == null) {
      EVResponse.failure(res,401,"Access token not true");
      return;
    }

    var LocationInfo = EVBody(req.body);
    var location_id = req.params.location_id;

    RxMongo.findOneAndUpdated(Locations, {
      "_id": location_id,
      "supplier_id": supplier_id
    }, LocationInfo).subscribe(function(doc){
      EVResponse.success(res,doc);
    }, function(err){
      EVResponse.failure(res,402, "Update Item failure");
    });
  },

  /**
   * @api {delete} locations/:location_id?access_token Delete Location
   * @apiParam {string} location_id Location_ID want to Delete
   * @apiParam {string} access_token Authorized access_token
   * @apiVersion 0.1.0
   * @apiName DeleteLocation
   * @apiGroup Locations
   * @apiPermission supplier or admin
   *
   * @apiDescription  Delete Location
   *
   *
   * @apiExample Example usage:
   * DELETE /locations/sdfdsafa?access_token=asdfdsaf
   *
   * @apiSuccess {Number} code                Code Success
   * @apiSuccess {Object} data                Message
   * @apiSuccessExample {json} Success-Response:
   *     HTTP/1.1 200 OK
   *     {
     *       code: 200,
     *       data: "Success"
     *     }
   *
   *
   * @apiErrorExample Access token not true:
   *     HTTP/1.1 401 Access token not true
   *     {
   *       code : 401
   *       error: "Access token not true"
   *     }
   * @apiErrorExample Delete Location Failure:
   *     HTTP/1.1 402 Delete Location Failure
   *     {
   *       code : 402
   *       error: "Delete Location Failure"
   *     }
   */
  delete: function(req,res,next) {

    var supplier_id = EVResponse.verifiyAccessToken(req,"supplier_id");
    if (supplier_id == null) {
      EVResponse.failure(res,401,"Access token not true");
      return;
    }

    var location_id = req.params.location_id;
    RxMongo.remove(Locations, {
      '_id': location_id,
      'supplier_id': supplier_id
    }).subscribe(function(){
      EVResponse.success(res,"Delete success");
    }, function(err){
      EVResponse.failure(res,402, "Delete Item failure");
    });
  },

};
<commit_msg>[HotFix] Fix bug cho Location<commit_after>var Suppliers = require('../../models/Supplier');
var Locations = require('../../models/Location');

var mongoose = require('mongoose');
var EVResponse = require('./../EVResponse.js');
var Rx = require('rxjs/Rx');
var RxMongo = require('./../RxMongo.js');
var EVBody = require('./../EVBody.js');

module.exports = {

  /**
   * @api {get} locations/:location_id GetDetail
   * @apiParam {string} location_id Location_ID want to get detail
   * @apiVersion 0.1.0
   * @apiName GetDetail
   * @apiGroup Locations
   * @apiPermission none
   *
   * @apiDescription  Read location detail info
   *
   *
   * @apiExample Example usage:
   * GET /locations/dasdsadsad
   *
   * @apiSuccess {Number} code                Code Success
   * @apiSuccess {Object} data                Location detail
   * @apiSuccessExample {json} Success-Response:
   *     HTTP/1.1 200 OK
   *     {
     *       code: 200,
     *       data: {
     *        location_id: string,
     *        supplier_id: string,
     *        name: string,
     *        detail: string,
     *        address: string,
     *        link: [string],
     *        image_url: string,
     *        created_date: Number,
     *        location_info: {Object Location},
     *        tags: [string]
     *        status: string,
     *       }
     *     }
   *
   *
   * @apiErrorExample Get locations failure:
   *     HTTP/1.1 402 Get locations failure
   *     {
   *       code : 402
   *       error: "Get locations failure"
  *     }
   */
  getDetail: function(req,res,next) {

    var location_id = req.params.location_id;
    var rx = RxMongo.findOne(Locations,{
      "_id": location_id,
    }, false);

    rx.subscribe(function(doc){
      EVResponse.success(res,doc);
    }, function(error) {
      EVResponse.failure(res,402,error);
    });
  },

  /**
   * @api {post} locations?access_token Create Location
   * @apiParam {string} access_token Authorized access_token
   * @apiVersion 0.1.0
   * @apiName CreateLocation
   * @apiGroup Locations
   * @apiPermission supplier or admin
   *
   * @apiDescription  Create Location
   *
   * @apiParamExample {json} Request-Example-InBody-Required:
   * {
     *        name: string,
     *        detail: string,
     *        address: string,
     *        link: [string],
     *        image_url: string,
     *        created_date: Number,
     *        location_info: {Object Location},
     *        tags: [string]
     *        status: string,
     * }
   *
   *
   * @apiExample Example usage:
   * POST /locations?access_token=asdsad
   *
   * @apiSuccess {Number} code                Code Success
   * @apiSuccess {Object} data                Location detail
   * @apiSuccessExample {json} Success-Response:
   *     HTTP/1.1 200 OK
   *     {
     *       code: 200,
     *       data: {
     *        location_id: string,
     *        supplier_id: string,
     *        name: string,
     *        detail: string,
     *        address: string,
     *        link: [string],
     *        image_url: string,
     *        created_date: Number,
     *        location_info: {Object Location},
     *        tags: [string]
     *        status: string,
     *       }
     *     }
   *
   *
   * @apiErrorExample Access token not true:
   *     HTTP/1.1 401 Access token not true
   *     {
   *       code : 401
   *       error: "Access token not true"
   *     }
   * @apiErrorExample Create location failure:
   *     HTTP/1.1 402 Create location failure
   *     {
   *       code : 402
   *       error: "Create location failure"
   *     }
   */
  create: function(req,res,next) {

    console.log("Call location");

    var supplier_id = EVResponse.verifiyAccessToken(req,"supplier_id");
    if (supplier_id == null) {
      EVResponse.failure(res,401,"Access token not true");
      return;
    }
    var locationInfo = EVBody(req.body);
    locationInfo.supplier_id = supplier_id;
    var newItem = new Locations(locationInfo);
    console.log(newItem);

    RxMongo.save(newItem).subscribe(function() {
      EVResponse.success(res,newItem);
    }, function(err) {
      EVResponse.failure(res,402, "Create Location failure");
    });
  },

  /**
   * @api {put} locations/:location_id?access_token Update Location
   * @apiParam {string} location_id Location_ID want to update
   * @apiParam {string} access_token Authorized access_token
   * @apiVersion 0.1.0
   * @apiName UpdateLocation
   * @apiGroup Locations
   * @apiPermission supplier or admin
   *
   * @apiDescription  Update Location
   *
   * @apiParamExample {json} Request-Example-InBody-Required:
   * {
     *        name: string,
     *        detail: string,
     *        address: string,
     *        link: [string],
     *        image_url: string,
     *        created_date: Number,
     *        location_info: {Object Location},
     *        tags: [string]
     *        status: string,
     * }
   *
   *
   * @apiExample Example usage:
   * PUT /locations/sdfdsafa?access_token=?
   *
   * @apiSuccess {Number} code                Code Success
   * @apiSuccess {Object} data                Location detail
   * @apiSuccessExample {json} Success-Response:
   *     HTTP/1.1 200 OK
   *     {
     *       code: 200,
     *       data: {
     *        location_id: string,
     *        supplier_id: string,
     *        name: string,
     *        detail: string,
     *        address: string,
     *        link: [string],
     *        image_url: string,
     *        created_date: Number,
     *        location_info: {Object Location},
     *        tags: [string]
     *        status: string,
     *       }
     *     }
   *
   *
   * @apiErrorExample Access token not true:
   *     HTTP/1.1 401 Access token not true
   *     {
   *       code : 401
   *       error: "Access token not true"
   *     }
   * @apiErrorExample Update fail:
   *     HTTP/1.1 402 Update fail
   *     {
   *       code : 402
   *       error: "Update fail with error"
   *     }
   */
  update: function(req,res,next) {

    var supplier_id = EVResponse.verifiyAccessToken(req,"supplier_id");
    if (supplier_id == null) {
      EVResponse.failure(res,401,"Access token not true");
      return;
    }

    var LocationInfo = EVBody(req.body);
    var location_id = req.params.location_id;

    RxMongo.findOneAndUpdated(Locations, {
      "_id": location_id,
      "supplier_id": supplier_id
    }, LocationInfo).subscribe(function(doc){
      EVResponse.success(res,doc);
    }, function(err){
      EVResponse.failure(res,402, "Update Item failure");
    });
  },

  /**
   * @api {delete} locations/:location_id?access_token Delete Location
   * @apiParam {string} location_id Location_ID want to Delete
   * @apiParam {string} access_token Authorized access_token
   * @apiVersion 0.1.0
   * @apiName DeleteLocation
   * @apiGroup Locations
   * @apiPermission supplier or admin
   *
   * @apiDescription  Delete Location
   *
   *
   * @apiExample Example usage:
   * DELETE /locations/sdfdsafa?access_token=asdfdsaf
   *
   * @apiSuccess {Number} code                Code Success
   * @apiSuccess {Object} data                Message
   * @apiSuccessExample {json} Success-Response:
   *     HTTP/1.1 200 OK
   *     {
     *       code: 200,
     *       data: "Success"
     *     }
   *
   *
   * @apiErrorExample Access token not true:
   *     HTTP/1.1 401 Access token not true
   *     {
   *       code : 401
   *       error: "Access token not true"
   *     }
   * @apiErrorExample Delete Location Failure:
   *     HTTP/1.1 402 Delete Location Failure
   *     {
   *       code : 402
   *       error: "Delete Location Failure"
   *     }
   */
  delete: function(req,res,next) {

    var supplier_id = EVResponse.verifiyAccessToken(req,"supplier_id");
    if (supplier_id == null) {
      EVResponse.failure(res,401,"Access token not true");
      return;
    }

    var location_id = req.params.location_id;
    RxMongo.remove(Locations, {
      '_id': location_id,
      'supplier_id': supplier_id
    }).subscribe(function(){
      EVResponse.success(res,"Delete success");
    }, function(err){
      EVResponse.failure(res,402, "Delete Item failure");
    });
  },

};
<|endoftext|>


<commit_before>var typed = new Typed('#typed', {
    stringsElement: '#typed-strings',
    typeSpeed: 60
});

subjectInput = document.getElementById("subject");
emailInput = document.getElementById("email");
messageInput = document.getElementById("message");
sendButton = document.getElementById("submitButton");

sendButton.addEventListener("click", function(e) {
    e.preventDefault();

    var http = new XMLHttpRequest();
    var url = "https://cv-mailer.herokuapp.com/email/send";
    var params = "subject=" + subjectInput.value + "&from=" + emailInput.value + "&message=" + messageInput.value;
    http.open("POST", url, true);
    http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

    http.onreadystatechange = function() {
        if(http.readyState == 4 && http.status == 200) {
            console.log(http.responseText);
        }
    }

    http.send(params);
    console.log("sended", params);
});

// Add Google Maps
function initMap() {
    var customMapType = new google.maps.StyledMapType(
        [
            {
                "featureType": "road",
                "elementType": "labels",
                "stylers": [
                    {
                        "visibility": "on"
                    }
                ]
            },
            {
                "featureType": "poi",
                "stylers": [
                    {
                        "visibility": "off"
                    }
                ]
            },
            {
                "featureType": "administrative",
                "stylers": [
                    {
                        "visibility": "off"
                    }
                ]
            },
            {
                "featureType": "road",
                "elementType": "geometry.fill",
                "stylers": [
                    {
                        "color": "#000000"
                    },
                    {
                        "weight": 1
                    }
                ]
            },
            {
                "featureType": "road",
                "elementType": "geometry.stroke",
                "stylers": [
                    {
                        "color": "#000000"
                    },
                    {
                        "weight": 0.8
                    }
                ]
            },
            {
                "featureType": "landscape",
                "stylers": [
                    {
                        "color": "#ffffff"
                    }
                ]
            },
            {
                "featureType": "water",
                "stylers": [
                    {
                        "visibility": "off"
                    }
                ]
            },
            {
                "featureType": "transit",
                "stylers": [
                    {
                        "visibility": "off"
                    }
                ]
            },
            {
                "elementType": "labels",
                "stylers": [
                    {
                        "visibility": "off"
                    }
                ]
            },
            {
                "elementType": "labels.text",
                "stylers": [
                    {
                        "visibility": "on"
                    }
                ]
            },
            {
                "elementType": "labels.text.stroke",
                "stylers": [
                    {
                        "color": "#ffffff"
                    }
                ]
            },
            {
                "elementType": "labels.text.fill",
                "stylers": [
                    {
                        "color": "#000000"
                    }
                ]
            },
            {
                "elementType": "labels.icon",
                "stylers": [
                    {
                        "visibility": "on"
                    }
                ]
            }
        ], {
      name: 'Styled'
    });
    var customMapTypeId = 'custom_style';

    var latLng = {
      lat: 55.7547585,
      lng: 37.6038036
    };

    var map = new google.maps.Map(document.getElementById("map"), {
      zoom: 11,
      center: latLng,
      mapTypeControlOptions: {
        mapTypeIds: [google.maps.MapTypeId.ROADMAP, customMapTypeId]
      }
    });

    map.mapTypes.set(customMapTypeId, customMapType);
    map.setMapTypeId(customMapTypeId);

  }<commit_msg>Fixed to body<commit_after>var typed = new Typed('#typed', {
    stringsElement: '#typed-strings',
    typeSpeed: 60
});

subjectInput = document.getElementById("subject");
emailInput = document.getElementById("email");
messageInput = document.getElementById("message");
sendButton = document.getElementById("submitButton");

sendButton.addEventListener("click", function(e) {
    e.preventDefault();

    var http = new XMLHttpRequest();
    var url = "https://cv-mailer.herokuapp.com/email/send";
    var params = "subject=" + subjectInput.value + "&from=" + emailInput.value + "&body=" + messageInput.value;
    http.open("POST", url, true);
    http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");

    http.onreadystatechange = function() {
        if(http.readyState == 4 && http.status == 200) {
            console.log(http.responseText);
        }
    }

    http.send(params);
    console.log("sended", params);
});

// Add Google Maps
function initMap() {
    var customMapType = new google.maps.StyledMapType(
        [
            {
                "featureType": "road",
                "elementType": "labels",
                "stylers": [
                    {
                        "visibility": "on"
                    }
                ]
            },
            {
                "featureType": "poi",
                "stylers": [
                    {
                        "visibility": "off"
                    }
                ]
            },
            {
                "featureType": "administrative",
                "stylers": [
                    {
                        "visibility": "off"
                    }
                ]
            },
            {
                "featureType": "road",
                "elementType": "geometry.fill",
                "stylers": [
                    {
                        "color": "#000000"
                    },
                    {
                        "weight": 1
                    }
                ]
            },
            {
                "featureType": "road",
                "elementType": "geometry.stroke",
                "stylers": [
                    {
                        "color": "#000000"
                    },
                    {
                        "weight": 0.8
                    }
                ]
            },
            {
                "featureType": "landscape",
                "stylers": [
                    {
                        "color": "#ffffff"
                    }
                ]
            },
            {
                "featureType": "water",
                "stylers": [
                    {
                        "visibility": "off"
                    }
                ]
            },
            {
                "featureType": "transit",
                "stylers": [
                    {
                        "visibility": "off"
                    }
                ]
            },
            {
                "elementType": "labels",
                "stylers": [
                    {
                        "visibility": "off"
                    }
                ]
            },
            {
                "elementType": "labels.text",
                "stylers": [
                    {
                        "visibility": "on"
                    }
                ]
            },
            {
                "elementType": "labels.text.stroke",
                "stylers": [
                    {
                        "color": "#ffffff"
                    }
                ]
            },
            {
                "elementType": "labels.text.fill",
                "stylers": [
                    {
                        "color": "#000000"
                    }
                ]
            },
            {
                "elementType": "labels.icon",
                "stylers": [
                    {
                        "visibility": "on"
                    }
                ]
            }
        ], {
      name: 'Styled'
    });
    var customMapTypeId = 'custom_style';

    var latLng = {
      lat: 55.7547585,
      lng: 37.6038036
    };

    var map = new google.maps.Map(document.getElementById("map"), {
      zoom: 11,
      center: latLng,
      mapTypeControlOptions: {
        mapTypeIds: [google.maps.MapTypeId.ROADMAP, customMapTypeId]
      }
    });

    map.mapTypes.set(customMapTypeId, customMapType);
    map.setMapTypeId(customMapTypeId);

  }<|endoftext|>


<commit_before>import deindent from '../../../../utils/deindent.js';
import flattenReference from '../../../../utils/flattenReference.js';
import getSetter from '../shared/binding/getSetter.js';
import getStaticAttributeValue from './getStaticAttributeValue.js';

export default function visitBinding ( generator, block, state, node, attribute ) {
	const { name, keypath } = flattenReference( attribute.value );
	const { snippet, contexts, dependencies } = block.contextualise( attribute.value );

	if ( dependencies.length > 1 ) throw new Error( 'An unexpected situation arose. Please raise an issue at https://github.com/sveltejs/svelte/issues — thanks!' );

	contexts.forEach( context => {
		if ( !~state.allUsedContexts.indexOf( context ) ) state.allUsedContexts.push( context );
	});

	const eventName = getBindingEventName( node, attribute );
	const handler = block.getUniqueName( `${state.parentNode}_${eventName}_handler` );
	const isMultipleSelect = node.name === 'select' && node.attributes.find( attr => attr.name.toLowerCase() === 'multiple' ); // TODO use getStaticAttributeValue
	const type = getStaticAttributeValue( node, 'type' );
	const bindingGroup = attribute.name === 'group' ? getBindingGroup( generator, keypath ) : null;
	const value = getBindingValue( generator, block, state, node, attribute, isMultipleSelect, bindingGroup, type );

	let setter = getSetter({ block, name, keypath, context: '_svelte', attribute, dependencies, value });
	let updateElement = `${state.parentNode}.${attribute.name} = ${snippet};`;
	const lock = block.getUniqueName( `${state.parentNode}_${attribute.name}_updating` );
	let updateCondition = `!${lock}`;

	// <select> special case
	if ( node.name === 'select' ) {
		if ( !isMultipleSelect ) {
			setter = `var selectedOption = ${state.parentNode}.selectedOptions[0] || ${state.parentNode}.options[0];\n${setter}`;
		}

		const value = block.getUniqueName( 'value' );
		const i = block.getUniqueName( 'i' );
		const option = block.getUniqueName( 'option' );

		const ifStatement = isMultipleSelect ?
			deindent`
				${option}.selected = ~${value}.indexOf( ${option}.__value );` :
			deindent`
				if ( ${option}.__value === ${value} ) {
					${option}.selected = true;
					break;
				}`;

		updateElement = deindent`
			var ${value} = ${snippet};
			for ( var ${i} = 0; ${i} < ${state.parentNode}.options.length; ${i} += 1 ) {
				var ${option} = ${state.parentNode}.options[${i}];

				${ifStatement}
			}
		`;
	}

	// <input type='checkbox|radio' bind:group='selected'> special case
	else if ( attribute.name === 'group' ) {
		if ( type === 'radio' ) {
			setter = deindent`
				if ( !${state.parentNode}.checked ) return;
				${setter}
			`;
		}

		const condition = type === 'checkbox' ?
			`~${snippet}.indexOf( ${state.parentNode}.__value )` :
			`${state.parentNode}.__value === ${snippet}`;

		block.builders.create.addLine(
			`${block.component}._bindingGroups[${bindingGroup}].push( ${state.parentNode} );`
		);

		block.builders.destroy.addBlock(
			`${block.component}._bindingGroups[${bindingGroup}].splice( ${block.component}._bindingGroups[${bindingGroup}].indexOf( ${state.parentNode} ), 1 );`
		);

		updateElement = `${state.parentNode}.checked = ${condition};`;
	}

	else if ( node.name === 'audio' || node.name === 'video' ) {
		generator.hasComplexBindings = true;
		block.builders.create.addBlock( `${block.component}._bindings.push( ${handler} );` );

		if ( attribute.name === 'currentTime' ) {
			setter = deindent`
				if ( !${state.parentNode}.paused ) requestAnimationFrame( ${handler} );
				${setter}
			`;

			updateCondition += ` && !isNaN( ${snippet} )`;
		}

		else if ( attribute.name === 'duration' ) {
			updateCondition = null;
		}

		else if ( attribute.name === 'paused' ) {
			updateElement = `${state.parentNode}[ ${snippet} ? 'pause' : 'play' ]()`;
		}
	}

	block.builders.create.addBlock( deindent`
		var ${lock} = false;

		function ${handler} () {
			${lock} = true;
			${setter}
			${lock} = false;
		}

		${generator.helper( 'addEventListener' )}( ${state.parentNode}, '${eventName}', ${handler} );
	` );

	if ( node.name !== 'audio' && node.name !== 'video' ) node.initialUpdate = updateElement;

	if ( updateCondition !== null ) {
		// audio/video duration is read-only, it never updates
		block.builders.update.addBlock( deindent`
			if ( ${updateCondition} ) {
				${updateElement}
			}
		` );
	}

	block.builders.destroy.addLine( deindent`
		${generator.helper( 'removeEventListener' )}( ${state.parentNode}, '${eventName}', ${handler} );
	` );

	if ( attribute.name === 'paused' ) {
		block.builders.create.addLine( `${generator.helper( 'addEventListener' )}( ${state.parentNode}, 'play', ${handler} );` );
		block.builders.destroy.addLine( `${generator.helper( 'removeEventListener' )}( ${state.parentNode}, 'play', ${handler} );` );
	}
}

function getBindingEventName ( node, attribute ) {
	if ( node.name === 'input' ) {
		const typeAttribute = node.attributes.find( attr => attr.type === 'Attribute' && attr.name === 'type' );
		const type = typeAttribute ? typeAttribute.value[0].data : 'text'; // TODO in validation, should throw if type attribute is not static

		return type === 'checkbox' || type === 'radio' ? 'change' : 'input';
	}

	if ( node.name === 'textarea' ) return 'input';
	if ( attribute.name === 'currentTime' ) return 'timeupdate';
	if ( attribute.name === 'duration' ) return 'durationchange';
	if ( attribute.name === 'paused' ) return 'pause';

	return 'change';
}

function getBindingValue ( generator, block, state, node, attribute, isMultipleSelect, bindingGroup, type ) {
	// <select multiple bind:value='selected>
	if ( isMultipleSelect ) {
		return `[].map.call( ${state.parentNode}.selectedOptions, function ( option ) { return option.__value; })`;
	}

	// <select bind:value='selected>
	if ( node.name === 'select' ) {
		return 'selectedOption && selectedOption.__value';
	}

	// <input type='checkbox' bind:group='foo'>
	if ( attribute.name === 'group' ) {
		if ( type === 'checkbox' ) {
			return `${generator.helper( 'getBindingGroupValue' )}( ${block.component}._bindingGroups[${bindingGroup}] )`;
		}

		return `${state.parentNode}.__value`;
	}

	// <input type='range|number' bind:value>
	if ( type === 'range' || type === 'number' ) {
		return `+${state.parentNode}.${attribute.name}`;
	}

	// everything else
	return `${state.parentNode}.${attribute.name}`;
}

function getBindingGroup ( generator, keypath ) {
	// TODO handle contextual bindings — `keypath` should include unique ID of
	// each block that provides context
	let index = generator.bindingGroups.indexOf( keypath );
	if ( index === -1 ) {
		index = generator.bindingGroups.length;
		generator.bindingGroups.push( keypath );
	}

	return index;
}
<commit_msg>prevent timer proliferation<commit_after>import deindent from '../../../../utils/deindent.js';
import flattenReference from '../../../../utils/flattenReference.js';
import getSetter from '../shared/binding/getSetter.js';
import getStaticAttributeValue from './getStaticAttributeValue.js';

export default function visitBinding ( generator, block, state, node, attribute ) {
	const { name, keypath } = flattenReference( attribute.value );
	const { snippet, contexts, dependencies } = block.contextualise( attribute.value );

	if ( dependencies.length > 1 ) throw new Error( 'An unexpected situation arose. Please raise an issue at https://github.com/sveltejs/svelte/issues — thanks!' );

	contexts.forEach( context => {
		if ( !~state.allUsedContexts.indexOf( context ) ) state.allUsedContexts.push( context );
	});

	const eventName = getBindingEventName( node, attribute );
	const handler = block.getUniqueName( `${state.parentNode}_${eventName}_handler` );
	const isMultipleSelect = node.name === 'select' && node.attributes.find( attr => attr.name.toLowerCase() === 'multiple' ); // TODO use getStaticAttributeValue
	const type = getStaticAttributeValue( node, 'type' );
	const bindingGroup = attribute.name === 'group' ? getBindingGroup( generator, keypath ) : null;
	const value = getBindingValue( generator, block, state, node, attribute, isMultipleSelect, bindingGroup, type );

	let setter = getSetter({ block, name, keypath, context: '_svelte', attribute, dependencies, value });
	let updateElement = `${state.parentNode}.${attribute.name} = ${snippet};`;
	const lock = block.getUniqueName( `${state.parentNode}_${attribute.name}_updating` );
	let updateCondition = `!${lock}`;

	// <select> special case
	if ( node.name === 'select' ) {
		if ( !isMultipleSelect ) {
			setter = `var selectedOption = ${state.parentNode}.selectedOptions[0] || ${state.parentNode}.options[0];\n${setter}`;
		}

		const value = block.getUniqueName( 'value' );
		const i = block.getUniqueName( 'i' );
		const option = block.getUniqueName( 'option' );

		const ifStatement = isMultipleSelect ?
			deindent`
				${option}.selected = ~${value}.indexOf( ${option}.__value );` :
			deindent`
				if ( ${option}.__value === ${value} ) {
					${option}.selected = true;
					break;
				}`;

		updateElement = deindent`
			var ${value} = ${snippet};
			for ( var ${i} = 0; ${i} < ${state.parentNode}.options.length; ${i} += 1 ) {
				var ${option} = ${state.parentNode}.options[${i}];

				${ifStatement}
			}
		`;
	}

	// <input type='checkbox|radio' bind:group='selected'> special case
	else if ( attribute.name === 'group' ) {
		if ( type === 'radio' ) {
			setter = deindent`
				if ( !${state.parentNode}.checked ) return;
				${setter}
			`;
		}

		const condition = type === 'checkbox' ?
			`~${snippet}.indexOf( ${state.parentNode}.__value )` :
			`${state.parentNode}.__value === ${snippet}`;

		block.builders.create.addLine(
			`${block.component}._bindingGroups[${bindingGroup}].push( ${state.parentNode} );`
		);

		block.builders.destroy.addBlock(
			`${block.component}._bindingGroups[${bindingGroup}].splice( ${block.component}._bindingGroups[${bindingGroup}].indexOf( ${state.parentNode} ), 1 );`
		);

		updateElement = `${state.parentNode}.checked = ${condition};`;
	}

	else if ( node.name === 'audio' || node.name === 'video' ) {
		generator.hasComplexBindings = true;
		block.builders.create.addBlock( `${block.component}._bindings.push( ${handler} );` );

		if ( attribute.name === 'currentTime' ) {
			const frame = block.getUniqueName( `${state.parentNode}_animationframe` );
			block.builders.create.addLine( `var ${frame};` );
			setter = deindent`
				cancelAnimationFrame( ${frame} );
				if ( !${state.parentNode}.paused ) ${frame} = requestAnimationFrame( ${handler} );
				${setter}
			`;

			updateCondition += ` && !isNaN( ${snippet} )`;
		}

		else if ( attribute.name === 'duration' ) {
			updateCondition = null;
		}

		else if ( attribute.name === 'paused' ) {
			updateElement = `${state.parentNode}[ ${snippet} ? 'pause' : 'play' ]();`;
		}
	}

	block.builders.create.addBlock( deindent`
		var ${lock} = false;

		function ${handler} () {
			${lock} = true;
			${setter}
			${lock} = false;
		}

		${generator.helper( 'addEventListener' )}( ${state.parentNode}, '${eventName}', ${handler} );
	` );

	if ( node.name !== 'audio' && node.name !== 'video' ) node.initialUpdate = updateElement;

	if ( updateCondition !== null ) {
		// audio/video duration is read-only, it never updates
		block.builders.update.addBlock( deindent`
			if ( ${updateCondition} ) {
				${updateElement}
			}
		` );
	}

	block.builders.destroy.addLine( deindent`
		${generator.helper( 'removeEventListener' )}( ${state.parentNode}, '${eventName}', ${handler} );
	` );

	if ( attribute.name === 'paused' ) {
		block.builders.create.addLine( `${generator.helper( 'addEventListener' )}( ${state.parentNode}, 'play', ${handler} );` );
		block.builders.destroy.addLine( `${generator.helper( 'removeEventListener' )}( ${state.parentNode}, 'play', ${handler} );` );
	}
}

function getBindingEventName ( node, attribute ) {
	if ( node.name === 'input' ) {
		const typeAttribute = node.attributes.find( attr => attr.type === 'Attribute' && attr.name === 'type' );
		const type = typeAttribute ? typeAttribute.value[0].data : 'text'; // TODO in validation, should throw if type attribute is not static

		return type === 'checkbox' || type === 'radio' ? 'change' : 'input';
	}

	if ( node.name === 'textarea' ) return 'input';
	if ( attribute.name === 'currentTime' ) return 'timeupdate';
	if ( attribute.name === 'duration' ) return 'durationchange';
	if ( attribute.name === 'paused' ) return 'pause';

	return 'change';
}

function getBindingValue ( generator, block, state, node, attribute, isMultipleSelect, bindingGroup, type ) {
	// <select multiple bind:value='selected>
	if ( isMultipleSelect ) {
		return `[].map.call( ${state.parentNode}.selectedOptions, function ( option ) { return option.__value; })`;
	}

	// <select bind:value='selected>
	if ( node.name === 'select' ) {
		return 'selectedOption && selectedOption.__value';
	}

	// <input type='checkbox' bind:group='foo'>
	if ( attribute.name === 'group' ) {
		if ( type === 'checkbox' ) {
			return `${generator.helper( 'getBindingGroupValue' )}( ${block.component}._bindingGroups[${bindingGroup}] )`;
		}

		return `${state.parentNode}.__value`;
	}

	// <input type='range|number' bind:value>
	if ( type === 'range' || type === 'number' ) {
		return `+${state.parentNode}.${attribute.name}`;
	}

	// everything else
	return `${state.parentNode}.${attribute.name}`;
}

function getBindingGroup ( generator, keypath ) {
	// TODO handle contextual bindings — `keypath` should include unique ID of
	// each block that provides context
	let index = generator.bindingGroups.indexOf( keypath );
	if ( index === -1 ) {
		index = generator.bindingGroups.length;
		generator.bindingGroups.push( keypath );
	}

	return index;
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

/**
 * Module dependencies.
 */
var app = require('../app');
var debug = require('debug')('zhihu-daily-reader:server');
var http = require('http');

/**
 * Get port from environment and store in Express.
 */
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */
var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);

/**
 * Normalize a port into a number, string, or false.
 */
function normalizePort(val)
{
    var port = parseInt(val, 10);

    if (isNaN(port))
    {
        // named pipe
        return val;
    }

    if (port >= 0)
    {
        // port number
        return port;
    }

    return false;
}

/**
 * Event listener for HTTP server "error" event.
 */
function onError(error)
{
    if (error.syscall !== 'listen')
    {
        throw error;
    }

    var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;

    // handle specific listen errors with friendly messages
    switch (error.code)
    {
        case 'EACCES':
            console.error(bind + ' requires elevated privileges');
            process.exit(1);
            break;

        case 'EADDRINUSE':
            console.error(bind + ' is already in use');
            process.exit(1);
            break;

        default:
            throw error;
    }
}

/**
 * Event listener for HTTP server "listening" event.
 */
function onListening()
{
    var addr = server.address();
    var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
    debug('Listening on ' + bind);
}
<commit_msg>remove debug module<commit_after>#!/usr/bin/env node

require('../app').listen(process.env.PORT || 3000);
<|endoftext|>


<commit_before>//fgnass.github.com/spin.js#v1.2.5
(function(a,b,c){function g(a,c){var d=b.createElement(a||"div"),e;for(e in c)d[e]=c[e];return d}function h(a){for(var b=1,c=arguments.length;b<c;b++)a.appendChild(arguments[b]);return a}function j(a,b,c,d){var g=["opacity",b,~~(a*100),c,d].join("-"),h=.01+c/d*100,j=Math.max(1-(1-a)/b*(100-h),a),k=f.substring(0,f.indexOf("Animation")).toLowerCase(),l=k&&"-"+k+"-"||"";return e[g]||(i.insertRule("@"+l+"keyframes "+g+"{"+"0%{opacity:"+j+"}"+h+"%{opacity:"+a+"}"+(h+.01)+"%{opacity:1}"+(h+b)%100+"%{opacity:"+a+"}"+"100%{opacity:"+j+"}"+"}",0),e[g]=1),g}function k(a,b){var e=a.style,f,g;if(e[b]!==c)return b;b=b.charAt(0).toUpperCase()+b.slice(1);for(g=0;g<d.length;g++){f=d[g]+b;if(e[f]!==c)return f}}function l(a,b){for(var c in b)a.style[k(a,c)||c]=b[c];return a}function m(a){for(var b=1;b<arguments.length;b++){var d=arguments[b];for(var e in d)a[e]===c&&(a[e]=d[e])}return a}function n(a){var b={x:a.offsetLeft,y:a.offsetTop};while(a=a.offsetParent)b.x+=a.offsetLeft,b.y+=a.offsetTop;return b}var d=["webkit","Moz","ms","O"],e={},f,i=function(){var a=g("style");return h(b.getElementsByTagName("head")[0],a),a.sheet||a.styleSheet}(),o={lines:12,length:7,width:5,radius:10,rotate:0,color:"#000",speed:1,trail:100,opacity:.25,fps:20,zIndex:2e9,className:"spinner",top:"auto",left:"auto"},p=function q(a){if(!this.spin)return new q(a);this.opts=m(a||{},q.defaults,o)};p.defaults={},m(p.prototype,{spin:function(a){this.stop();var b=this,c=b.opts,d=b.el=l(g(0,{className:c.className}),{position:"relative",zIndex:c.zIndex}),e=c.radius+c.length+c.width,h,i;a&&(a.insertBefore(d,a.firstChild||null),i=n(a),h=n(d),l(d,{left:(c.left=="auto"?i.x-h.x+(a.offsetWidth>>1):c.left+e)+"px",top:(c.top=="auto"?i.y-h.y+(a.offsetHeight>>1):c.top+e)+"px"})),d.setAttribute("aria-role","progressbar"),b.lines(d,b.opts);if(!f){var j=0,k=c.fps,m=k/c.speed,o=(1-c.opacity)/(m*c.trail/100),p=m/c.lines;!function q(){j++;for(var a=c.lines;a;a--){var e=Math.max(1-(j+a*p)%m*o,c.opacity);b.opacity(d,c.lines-a,e,c)}b.timeout=b.el&&setTimeout(q,~~(1e3/k))}()}return b},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=c),this},lines:function(a,b){function e(a,d){return l(g(),{position:"absolute",width:b.length+b.width+"px",height:b.width+"px",background:a,boxShadow:d,transformOrigin:"left",transform:"rotate("+~~(360/b.lines*c+b.rotate)+"deg) translate("+b.radius+"px"+",0)",borderRadius:(b.width>>1)+"px"})}var c=0,d;for(;c<b.lines;c++)d=l(g(),{position:"absolute",top:1+~(b.width/2)+"px",transform:b.hwaccel?"translate3d(0,0,0)":"",opacity:b.opacity,animation:f&&j(b.opacity,b.trail,c,b.lines)+" "+1/b.speed+"s linear infinite"}),b.shadow&&h(d,l(e("#000","0 0 4px #000"),{top:"2px"})),h(a,h(d,e(b.color,"0 0 1px rgba(0,0,0,.1)")));return a},opacity:function(a,b,c){b<a.childNodes.length&&(a.childNodes[b].style.opacity=c)}}),!function(){function a(a,b){return g("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',b)}var b=l(g("group"),{behavior:"url(#default#VML)"});!k(b,"transform")&&b.adj?(i.addRule(".spin-vml","behavior:url(#default#VML)"),p.prototype.lines=function(b,c){function f(){return l(a("group",{coordsize:e+" "+e,coordorigin:-d+" "+ -d}),{width:e,height:e})}function k(b,e,g){h(i,h(l(f(),{rotation:360/c.lines*b+"deg",left:~~e}),h(l(a("roundrect",{arcsize:1}),{width:d,height:c.width,left:c.radius,top:-c.width>>1,filter:g}),a("fill",{color:c.color,opacity:c.opacity}),a("stroke",{opacity:0}))))}var d=c.length+c.width,e=2*d,g=-(c.width+c.length)*2+"px",i=l(f(),{position:"absolute",top:g,left:g}),j;if(c.shadow)for(j=1;j<=c.lines;j++)k(j,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(j=1;j<=c.lines;j++)k(j);return h(b,i)},p.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d<e.childNodes.length&&(e=e.childNodes[b+d],e=e&&e.firstChild,e=e&&e.firstChild,e&&(e.opacity=c))}):f=k(b,"animation")}(),a.Spinner=p})(window,document);
<commit_msg>Story 56757158: Upgrated spin.js to the latest version in advance of breaking changes in Chrome<commit_after>//fgnass.github.com/spin.js#v1.2.5
(function(t,e){if(typeof exports=="object")module.exports=e();else if(typeof define=="function"&&define.amd)define(e);else t.Spinner=e()})(this,function(){"use strict";var t=["webkit","Moz","ms","O"],e={},i;function o(t,e){var i=document.createElement(t||"div"),o;for(o in e)i[o]=e[o];return i}function n(t){for(var e=1,i=arguments.length;e<i;e++)t.appendChild(arguments[e]);return t}var r=function(){var t=o("style",{type:"text/css"});n(document.getElementsByTagName("head")[0],t);return t.sheet||t.styleSheet}();function s(t,o,n,s){var a=["opacity",o,~~(t*100),n,s].join("-"),f=.01+n/s*100,l=Math.max(1-(1-t)/o*(100-f),t),u=i.substring(0,i.indexOf("Animation")).toLowerCase(),d=u&&"-"+u+"-"||"";if(!e[a]){r.insertRule("@"+d+"keyframes "+a+"{"+"0%{opacity:"+l+"}"+f+"%{opacity:"+t+"}"+(f+.01)+"%{opacity:1}"+(f+o)%100+"%{opacity:"+t+"}"+"100%{opacity:"+l+"}"+"}",r.cssRules.length);e[a]=1}return a}function a(e,i){var o=e.style,n,r;i=i.charAt(0).toUpperCase()+i.slice(1);for(r=0;r<t.length;r++){n=t[r]+i;if(o[n]!==undefined)return n}if(o[i]!==undefined)return i}function f(t,e){for(var i in e)t.style[a(t,i)||i]=e[i];return t}function l(t){for(var e=1;e<arguments.length;e++){var i=arguments[e];for(var o in i)if(t[o]===undefined)t[o]=i[o]}return t}function u(t){var e={x:t.offsetLeft,y:t.offsetTop};while(t=t.offsetParent)e.x+=t.offsetLeft,e.y+=t.offsetTop;return e}function d(t,e){return typeof t=="string"?t:t[e%t.length]}var p={lines:12,length:7,width:5,radius:10,rotate:0,corners:1,color:"#000",direction:1,speed:1,trail:100,opacity:1/4,fps:20,zIndex:2e9,className:"spinner",top:"auto",left:"auto",position:"relative"};function c(t){if(typeof this=="undefined")return new c(t);this.opts=l(t||{},c.defaults,p)}c.defaults={};l(c.prototype,{spin:function(t){this.stop();var e=this,n=e.opts,r=e.el=f(o(0,{className:n.className}),{position:n.position,width:0,zIndex:n.zIndex}),s=n.radius+n.length+n.width,a,l;if(t){t.insertBefore(r,t.firstChild||null);l=u(t);a=u(r);f(r,{left:(n.left=="auto"?l.x-a.x+(t.offsetWidth>>1):parseInt(n.left,10)+s)+"px",top:(n.top=="auto"?l.y-a.y+(t.offsetHeight>>1):parseInt(n.top,10)+s)+"px"})}r.setAttribute("role","progressbar");e.lines(r,e.opts);if(!i){var d=0,p=(n.lines-1)*(1-n.direction)/2,c,h=n.fps,m=h/n.speed,y=(1-n.opacity)/(m*n.trail/100),g=m/n.lines;(function v(){d++;for(var t=0;t<n.lines;t++){c=Math.max(1-(d+(n.lines-t)*g)%m*y,n.opacity);e.opacity(r,t*n.direction+p,c,n)}e.timeout=e.el&&setTimeout(v,~~(1e3/h))})()}return e},stop:function(){var t=this.el;if(t){clearTimeout(this.timeout);if(t.parentNode)t.parentNode.removeChild(t);this.el=undefined}return this},lines:function(t,e){var r=0,a=(e.lines-1)*(1-e.direction)/2,l;function u(t,i){return f(o(),{position:"absolute",width:e.length+e.width+"px",height:e.width+"px",background:t,boxShadow:i,transformOrigin:"left",transform:"rotate("+~~(360/e.lines*r+e.rotate)+"deg) translate("+e.radius+"px"+",0)",borderRadius:(e.corners*e.width>>1)+"px"})}for(;r<e.lines;r++){l=f(o(),{position:"absolute",top:1+~(e.width/2)+"px",transform:e.hwaccel?"translate3d(0,0,0)":"",opacity:e.opacity,animation:i&&s(e.opacity,e.trail,a+r*e.direction,e.lines)+" "+1/e.speed+"s linear infinite"});if(e.shadow)n(l,f(u("#000","0 0 4px "+"#000"),{top:2+"px"}));n(t,n(l,u(d(e.color,r),"0 0 1px rgba(0,0,0,.1)")))}return t},opacity:function(t,e,i){if(e<t.childNodes.length)t.childNodes[e].style.opacity=i}});function h(){function t(t,e){return o("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',e)}r.addRule(".spin-vml","behavior:url(#default#VML)");c.prototype.lines=function(e,i){var o=i.length+i.width,r=2*o;function s(){return f(t("group",{coordsize:r+" "+r,coordorigin:-o+" "+-o}),{width:r,height:r})}var a=-(i.width+i.length)*2+"px",l=f(s(),{position:"absolute",top:a,left:a}),u;function p(e,r,a){n(l,n(f(s(),{rotation:360/i.lines*e+"deg",left:~~r}),n(f(t("roundrect",{arcsize:i.corners}),{width:o,height:i.width,left:i.radius,top:-i.width>>1,filter:a}),t("fill",{color:d(i.color,e),opacity:i.opacity}),t("stroke",{opacity:0}))))}if(i.shadow)for(u=1;u<=i.lines;u++)p(u,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(u=1;u<=i.lines;u++)p(u);return n(e,l)};c.prototype.opacity=function(t,e,i,o){var n=t.firstChild;o=o.shadow&&o.lines||0;if(n&&e+o<n.childNodes.length){n=n.childNodes[e+o];n=n&&n.firstChild;n=n&&n.firstChild;if(n)n.opacity=i}}}var m=f(o("group"),{behavior:"url(#default#VML)"});if(!a(m,"transform")&&m.adj)h();else i=a(m,"animation");return c});
<|endoftext|>


<commit_before>/* global $ _ requests server helper sidebar */
'use strict';
var meta = function() {
// ==UserScript==
// @name         MusicBrainz: Replace recording artists from a release page
// @namespace    mbz-loujine
// @author       loujine
// @version      2016.5.16
// @downloadURL  https://bitbucket.org/loujine/musicbrainz-scripts/raw/default/mbz-replace_recording_artist_from_release_page.user.js
// @updateURL    https://bitbucket.org/loujine/musicbrainz-scripts/raw/default/mbz-replace_recording_artist_from_release_page.user.js
// @supportURL   https://bitbucket.org/loujine/musicbrainz-scripts
// @icon         https://bitbucket.org/loujine/musicbrainz-scripts/raw/default/icon.png
// @description  musicbrainz.org: Replace associated recording artist from a Release page
// @compatible   firefox+greasemonkey
// @licence      CC BY-NC-SA 3.0 (https://creativecommons.org/licenses/by-nc-sa/3.0/)
// @require      https://greasyfork.org/scripts/13747-mbz-loujine-common/code/mbz-loujine-common.js?version=126061
// @include      http*://*musicbrainz.org/release/*
// @include      http*://*mbsandbox.org/release/*
// @grant        none
// @run-at       document-end
// ==/UserScript==
};
if (meta && meta.toString && (meta = meta.toString())) {
    var meta = {'name': meta.match(/@name\s+(.+)/)[1],
                'version': meta.match(/@version\s+(.+)/)[1]};
}

// imported from mbz-loujine-common.js: requests, server, sidebar
var editNoteMsg = 'CSG: Set performer(s) in recording AR as recording artist\n';

function showSelectors() {
    var $rows = $(
        $('table.tbl a[href*="/artist/"]').parents('tr').get().reverse()
    );
    if (!$('#selectorColumn').length) {
        $('.subh').append('AR	');
    }

    $rows.each(function (idx, tr) {
        var mbid = $(tr).find('a[href*="/recording/"]').attr('href').split('/')[2];
        $(tr).append(
            $('').append(
                $('<input>', {
                    'id': 'replace-' + mbid,
                    'class': 'replace',
                    'type': 'checkbox',
                    'value': 'Replace artist'
                })
            )
        );
    });
}

// Replace composer -> performer as recording artist (CSG)
function formatEditInfo(json) {
    var data = [],
        performers = [],
        encodeName = function (name) {
            return encodeURIComponent(name).replace(/%20/g, '+');
        };
    data.push('edit-recording.name=' + encodeName(json.name));
    if (!json.comment.length) {
        data.push('edit-recording.comment');
    } else {
        data.push('edit-recording.comment=' + json.comment);
    }
    if (!json.isrcs.length) {
        data.push('edit-recording.isrcs.0');
    } else {
        json.isrcs.forEach(function(isrc, idx) {
            data.push('edit-recording.isrcs.' + idx + '=' + isrc);
        });
    }
    json.relationships.forEach(function(rel) {
        var linkType = rel.linkTypeID;

        if (_.includes(server.performingLinkTypes(), linkType)) {
            performers.push({'name': rel.target.name,
                             'creditedName': rel.entity0_credit,
                             'id': rel.target.id,
                             'link': linkType,
                             'mbid': rel.target.gid
            });
        }
    });
    var editNote = $('#batch_replace_edit_note')[0].value;
    data.push('edit-recording.edit_note=' + editNote);
    if (document.getElementById('votable').checked) {
        data.push('edit-recording.make_votable=1');
    } else {
        data.push('edit-recording.make_votable=0');
    }
    var uniqueIds = [];
    performers.sort(helper.comparefct).forEach(function(performer, idx) {
        if (_.includes(uniqueIds, performer.id)) {
            if (idx === performers.length - 1) {
                data[data.length - 3] = data[data.length - 3].slice(0, -2)
            }
            return;
        };
        uniqueIds.push(performer.id);
        var creditedName = performer.name;
        if (performer.creditedName) {
            creditedName = performer.creditedName;
        }
        data.push('edit-recording.artist_credit.names.' + idx + '.name=' + encodeName(creditedName));
        if (idx === performers.length - 1) {
            data.push('edit-recording.artist_credit.names.' + idx + '.join_phrase');
        } else {
            data.push('edit-recording.artist_credit.names.' + idx + '.join_phrase=,+');
        }
        data.push('edit-recording.artist_credit.names.' + idx + '.artist.name=' + encodeName(performer.name));
        data.push('edit-recording.artist_credit.names.' + idx + '.artist.id=' + performer.id);
    });
    return data.join('&');
}

function replaceArtist() {
    // in order to determine the edit parameters required by POST
    // we first load the /edit page and parse the JSON data
    // in the sourceData block
    $('.replace:input:checked:enabled').each(function (idx, node) {
        setTimeout(function () {
            var mbid = node.id.replace('replace-', ''),
                url = '/recording/' + encodeURIComponent(mbid) + '/edit',
                callback = function (info) {
                    var $status = $('#' + node.id + '-text');
                    // console.log('Sending POST ' + mbid + ' edit info');
                    // console.log(formatEditInfo(info));
                    requests.POST(url, formatEditInfo(info), function (xhr) {
                        $status.text('Sending edit data');
                        if (xhr.status === 200 || xhr.status === 0) {
                            node.disabled = true;
                            $status.text(
                                'Success (code ' + xhr.status + ')'
                            ).parent().css('color', 'green');
                            var editId = new RegExp(
                                '/edit/(.*)">edit'
                            ).exec(xhr.responseText)[1];
                            $status.after(
                                $('
').append(
                                    'edit ' + editId + ''
                                )
                            );
                        } else {
                            $status.text(
                                'Error (code ' + xhr.status + ')'
                            ).parent().css('color', 'red');
                        }
                    });
                };
            // console.log('Fetching ' + mbid + ' edit info');

            requests.GET(url, function (resp) {
                $(node).after('Fetching required data');
                var info = new RegExp('sourceData: (.*),\n').exec(resp)[1];
                callback(JSON.parse(info));
            });
        }, 2 * idx * server.timeout);
    });
}

(function displaySidebar(sidebar) {
    sidebar.container()
    .append(
        $('<input>', {
            'id': 'selectors',
            'type': 'button',
            'value': 'Show checkboxes'
        })
    ).append(
        $('
Replace artists
')
    ).append(
        $('
First click "Show checkboxes" then select recordings to update
')
    ).append(
        $('<input>', {
            'id': 'batch_select',
            'type': 'button',
            'disabled': true,
            'value': 'Select all'
        })
    ).append(
        $('
', {'class': 'auto-editor'})
        .append(
            $('Make all edits votable')
            .append($('<input>',
                      {'type': 'checkbox',
                       'id': 'votable'})
            )
        )
    ).append(
        $('
').append('Edit note:')
        .append(
            $('<textarea></textarea>', {
                'id': 'batch_replace_edit_note',
                'disabled': true,
                'text': sidebar.editNote(meta, editNoteMsg)
            })
        )
    ).append(
        $('<input>', {
            'id': 'batch_replace',
            'type': 'button',
            'disabled': true,
            'value': 'Replace selected artists'
        })
    );
})(sidebar);

$(document).ready(function () {
    $('#selectors').click(function () {
        showSelectors();
        $('#batch_select').prop('disabled', false);
        $('#batch_replace_edit_note').prop('disabled', false);
        $('#batch_replace').prop('disabled', false);
        $('#selectors').prop('disabled', true);
    });
    $('#batch_replace').click(function () {replaceArtist();});
    $('#batch_select').click(function () {
        $('.replace:input').attr('checked', true);
    });
    return false;
});
<commit_msg>[replace artists] Fix timing of on screen info display<commit_after>/* global $ _ requests server helper sidebar */
'use strict';
var meta = function() {
// ==UserScript==
// @name         MusicBrainz: Replace recording artists from a release page
// @namespace    mbz-loujine
// @author       loujine
// @version      2016.5.16
// @downloadURL  https://bitbucket.org/loujine/musicbrainz-scripts/raw/default/mbz-replace_recording_artist_from_release_page.user.js
// @updateURL    https://bitbucket.org/loujine/musicbrainz-scripts/raw/default/mbz-replace_recording_artist_from_release_page.user.js
// @supportURL   https://bitbucket.org/loujine/musicbrainz-scripts
// @icon         https://bitbucket.org/loujine/musicbrainz-scripts/raw/default/icon.png
// @description  musicbrainz.org: Replace associated recording artist from a Release page
// @compatible   firefox+greasemonkey
// @licence      CC BY-NC-SA 3.0 (https://creativecommons.org/licenses/by-nc-sa/3.0/)
// @require      https://greasyfork.org/scripts/13747-mbz-loujine-common/code/mbz-loujine-common.js?version=126061
// @include      http*://*musicbrainz.org/release/*
// @include      http*://*mbsandbox.org/release/*
// @grant        none
// @run-at       document-end
// ==/UserScript==
};
if (meta && meta.toString && (meta = meta.toString())) {
    var meta = {'name': meta.match(/@name\s+(.+)/)[1],
                'version': meta.match(/@version\s+(.+)/)[1]};
}

// imported from mbz-loujine-common.js: requests, server, sidebar
var editNoteMsg = 'CSG: Set performer(s) in recording AR as recording artist\n';

function showSelectors() {
    var $rows = $(
        $('table.tbl a[href*="/artist/"]').parents('tr').get().reverse()
    );
    if (!$('#selectorColumn').length) {
        $('.subh').append('AR	');
    }

    $rows.each(function (idx, tr) {
        var mbid = $(tr).find('a[href*="/recording/"]').attr('href').split('/')[2];
        $(tr).append(
            $('').append(
                $('<input>', {
                    'id': 'replace-' + mbid,
                    'class': 'replace',
                    'type': 'checkbox',
                    'value': 'Replace artist'
                })
            )
        );
    });
}

// Replace composer -> performer as recording artist (CSG)
function formatEditInfo(json) {
    var data = [],
        performers = [],
        encodeName = function (name) {
            return encodeURIComponent(name).replace(/%20/g, '+');
        };
    data.push('edit-recording.name=' + encodeName(json.name));
    if (!json.comment.length) {
        data.push('edit-recording.comment');
    } else {
        data.push('edit-recording.comment=' + json.comment);
    }
    if (!json.isrcs.length) {
        data.push('edit-recording.isrcs.0');
    } else {
        json.isrcs.forEach(function(isrc, idx) {
            data.push('edit-recording.isrcs.' + idx + '=' + isrc);
        });
    }
    json.relationships.forEach(function(rel) {
        var linkType = rel.linkTypeID;

        if (_.includes(server.performingLinkTypes(), linkType)) {
            performers.push({'name': rel.target.name,
                             'creditedName': rel.entity0_credit,
                             'id': rel.target.id,
                             'link': linkType,
                             'mbid': rel.target.gid
            });
        }
    });
    var editNote = $('#batch_replace_edit_note')[0].value;
    data.push('edit-recording.edit_note=' + editNote);
    if (document.getElementById('votable').checked) {
        data.push('edit-recording.make_votable=1');
    } else {
        data.push('edit-recording.make_votable=0');
    }
    var uniqueIds = [];
    performers.sort(helper.comparefct).forEach(function(performer, idx) {
        if (_.includes(uniqueIds, performer.id)) {
            if (idx === performers.length - 1) {
                data[data.length - 3] = data[data.length - 3].slice(0, -2)
            }
            return;
        };
        uniqueIds.push(performer.id);
        var creditedName = performer.name;
        if (performer.creditedName) {
            creditedName = performer.creditedName;
        }
        data.push('edit-recording.artist_credit.names.' + idx + '.name=' + encodeName(creditedName));
        if (idx === performers.length - 1) {
            data.push('edit-recording.artist_credit.names.' + idx + '.join_phrase');
        } else {
            data.push('edit-recording.artist_credit.names.' + idx + '.join_phrase=,+');
        }
        data.push('edit-recording.artist_credit.names.' + idx + '.artist.name=' + encodeName(performer.name));
        data.push('edit-recording.artist_credit.names.' + idx + '.artist.id=' + performer.id);
    });
    return data.join('&');
}

function replaceArtist() {
    // in order to determine the edit parameters required by POST
    // we first load the /edit page and parse the JSON data
    // in the sourceData block
    $('.replace:input:checked:enabled').each(function (idx, node) {
        setTimeout(function () {
            var mbid = node.id.replace('replace-', ''),
                url = '/recording/' + encodeURIComponent(mbid) + '/edit',
                callback = function (info) {
                    var $status = $('#' + node.id + '-text');
                    $status.text('Sending edit data');
                    // console.log('Sending POST ' + mbid + ' edit info');
                    // console.log(formatEditInfo(info));
                    requests.POST(url, formatEditInfo(info), function (xhr) {
                        if (xhr.status === 200 || xhr.status === 0) {
                            node.disabled = true;
                            $status.text(
                                'Success (code ' + xhr.status + ')'
                            ).parent().css('color', 'green');
                            var editId = new RegExp(
                                '/edit/(.*)">edit'
                            ).exec(xhr.responseText)[1];
                            $status.after(
                                $('
').append(
                                    'edit ' + editId + ''
                                )
                            );
                        } else {
                            $status.text(
                                'Error (code ' + xhr.status + ')'
                            ).parent().css('color', 'red');
                        }
                    });
                };
            // console.log('Fetching ' + mbid + ' edit info');

            $(node).after('Fetching required data');
            requests.GET(url, function (resp) {
                var info = new RegExp('sourceData: (.*),\n').exec(resp)[1];
                callback(JSON.parse(info));
            });
        }, 2 * idx * server.timeout);
    });
}

(function displaySidebar(sidebar) {
    sidebar.container()
    .append(
        $('<input>', {
            'id': 'selectors',
            'type': 'button',
            'value': 'Show checkboxes'
        })
    ).append(
        $('
Replace artists
')
    ).append(
        $('
First click "Show checkboxes" then select recordings to update
')
    ).append(
        $('<input>', {
            'id': 'batch_select',
            'type': 'button',
            'disabled': true,
            'value': 'Select all'
        })
    ).append(
        $('
', {'class': 'auto-editor'})
        .append(
            $('Make all edits votable')
            .append($('<input>',
                      {'type': 'checkbox',
                       'id': 'votable'})
            )
        )
    ).append(
        $('
').append('Edit note:')
        .append(
            $('<textarea></textarea>', {
                'id': 'batch_replace_edit_note',
                'disabled': true,
                'text': sidebar.editNote(meta, editNoteMsg)
            })
        )
    ).append(
        $('<input>', {
            'id': 'batch_replace',
            'type': 'button',
            'disabled': true,
            'value': 'Replace selected artists'
        })
    );
})(sidebar);

$(document).ready(function () {
    $('#selectors').click(function () {
        showSelectors();
        $('#batch_select').prop('disabled', false);
        $('#batch_replace_edit_note').prop('disabled', false);
        $('#batch_replace').prop('disabled', false);
        $('#selectors').prop('disabled', true);
    });
    $('#batch_replace').click(function () {replaceArtist();});
    $('#batch_select').click(function () {
        $('.replace:input').attr('checked', true);
    });
    return false;
});
<|endoftext|>