<commit_before>'use strict';

angular.module('emulvcApp')
  .factory('viewState', function($rootScope) {

    //shared service object to be returned
    var sServObj = {};

    sServObj.sS = 0;
    sServObj.eS = 0;
    sServObj.selectS = -1;
    sServObj.selectE = -1;
    sServObj.selected = [];
    sServObj.lasteditArea = null;
    sServObj.editing = false;

    sServObj.tmpFixedBufferLength = 128085;

    /**
     * set selected Area
     * @param start of selected Area
     * @param end of seleected Area
     */
    sServObj.select = function(start, end) {
      this.selectS = start;
      this.selectE = end;
    };

    /**
     * get pixel position in current viewport given the canvas width
     * @param w is width of canvas
     * @param s is current sample to convert to pixel value
     */
    sServObj.getPos = function(w, s) {
      return (w * (s - this.sS) / (this.eS - this.sS + 1)); // + 1 because of view (displays all samples in view)
    };

    /**
     * calculate the pixel distance between two samples
     * @param w is width of canvas
     */
    sServObj.getSampleDist = function(w) {
      return this.getPos(w, this.sS + 1) - this.getPos(w, this.sS);
    };

    /**
     * sets the current (clicked) Tier Name
     * @param name is name of tier
     */
    sServObj.setcurClickTierName= function(name) {
      this.curClickTierName = name;
    };

    /**
     * gets the current (clicked) Tier Name
     */
    sServObj.getcurClickTierName = function() {
      return this.curClickTierName;
    };

    /**
     * sets the current (mousemove) Tier Name
     * @param name is name of tier
     */
    sServObj.setcurMouseTierName= function(name) {
      this.curMouseTierName = name;
    };

    /**
     * gets the current (mousemove) Tier Name
     */
    sServObj.getcurMouseTierName = function() {
      return this.curMouseTierName;
    };

    /**
     * sets the current (mousemove) Segment
     * @param name is name of tier
     */
    sServObj.setcurMouseSegment = function(segment) {
      this.curMouseSegment = segment;
    };

    /**
     * gets the current (mousemove) Segment
     */
    sServObj.getcurMouseSegment= function() {
      return this.curMouseSegment;
    };

    /**
     * sets the current (mousemove) Segment
     * @param name is name of tier
     */
    sServObj.setcurMouseSegmentId = function(id) {
      this.curMouseSegmentId = id;
    };

    /**
     * gets the current (mousemove) Segment
     */
    sServObj.getcurMouseSegmentId= function() {
      return this.curMouseSegmentId;
    };

    /**
     * sets the current (click) Segment
     * @param segment
     */
    sServObj.setcurClickSegment = function(segment, id) {
      this.curClickSegment = segment;
      this.selected = [];
      this.selected.push(id);
    };

    /**
     * sets a multiple select (click) Segment
     * @param segment
     */
    sServObj.setcurClickSegmentMultiple = function(segment, id) {
      var empty = true;
      var my = this;
      this.selected.forEach(function(entry) {
        if (my.selected.indexOf(id) == -1 && (entry - 1 == id ||  entry + 1 == id)) {
          my.selected.push(id);
          empty = false;
        }
      });
      if (empty) {
        this.selected = [];
        this.selected.push(id);
      }
    };

    /**
     * gets the current (click) Segment
     */
    sServObj.getcurClickSegment= function() {
      return this.selected;
    };

    /**
     * gets the current (click) Segment
     */
    sServObj.getlastClickSegment= function() {
      return this.curClickSegment;
    };

    sServObj.isEditing = function() {
      return this.editing;
    };

    sServObj.setEditing = function(n) {
      this.editing = n;
    };

    sServObj.setlasteditArea = function(name) {
      this.lasteditArea = name;
    };

    sServObj.getlastID= function() {
      return this.lasteditArea.substr(1);
    };

    sServObj.getlasteditArea = function() {
      return this.lasteditArea;
    };

    sServObj.deleteEditArea = function() {
      if (null != this.getlasteditArea()) $("." + this.getlasteditArea()).remove();
      this.editing = false;
    };

    sServObj.resizeSelectArea = function(start, end) {
      this.selectS = start;
      this.selectE = end;
    };

    sServObj.resizeSelectAreaMulti = function(start, end) {
      if (start < this.selectS)
        this.selectS = start;
      if (end > this.selectE)
        this.selectE = end;
    };

    sServObj.countSelected = function() {
      return this.selected.length;
    };

    sServObj.getCurrentSample = function(perc) {
      return this.sS + (this.eS - this.sS) * perc;
    };

    sServObj.getCurrentPercent = function(sample) {
      return (sample * (100 / (this.eS - this.sS) / 100));
    };

    /**
     * round to n decimal digits after the comma
     * used to help display numbers with a given
     * precision
     */
    sServObj.round = function(x, n) {
      if (n < 1 || n > 14) alert("error in call of round function!!");
      var e = Math.pow(10, n);
      var k = (Math.round(x * e) / e).toString();
      if (k.indexOf('.') == -1) k += '.';
      k += e.toString().substring(1);
      return k.substring(0, k.indexOf('.') + n + 1);
    };

    sServObj.openEditArea = function() {
      var lastEventClick = this.getlastClickSegment();
      var lastEventClickId = this.getlastID();
      var elem = $("#" + this.getcurClickTierName()).find("canvas")[0];
      var start = this.getPos(elem.clientWidth, lastEventClick.startSample) + elem.offsetLeft;
      var end = this.getPos(elem.clientWidth, (lastEventClick.startSample + lastEventClick.sampleDur)) + elem.offsetLeft;
      var top = elem.offsetTop;
      var height = elem.clientHeight;
      var myid = this.createEditArea(this.getcurClickTierName(), start, top, end - start, height, lastEventClick.label, lastEventClickId);
      this.createSelection($("#" + myid)[0], 0, $("#" + myid).val().length);
      return myid;
    };

    sServObj.createSelection = function(field, start, end) {
      if (field.createTextRange) {
        var selRange = field.createTextRange();
        selRange.collapse(true);
        selRange.moveStart('character', start);
        selRange.moveEnd('character', end);
        selRange.select();
      } else if (field.setSelectionRange) {
        field.setSelectionRange(start, end);
      } else if (field.selectionStart) {
        field.selectionStart = start;
        field.selectionEnd = end;
      }
      field.focus();
    };

    sServObj.createEditArea = function(id, x, y, width, height, label, labelid) {
      var textid = "_" + labelid;
      $("#" + id).append($("<textarea>").attr({
        id: textid,
        "autofocus": "true",
        "class": textid + " Label_Edit",
        "ng-model": "message"
      }).css({
        "position": "absolute",
        "top": y + 1 + "px",
        "left": x + 2 + "px",
        "width": width - 1 + "px",
        "height": height + "px",
        "max-height": height - (height / 3) + "px",
        "padding-top": (height / 3) + "px"
      }).text(label));
      return textid;
    };

    /**
     * set view port to start and end sample
     * (with several out-of-bounds like checks)
     *
     * @param sSample start sample of view
     * @param sSample end sample of view
     */
    sServObj.setViewPort = function(sSample, eSample) {

        var oldStart = this.sS;
        var oldEnd = this.eS;
        if (sSample !== undefined) {
            this.sS = Math.round(sSample);
        }
        if (eSample !== undefined) {
            this.eS = Math.round(eSample);
        }

        // check if moving left or right is not out of bounds -> prevent zooming on edge when moving left/right
        if (oldStart > this.sS && oldEnd > this.eS) {
            //moved left
            if (this.sS < 0) {
                this.sS = 0;
                this.eS = oldEnd + Math.abs(this.sS);
            }
        }
        if (oldStart < this.sS && oldEnd < this.eS) {
            //moved right
            if (this.eS > this.tmpFixedBufferLength) {
                this.sS = oldStart;
                this.eS = this.tmpFixedBufferLength;
            }
        }

        // // check if in range
        // if (this.sS < 0) {
        //     this.sS = 0;
        // }
        // if (this.eS > this.backend.currentBuffer.length - 1) {
        //     this.eS = this.backend.currentBuffer.length - 1;
        // }
        // if (this.eS - this.sS < 4) {
        //     this.sS = oldStart;
        //     this.eS = oldEnd;
        // }
        // this.drawBuffer();
    };

    /**
     * set view port to start and end sample
     * (with several out-of-bounds like checks)
     *
     * @param zoomIn bool to specify zooming direction
     * if set to true -> zoom in
     * if set to false -> zoom out
     */
    sServObj.zoomViewPort = function(zoomIn) {

        // this.tierHandler.removeLabelDoubleClick();
        var newStartS, newEndS;
        var d1 = 1;//this.viewPort.curMouseMoveSegmentStart - this.viewPort.sS;
        var d2 = 1; //this.viewPort.eS - this.viewPort.curMouseMoveSegmentStart;
        var d = this.eS - this.sS;

        if (zoomIn) {

          newStartS = this.sS + d * 0.1;
          newEndS = this.eS - d * 0.1;

            // if (this.viewPort.curMouseMoveSegmentStart) { //check if in view
                // newStartS = this.sS + d1 * 0.5;
                // newEndS = this.eS - d2 * 0.5;
            // } //else {
            //     newStartS = this.viewPort.sS + ~~(d / 4);
            //     newEndS = this.viewPort.eS - ~~(d / 4);
            // }
        } else {
          newStartS = this.sS - d * 0.1;
          newEndS = this.eS + d * 0.1;

        //     if (this.viewPort.curMouseMoveSegmentStart) { //check if in view
        //         newStartS = this.viewPort.sS - d1 * 0.5;
        //         newEndS = this.viewPort.eS + d2 * 0.5;
        //     } else {
        //         newStartS = this.viewPort.sS - ~~(d / 4);
        //         newEndS = this.viewPort.eS + ~~(d / 4);
        //     }
       }
        this.setViewPort(newStartS, newEndS);
    };

    /**
     * moves view port to the right or to the left
     * without changing the zoom
     *
     * @param shiftRight bool to specify direction
     * if set to true -> shift right
     * if set to falce -> shift left
     */
    sServObj.shiftViewPort = function(shiftRight) {
        // my.removeLabelDoubleClick();
        var newStartS, newEndS;
        if (shiftRight) {
            newStartS = this.sS + ~~((this.eS - this.sS) / 4);
            newEndS = this.eS + ~~((this.eS - this.sS) / 4);
        } else {
            newStartS = this.sS - ~~((this.eS - this.sS) / 4);
            newEndS = this.eS - ~~((this.eS - this.sS) / 4);
        }

        this.setViewPort(newStartS, newEndS);
    };

    return sServObj;

  });<commit_msg>all zoom viewport checks back<commit_after>'use strict';

angular.module('emulvcApp')
  .factory('viewState', function($rootScope) {

    //shared service object to be returned
    var sServObj = {};

    sServObj.sS = 0;
    sServObj.eS = 0;
    sServObj.selectS = -1;
    sServObj.selectE = -1;
    sServObj.selected = [];
    sServObj.lasteditArea = null;
    sServObj.editing = false;

    sServObj.tmpFixedBufferLength = 128085;

    /**
     * set selected Area
     * @param start of selected Area
     * @param end of seleected Area
     */
    sServObj.select = function(start, end) {
      this.selectS = start;
      this.selectE = end;
    };

    /**
     * get pixel position in current viewport given the canvas width
     * @param w is width of canvas
     * @param s is current sample to convert to pixel value
     */
    sServObj.getPos = function(w, s) {
      return (w * (s - this.sS) / (this.eS - this.sS + 1)); // + 1 because of view (displays all samples in view)
    };

    /**
     * calculate the pixel distance between two samples
     * @param w is width of canvas
     */
    sServObj.getSampleDist = function(w) {
      return this.getPos(w, this.sS + 1) - this.getPos(w, this.sS);
    };

    /**
     * sets the current (clicked) Tier Name
     * @param name is name of tier
     */
    sServObj.setcurClickTierName= function(name) {
      this.curClickTierName = name;
    };

    /**
     * gets the current (clicked) Tier Name
     */
    sServObj.getcurClickTierName = function() {
      return this.curClickTierName;
    };

    /**
     * sets the current (mousemove) Tier Name
     * @param name is name of tier
     */
    sServObj.setcurMouseTierName= function(name) {
      this.curMouseTierName = name;
    };

    /**
     * gets the current (mousemove) Tier Name
     */
    sServObj.getcurMouseTierName = function() {
      return this.curMouseTierName;
    };

    /**
     * sets the current (mousemove) Segment
     * @param name is name of tier
     */
    sServObj.setcurMouseSegment = function(segment) {
      this.curMouseSegment = segment;
    };

    /**
     * gets the current (mousemove) Segment
     */
    sServObj.getcurMouseSegment= function() {
      return this.curMouseSegment;
    };

    /**
     * sets the current (mousemove) Segment
     * @param name is name of tier
     */
    sServObj.setcurMouseSegmentId = function(id) {
      this.curMouseSegmentId = id;
    };

    /**
     * gets the current (mousemove) Segment
     */
    sServObj.getcurMouseSegmentId= function() {
      return this.curMouseSegmentId;
    };

    /**
     * sets the current (click) Segment
     * @param segment
     */
    sServObj.setcurClickSegment = function(segment, id) {
      this.curClickSegment = segment;
      this.selected = [];
      this.selected.push(id);
    };

    /**
     * sets a multiple select (click) Segment
     * @param segment
     */
    sServObj.setcurClickSegmentMultiple = function(segment, id) {
      var empty = true;
      var my = this;
      this.selected.forEach(function(entry) {
        if (my.selected.indexOf(id) == -1 && (entry - 1 == id ||  entry + 1 == id)) {
          my.selected.push(id);
          empty = false;
        }
      });
      if (empty) {
        this.selected = [];
        this.selected.push(id);
      }
    };

    /**
     * gets the current (click) Segment
     */
    sServObj.getcurClickSegment= function() {
      return this.selected;
    };

    /**
     * gets the current (click) Segment
     */
    sServObj.getlastClickSegment= function() {
      return this.curClickSegment;
    };

    sServObj.isEditing = function() {
      return this.editing;
    };

    sServObj.setEditing = function(n) {
      this.editing = n;
    };

    sServObj.setlasteditArea = function(name) {
      this.lasteditArea = name;
    };

    sServObj.getlastID= function() {
      return this.lasteditArea.substr(1);
    };

    sServObj.getlasteditArea = function() {
      return this.lasteditArea;
    };

    sServObj.deleteEditArea = function() {
      if (null != this.getlasteditArea()) $("." + this.getlasteditArea()).remove();
      this.editing = false;
    };

    sServObj.resizeSelectArea = function(start, end) {
      this.selectS = start;
      this.selectE = end;
    };

    sServObj.resizeSelectAreaMulti = function(start, end) {
      if (start < this.selectS)
        this.selectS = start;
      if (end > this.selectE)
        this.selectE = end;
    };

    sServObj.countSelected = function() {
      return this.selected.length;
    };

    sServObj.getCurrentSample = function(perc) {
      return this.sS + (this.eS - this.sS) * perc;
    };

    sServObj.getCurrentPercent = function(sample) {
      return (sample * (100 / (this.eS - this.sS) / 100));
    };

    /**
     * round to n decimal digits after the comma
     * used to help display numbers with a given
     * precision
     */
    sServObj.round = function(x, n) {
      if (n < 1 || n > 14) alert("error in call of round function!!");
      var e = Math.pow(10, n);
      var k = (Math.round(x * e) / e).toString();
      if (k.indexOf('.') == -1) k += '.';
      k += e.toString().substring(1);
      return k.substring(0, k.indexOf('.') + n + 1);
    };

    sServObj.openEditArea = function() {
      var lastEventClick = this.getlastClickSegment();
      var lastEventClickId = this.getlastID();
      var elem = $("#" + this.getcurClickTierName()).find("canvas")[0];
      var start = this.getPos(elem.clientWidth, lastEventClick.startSample) + elem.offsetLeft;
      var end = this.getPos(elem.clientWidth, (lastEventClick.startSample + lastEventClick.sampleDur)) + elem.offsetLeft;
      var top = elem.offsetTop;
      var height = elem.clientHeight;
      var myid = this.createEditArea(this.getcurClickTierName(), start, top, end - start, height, lastEventClick.label, lastEventClickId);
      this.createSelection($("#" + myid)[0], 0, $("#" + myid).val().length);
      return myid;
    };

    sServObj.createSelection = function(field, start, end) {
      if (field.createTextRange) {
        var selRange = field.createTextRange();
        selRange.collapse(true);
        selRange.moveStart('character', start);
        selRange.moveEnd('character', end);
        selRange.select();
      } else if (field.setSelectionRange) {
        field.setSelectionRange(start, end);
      } else if (field.selectionStart) {
        field.selectionStart = start;
        field.selectionEnd = end;
      }
      field.focus();
    };

    sServObj.createEditArea = function(id, x, y, width, height, label, labelid) {
      var textid = "_" + labelid;
      $("#" + id).append($("<textarea>").attr({
        id: textid,
        "autofocus": "true",
        "class": textid + " Label_Edit",
        "ng-model": "message"
      }).css({
        "position": "absolute",
        "top": y + 1 + "px",
        "left": x + 2 + "px",
        "width": width - 1 + "px",
        "height": height + "px",
        "max-height": height - (height / 3) + "px",
        "padding-top": (height / 3) + "px"
      }).text(label));
      return textid;
    };

    /**
     * set view port to start and end sample
     * (with several out-of-bounds like checks)
     *
     * @param sSample start sample of view
     * @param sSample end sample of view
     */
    sServObj.setViewPort = function(sSample, eSample) {

        var oldStart = this.sS;
        var oldEnd = this.eS;
        if (sSample !== undefined) {
            this.sS = Math.round(sSample);
        }
        if (eSample !== undefined) {
            this.eS = Math.round(eSample);
        }

        // check if moving left or right is not out of bounds -> prevent zooming on edge when moving left/right
        if (oldStart > this.sS && oldEnd > this.eS) {
            //moved left
            if (this.sS < 0) {
                this.sS = 0;
                this.eS = oldEnd + Math.abs(this.sS);
            }
        }
        if (oldStart < this.sS && oldEnd < this.eS) {
            //moved right
            if (this.eS > this.tmpFixedBufferLength) {
                this.sS = oldStart;
                this.eS = this.tmpFixedBufferLength;
            }
        }

        // check if in range
        if (this.sS < 0) {
            this.sS = 0;
        }
        if (this.eS > this.tmpFixedBufferLength) {
            this.eS = this.tmpFixedBufferLength;
        }
        // check if at least 4 samples are showing (fixed max zoom size)
        if (this.eS - this.sS < 4) {
            this.sS = oldStart;
            this.eS = oldEnd;
        }
    };

    /**
     * set view port to start and end sample
     * (with several out-of-bounds like checks)
     *
     * @param zoomIn bool to specify zooming direction
     * if set to true -> zoom in
     * if set to false -> zoom out
     */
    sServObj.zoomViewPort = function(zoomIn) {

        // this.tierHandler.removeLabelDoubleClick();
        var newStartS, newEndS;
        var d1 = 1;//this.viewPort.curMouseMoveSegmentStart - this.viewPort.sS;
        var d2 = 1; //this.viewPort.eS - this.viewPort.curMouseMoveSegmentStart;
        var d = this.eS - this.sS;

        if (zoomIn) {

          newStartS = this.sS + d * 0.1;
          newEndS = this.eS - d * 0.1;

            // if (this.viewPort.curMouseMoveSegmentStart) { //check if in view
                // newStartS = this.sS + d1 * 0.5;
                // newEndS = this.eS - d2 * 0.5;
            // } //else {
            //     newStartS = this.viewPort.sS + ~~(d / 4);
            //     newEndS = this.viewPort.eS - ~~(d / 4);
            // }
        } else {
          newStartS = this.sS - d * 0.1;
          newEndS = this.eS + d * 0.1;

        //     if (this.viewPort.curMouseMoveSegmentStart) { //check if in view
        //         newStartS = this.viewPort.sS - d1 * 0.5;
        //         newEndS = this.viewPort.eS + d2 * 0.5;
        //     } else {
        //         newStartS = this.viewPort.sS - ~~(d / 4);
        //         newEndS = this.viewPort.eS + ~~(d / 4);
        //     }
       }
        this.setViewPort(newStartS, newEndS);
    };

    /**
     * moves view port to the right or to the left
     * without changing the zoom
     *
     * @param shiftRight bool to specify direction
     * if set to true -> shift right
     * if set to falce -> shift left
     */
    sServObj.shiftViewPort = function(shiftRight) {
        // my.removeLabelDoubleClick();
        var newStartS, newEndS;
        if (shiftRight) {
            newStartS = this.sS + ~~((this.eS - this.sS) / 4);
            newEndS = this.eS + ~~((this.eS - this.sS) / 4);
        } else {
            newStartS = this.sS - ~~((this.eS - this.sS) / 4);
            newEndS = this.eS - ~~((this.eS - this.sS) / 4);
        }

        this.setViewPort(newStartS, newEndS);
    };

    return sServObj;

  });<|endoftext|>


<commit_before>/*
Name:           piwik
Description:    Access a Piwik API or track hits with node.js
Author:         Franklin van de Meent (http://frankl.in)
Source & docs:  https://github.com/fvdm/nodejs-piwik
Feedback:       https://github.com/fvdm/nodejs-piwik/issues
License:        Unlicense / Public Domain (see UNLICENSE file)
                (https://github.com/fvdm/nodejs-piwik/raw/develop/UNLICENSE)
*/

var urltool = require ('url');
var querystring = require ('querystring');
var http = null;

var app = {settings: {}};

// SETUP basics
app.setup = function (baseURL, token, timeout) {
  var url = urltool.parse (baseURL, true);

  if (url.protocol === 'https:') {
    http = require ('https');
    app.settings.apiprotocol = 'https:';
    app.settings.apiport = url.port || 443;
  } else {
    http = require ('http');
    app.settings.apiprotocol = 'http:';
    app.settings.apiport = url.port || 80;
  }

  // token in baseURL?
  if (url.query && url.query.token_auth) {
    app.settings.token = url.query.token_auth;
  }

  // override with custom token, and set timeout
  if (typeof token === 'number') {
    app.settings.timeout = token;
  } else if (token) {
    app.settings.token = token;
    app.settings.timeout = timeout || 5000;
  }

  app.settings.apihost = url.hostname;
  app.settings.apipath = url.pathname;

  return app;
};

// API call
app.api = function (vars, cb) {
  vars = typeof vars === 'object' ? vars : {};
  vars.module = 'API';
  vars.format = 'JSON';
  vars.token_auth = app.settings.token;
  talk ({method: 'GET', query: vars}, cb);
  return app;
};

// Track
app.track = function (vars, cb) {
  var bulk = {requests: []};
  var i, k, val, keys;
  if (app.settings.token) { bulk.token_auth = app.settings.token; }

  if (vars instanceof Array && vars[0] instanceof Object) {
    // array with objects
    for (i = 0; i < vars.length; i++) {
      keys = Object.keys (vars [i]);
      for (k = 0; k < keys.length; k++) {
        val = vars [i] [keys [k]];
        vars [i] [keys [k]] = typeof val === 'object' ? JSON.stringify (val) : val;
      }
      vars [i].rec = 1;
      vars [i].apiv = 1;
      vars [i] = '?'+ querystring.stringify (vars [i]);
      bulk.requests.push (vars [i]);
      delete vars [i];
    }
  } else if (vars instanceof Object) {
    // object
    keys = Object.keys (vars);
    for (i = 0; i < keys.length; i++) {
      val = vars [keys [i]];
      vars [keys [i]] = typeof val === 'object' ? JSON.stringify (val) : val;
    }
    vars.rec = 1;
    vars.apiv = 1;
    bulk.requests.push ('?'+ querystring.stringify (vars) );
  }

  talk(
    {
      method: 'POST',
      path: 'piwik.php',
      body: JSON.stringify (bulk)
    },
    function (err, data) {
      if (err) { return cb (err); }
      if (data.status === 'success') {
        cb (null, data);
      } else {
        var error = new Error ('track failed');
        error.data = data;
        cb (error);
      }
    }
  );

  return app;
};

// HTTP GET
function talk (props, cb) {
  // prevent multiple callbacks
  var complete = false;
  function callback (err, res) {
    if (!complete) {
      complete = true;
      cb (err, res || null);
    }
  }

  // build request
  var query = '';
  if (props.query instanceof Object) {
    var keys = Object.keys (props.query);
    for (var i = 0; i < keys.length; i++) {
      var key = keys [i];
      if (typeof props.query [key] === 'object') {
        props.query [key] = JSON.stringify (props.query [key]);
      }
    }
    query = '?'+ querystring.stringify (props.query);
  }

  var options = {
    protocol: app.settings.apiprotocol,
    host: app.settings.apihost,
    port: app.settings.apiport,
    path: app.settings.apipath + (props.path || '') + query,
    method: props.method || 'GET',
    headers: {}
  };

  if (props.method === 'POST' && typeof props.body === 'string') {
    options.headers ['Content-Type'] = 'application/json';
    options.headers ['Content-Length'] = props.body.length;
  }

  var request = http.request (options);

  // response
  request.on ('response', function (response) {
    var data = [];
    var size = 0;

    response.on ('close', function () {
      callback (new Error ('request dropped'));
    });

    response.on ('data', function (chunk) {
      data.push (chunk);
      size += chunk.length;
    });

    response.on ('end', function () {
      var error = null;
      data = Buffer.concat (data, size) .toString () .trim ();

      if (response.statusCode >= 300) {
        error = new Error ('http error');
        error.code = response.statusCode;
        error.body = data;
      }

      try {
        data = JSON.parse (data);
        if (data.result && data.result === 'error') {
          error = new Error ('api error');
          error.text = data.message;
        }
      }
      catch (e) {
        error = new Error ('response invalid');
        error.code = response.statusCode;
        error.body = data;
      }

      callback (error, !error ? data : null);
    });
  });

  // client timeout
  request.on ('socket', function (socket) {
    if (typeof api.settings.timeout === 'number') {
      socket.setTimeout (parseInt (api.settings.timeout));
      socket.on ('timeout', function () {
        callback (new Error('request timeout'));
        request.abort ();
      });
    }
  });

  // client error
  request.on ('error', function (error) {
    var err = new Error ('request failed');
    if (error.code === 'ECONNRESET') {
      err = new Error ('request timeout');
    }
    err.error = error;
    callback (err);
  });

  // run it
  request.end (props.body || null);
}

// module
module.exports = app;
<commit_msg>Fixed variable typo<commit_after>/*
Name:           piwik
Description:    Access a Piwik API or track hits with node.js
Author:         Franklin van de Meent (http://frankl.in)
Source & docs:  https://github.com/fvdm/nodejs-piwik
Feedback:       https://github.com/fvdm/nodejs-piwik/issues
License:        Unlicense / Public Domain (see UNLICENSE file)
                (https://github.com/fvdm/nodejs-piwik/raw/develop/UNLICENSE)
*/

var urltool = require ('url');
var querystring = require ('querystring');
var http = null;

var app = {settings: {}};

// SETUP basics
app.setup = function (baseURL, token, timeout) {
  var url = urltool.parse (baseURL, true);

  if (url.protocol === 'https:') {
    http = require ('https');
    app.settings.apiprotocol = 'https:';
    app.settings.apiport = url.port || 443;
  } else {
    http = require ('http');
    app.settings.apiprotocol = 'http:';
    app.settings.apiport = url.port || 80;
  }

  // token in baseURL?
  if (url.query && url.query.token_auth) {
    app.settings.token = url.query.token_auth;
  }

  // override with custom token, and set timeout
  if (typeof token === 'number') {
    app.settings.timeout = token;
  } else if (token) {
    app.settings.token = token;
    app.settings.timeout = timeout || 5000;
  }

  app.settings.apihost = url.hostname;
  app.settings.apipath = url.pathname;

  return app;
};

// API call
app.api = function (vars, cb) {
  vars = typeof vars === 'object' ? vars : {};
  vars.module = 'API';
  vars.format = 'JSON';
  vars.token_auth = app.settings.token;
  talk ({method: 'GET', query: vars}, cb);
  return app;
};

// Track
app.track = function (vars, cb) {
  var bulk = {requests: []};
  var i, k, val, keys;
  if (app.settings.token) { bulk.token_auth = app.settings.token; }

  if (vars instanceof Array && vars[0] instanceof Object) {
    // array with objects
    for (i = 0; i < vars.length; i++) {
      keys = Object.keys (vars [i]);
      for (k = 0; k < keys.length; k++) {
        val = vars [i] [keys [k]];
        vars [i] [keys [k]] = typeof val === 'object' ? JSON.stringify (val) : val;
      }
      vars [i].rec = 1;
      vars [i].apiv = 1;
      vars [i] = '?'+ querystring.stringify (vars [i]);
      bulk.requests.push (vars [i]);
      delete vars [i];
    }
  } else if (vars instanceof Object) {
    // object
    keys = Object.keys (vars);
    for (i = 0; i < keys.length; i++) {
      val = vars [keys [i]];
      vars [keys [i]] = typeof val === 'object' ? JSON.stringify (val) : val;
    }
    vars.rec = 1;
    vars.apiv = 1;
    bulk.requests.push ('?'+ querystring.stringify (vars) );
  }

  talk(
    {
      method: 'POST',
      path: 'piwik.php',
      body: JSON.stringify (bulk)
    },
    function (err, data) {
      if (err) { return cb (err); }
      if (data.status === 'success') {
        cb (null, data);
      } else {
        var error = new Error ('track failed');
        error.data = data;
        cb (error);
      }
    }
  );

  return app;
};

// HTTP GET
function talk (props, cb) {
  // prevent multiple callbacks
  var complete = false;
  function callback (err, res) {
    if (!complete) {
      complete = true;
      cb (err, res || null);
    }
  }

  // build request
  var query = '';
  if (props.query instanceof Object) {
    var keys = Object.keys (props.query);
    for (var i = 0; i < keys.length; i++) {
      var key = keys [i];
      if (typeof props.query [key] === 'object') {
        props.query [key] = JSON.stringify (props.query [key]);
      }
    }
    query = '?'+ querystring.stringify (props.query);
  }

  var options = {
    protocol: app.settings.apiprotocol,
    host: app.settings.apihost,
    port: app.settings.apiport,
    path: app.settings.apipath + (props.path || '') + query,
    method: props.method || 'GET',
    headers: {}
  };

  if (props.method === 'POST' && typeof props.body === 'string') {
    options.headers ['Content-Type'] = 'application/json';
    options.headers ['Content-Length'] = props.body.length;
  }

  var request = http.request (options);

  // response
  request.on ('response', function (response) {
    var data = [];
    var size = 0;

    response.on ('close', function () {
      callback (new Error ('request dropped'));
    });

    response.on ('data', function (chunk) {
      data.push (chunk);
      size += chunk.length;
    });

    response.on ('end', function () {
      var error = null;
      data = Buffer.concat (data, size) .toString () .trim ();

      if (response.statusCode >= 300) {
        error = new Error ('http error');
        error.code = response.statusCode;
        error.body = data;
      }

      try {
        data = JSON.parse (data);
        if (data.result && data.result === 'error') {
          error = new Error ('api error');
          error.text = data.message;
        }
      }
      catch (e) {
        error = new Error ('response invalid');
        error.code = response.statusCode;
        error.body = data;
      }

      callback (error, !error ? data : null);
    });
  });

  // client timeout
  request.on ('socket', function (socket) {
    if (typeof app.settings.timeout === 'number') {
      socket.setTimeout (parseInt (app.settings.timeout));
      socket.on ('timeout', function () {
        callback (new Error('request timeout'));
        request.abort ();
      });
    }
  });

  // client error
  request.on ('error', function (error) {
    var err = new Error ('request failed');
    if (error.code === 'ECONNRESET') {
      err = new Error ('request timeout');
    }
    err.error = error;
    callback (err);
  });

  // run it
  request.end (props.body || null);
}

// module
module.exports = app;
<|endoftext|>


<commit_before>'use strict';
/*global SVGjsAnim */

SVGjsAnim.prototype.Haulage = function() {
  this.haulage = this.draw
    .group()
    .attr('id', 'haulage');

  // IE doesn't read image size
  var w = this.origSceneW;
  var h = this.origSceneH;

  this.zimba = this.draw.image('images/zimba_longhole.svg', w, h);
  this.scene.add(this.zimba);
  this.zimba
    .x(-30)
    .animate(6000)
    .x(6)
    .loop()
  ;

  this.scooptram = this.draw.image('images/scooptram.svg', w, h);
  this.scene.add(this.scooptram);
  this.scooptram
    .x(-30)
    .animate(6000)
    .x(6)
    .loop()
  ;

  this.headings.haulage = this.Heading('Haulage_Video', 'haulage', 4.4, 325, 530);

  this.scene
    .add(this.haulage);

  this.sceneHeadings
    .add(this.headings.haulage);

  return this;
};

<commit_msg>Added scooptram component to haulage<commit_after>'use strict';
/*global SVGjsAnim */

SVGjsAnim.prototype.Haulage = function() {
  this.haulage = this.draw
    .group()
    .attr('id', 'haulage');

  // IE doesn't read image size
  var w = this.origSceneW;
  var h = this.origSceneH;

  this.zimba = this.draw.image('images/zimba_longhole.svg', w, h);
  this.scene.add(this.zimba);
  this.zimba
    .x(-30)
    .animate(6000)
    .x(6)
    .loop()
  ;

  this.scooptramHaulage = this.draw.scooptram()
    .move(-700, -42.5)
    .setX(50)
  ;
  this.haulage.add(this.scooptramHaulage);
  this.scooptramHaulage.go();

  this.headings.haulage = this.Heading('Haulage_Video', 'haulage', 4.4, 325, 530);

  this.scene
    .add(this.haulage);

  this.sceneHeadings
    .add(this.headings.haulage);

  return this;
};

<|endoftext|>


<commit_before>'use strict';

/**
 * ButtressJS - Realtime datastore for business software
 *
 * @file schemaRoutes.js
 * @description A list of default routes for schema
 * @module routes
 * @author Chris Bates-Keegan
 *
 */

const Route = require('./route');
const Model = require('../model');
// const Helpers = require('../../helpers');

let routes = [];

/**
 * @class GetList
 */
class GetList extends Route {
  constructor(schema) {
    super(`${schema.collection}`, `GET ${schema.collection} LIST`);
    this.verb = Route.Constants.Verbs.GET;
    this.auth = Route.Constants.Auth.ADMIN;
    this.permissions = Route.Constants.Permissions.LIST;

    // Fetch model
    this.model = Model[schema.collection];
    if (!this.model) {
      // Somthing went wrong!!1?
    }

  }

  _validate() {
    return Promise.resolve(true);
  }

  _exec() {
    return this.model.findAll();
  }
}
routes.push(GetList);

/**
 * @class GetOne
 */
class GetOne extends Route {
  constructor() {
    super('entity/:id', 'GET ENTITY');
    this.verb = Route.Constants.Verbs.GET;
    this.auth = Route.Constants.Auth.ADMIN;
    this.permissions = Route.Constants.Permissions.READ;

    this._entity = false;
  }

  _validate() {
    return new Promise((resolve, reject) => {
      this.model.getById(this.req.params.id)
        .then(entity => {
          if (!entity) {
            this.log(`ERROR: Invalid ID: ${this.req.params.id}`, Route.LogLevel.ERR);
            reject({statusCode: 400});
            return;
          }
          this._entity = entity;
          resolve(true);
        });
    });
  }

  _exec() {
    return Promise.resolve(this._entity);
  }
}
// routes.push(GetOne);

/**
 * @class AddOne
 */
class AddOne extends Route {
  constructor() {
    super('entity', 'ADD ENTITY');
    this.verb = Route.Constants.Verbs.POST;
    this.auth = Route.Constants.Auth.ADMIN;
    this.permissions = Route.Constants.Permissions.ADD;

    this.activityVisibility = Model.Constants.Activity.Visibility.PRIVATE;
    this.activityBroadcast = true;
  }

  _validate() {
    return new Promise((resolve, reject) => {
      let validation = this.model.validate(this.req.body);
      if (!validation.isValid) {
        if (validation.missing.length > 0) {
          this.log(`ERROR: Missing field: ${validation.missing[0]}`, Route.LogLevel.ERR);
          reject({statusCode: 400, message: `COMPANY: Missing field: ${validation.missing[0]}`});
          return;
        }
        if (validation.invalid.length > 0) {
          this.log(`ERROR: Invalid value: ${validation.invalid[0]}`, Route.LogLevel.ERR);
          reject({statusCode: 400, message: `COMPANY: Invalid value: ${validation.invalid[0]}`});
          return;
        }

        this.log(`ERROR: COMPANY: Unhandled Error`, Route.LogLevel.ERR);
        reject({statusCode: 400, message: `COMPANY: Unhandled error.`});
        return;
      }

      this.model.isDuplicate(this.req.body)
        .then(res => {
          if (res === true) {
            this.log('ERROR: Duplicate company', Route.LogLevel.ERR);
            reject({statusCode: 400});
            return;
          }
          resolve(true);
        });
    });
  }

  _exec() {
    return this.model.add(this.req.body);
  }
}
// routes.push(AddOne);

/**
 * @class UpdateOne
 */
class UpdateOne extends Route {
  constructor() {
    super('entity/:id', 'UPDATE ENTITY');
    this.verb = Route.Constants.Verbs.PUT;
    this.auth = Route.Constants.Auth.ADMIN;
    this.permissions = Route.Constants.Permissions.WRITE;
    this._entity = null;

    this.activityVisibility = Model.Constants.Activity.Visibility.PRIVATE;
    this.activityBroadcast = true;
  }

  _validate() {
    return new Promise((resolve, reject) => {
      let validation = this.model.validateUpdate(this.req.body);
      if (!validation.isValid) {
        if (validation.isPathValid === false) {
          this.log(`ERROR: Update path is invalid: ${validation.invalidPath}`, Route.LogLevel.ERR);
          reject({statusCode: 400, message: `COMPANY: Update path is invalid: ${validation.invalidPath}`});
          return;
        }
        if (validation.isValueValid === false) {
          this.log(`ERROR: Update value is invalid: ${validation.invalidValue}`, Route.LogLevel.ERR);
          if (validation.isMissingRequired) {
            reject({statusCode: 400, message: `COMPANY: Missing required property updating ${this.req.body.path}: ${validation.missingRequired}`});
          } else {
            reject({statusCode: 400, message: `COMPANY: Update value is invalid for path ${this.req.body.path}: ${validation.invalidValue}`});
          }
          return;
        }
      }

      this.model.exists(this.req.params.id)
        .then(exists => {
          if (!exists) {
            this.log('ERROR: Invalid ID', Route.LogLevel.ERR);
            reject({statusCode: 400});
            return;
          }
          resolve(true);
        });
    });
  }

  _exec() {
    return this.model.updateByPath(this.req.body, this.req.params.id);
  }
}
// routes.push(UpdateOne);

/**
 * @class DeleteOne
 */
class DeleteOne extends Route {
  constructor() {
    super('entity/:id', 'DELETE ENTITY');
    this.verb = Route.Constants.Verbs.DEL;
    this.auth = Route.Constants.Auth.ADMIN;
    this.permissions = Route.Constants.Permissions.DELETE;
    this._entity = false;
  }

  _validate() {
    return new Promise((resolve, reject) => {
      this.model.findById(this.req.params.id)
        .then(entity => {
          if (!entity) {
            this.log('ERROR: Invalid ID', Route.LogLevel.ERR);
            reject({statusCode: 400});
            return;
          }
          this._entity = entity;
          resolve(true);
        });
    });
  }

  _exec() {
    return this.model.rm(this._entity).then(() => true);
  }
}
// routes.push(DeleteOne);

/**
 * @type {*[]}
 */
module.exports = routes;
<commit_msg>- ADDED: Enabled core routes in schemaRoutes<commit_after>'use strict';

/**
 * ButtressJS - Realtime datastore for business software
 *
 * @file schemaRoutes.js
 * @description A list of default routes for schema
 * @module routes
 * @author Chris Bates-Keegan
 *
 */

const Route = require('./route');
const Model = require('../model');
// const Helpers = require('../../helpers');

let routes = [];

/**
 * @class GetList
 */
class GetList extends Route {
  constructor(schema) {
    super(`${schema.collection}`, `GET ${schema.collection} LIST`);
    this.verb = Route.Constants.Verbs.GET;
    this.auth = Route.Constants.Auth.ADMIN;
    this.permissions = Route.Constants.Permissions.LIST;

    // Fetch model
    this.model = Model[schema.collection];
    if (!this.model) {
      // Somthing went wrong!!1?
    }

  }

  _validate() {
    return Promise.resolve(true);
  }

  _exec() {
    return this.model.findAll();
  }
}
routes.push(GetList);

/**
 * @class GetOne
 */
class GetOne extends Route {
  constructor(schema) {
    super(`${schema.collection}/:id`, `GET ${schema.collection}`);
    this.verb = Route.Constants.Verbs.GET;
    this.auth = Route.Constants.Auth.ADMIN;
    this.permissions = Route.Constants.Permissions.READ;

    this.schema = schema;
    this.model = Model[schema.collection];

    this._entity = false;
  }

  _validate() {
    return new Promise((resolve, reject) => {
      this.model.getById(this.req.params.id)
        .then(entity => {
          if (!entity) {
            this.log(`${this.schema.collection}: Invalid ID: ${this.req.params.id}`, Route.LogLevel.ERR);
            reject({statusCode: 400});
            return;
          }
          this._entity = entity;
          resolve(true);
        });
    });
  }

  _exec() {
    return Promise.resolve(this._entity);
  }
}
routes.push(GetOne);

/**
 * @class AddOne
 */
class AddOne extends Route {
  constructor(schema) {
    super(`${schema.collection}`, `ADD ${schema.collection}`);
    this.verb = Route.Constants.Verbs.POST;
    this.auth = Route.Constants.Auth.ADMIN;
    this.permissions = Route.Constants.Permissions.ADD;

    this.schema = schema;
    this.model = Model[schema.collection];
  }

  _validate() {
    return new Promise((resolve, reject) => {
      let validation = this.model.validate(this.req.body);
      if (!validation.isValid) {
        if (validation.missing.length > 0) {
          this.log(`${this.schema.collection}: Missing field: ${validation.missing[0]}`, Route.LogLevel.ERR);
          reject({statusCode: 400, message: `${this.schema.collection}: Missing field: ${validation.missing[0]}`});
          return;
        }
        if (validation.invalid.length > 0) {
          this.log(`${this.schema.collection}: Invalid value: ${validation.invalid[0]}`, Route.LogLevel.ERR);
          reject({statusCode: 400, message: `${this.schema.collection}: Invalid value: ${validation.invalid[0]}`});
          return;
        }

        this.log(`${this.schema.collection}: Unhandled Error`, Route.LogLevel.ERR);
        reject({statusCode: 400, message: `${this.schema.collection}: Unhandled error.`});
        return;
      }

      this.model.isDuplicate(this.req.body)
        .then(res => {
          if (res === true) {
            this.log(`${this.schema.collection}: Duplicate entity`, Route.LogLevel.ERR);
            reject({statusCode: 400});
            return;
          }
          resolve(true);
        });
    });
  }

  _exec() {
    return this.model.add(this.req.body);
  }
}
routes.push(AddOne);

/**
 * @class UpdateOne
 */
class UpdateOne extends Route {
  constructor(schema) {
    super(`${schema.collection}/:id`, `UPDATE ${schema.collection}`);
    this.verb = Route.Constants.Verbs.PUT;
    this.auth = Route.Constants.Auth.ADMIN;
    this.permissions = Route.Constants.Permissions.WRITE;

    this.schema = schema;
    this.model = Model[schema.collection];

    this._entity = null;
  }

  _validate() {
    return new Promise((resolve, reject) => {
      let validation = this.model.validateUpdate(this.req.body);
      if (!validation.isValid) {
        if (validation.isPathValid === false) {
          this.log(`${this.schema.collection}: Update path is invalid: ${validation.invalidPath}`, Route.LogLevel.ERR);
          reject({
            statusCode: 400,
            message: `${this.schema.collection}: Update path is invalid: ${validation.invalidPath}`
          });
          return;
        }
        if (validation.isValueValid === false) {
          this.log(`${this.schema.collection}: Update value is invalid: ${validation.invalidValue}`, Route.LogLevel.ERR);
          if (validation.isMissingRequired) {
            reject({
              statusCode: 400,
              message: `${this.schema.collection}: Missing required property updating ${this.req.body.path}: ${validation.missingRequired}`
            });
          } else {
            reject({
              statusCode: 400,
              message: `${this.schema.collection}: Update value is invalid for path ${this.req.body.path}: ${validation.invalidValue}`
            });
          }
          return;
        }
      }

      this.model.exists(this.req.params.id)
        .then(exists => {
          if (!exists) {
            this.log('ERROR: Invalid ID', Route.LogLevel.ERR);
            reject({statusCode: 400});
            return;
          }
          resolve(true);
        });
    });
  }

  _exec() {
    return this.model.updateByPath(this.req.body, this.req.params.id);
  }
}
routes.push(UpdateOne);

/**
 * @class DeleteOne
 */
class DeleteOne extends Route {
  constructor(schema) {
    super(`${schema.collection}/:id`, `DELETE ${schema.collection}`);
    this.verb = Route.Constants.Verbs.DEL;
    this.auth = Route.Constants.Auth.ADMIN;
    this.permissions = Route.Constants.Permissions.DELETE;

    this.schema = schema;
    this.model = Model[schema.collection];

    this._entity = false;
  }

  _validate() {
    return new Promise((resolve, reject) => {
      this.model.findById(this.req.params.id)
        .then(entity => {
          if (!entity) {
            this.log(`${this.schema.collection}: Invalid ID`, Route.LogLevel.ERR);
            reject({statusCode: 400});
            return;
          }
          this._entity = entity;
          resolve(true);
        });
    });
  }

  _exec() {
    return this.model.rm(this._entity).then(() => true);
  }
}
routes.push(DeleteOne);

/**
 * @type {*[]}
 */
module.exports = routes;
<|endoftext|>


<commit_before>(function() {
/**
 * PLUTO
 * Native HTML Template Rendering
 *
 *
 * The MIT License (MIT)
 * Copyright (c) 2013 Roi Avinoam
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
class Template extends HTMLTemplateElement {
    render(obj) {
        var compiled = this._compiled || (this._compiled = {})
        if (compiled.html !== this.innerHTML) { // recompile
            // console.log('RECOMPILE', this) // bad - nested cloned templates are re-compiled on every item
            Object.assign(compiled, this.compile(), { html: this.innerHTML })
        }

        var { content, exprs, items } = compiled
        return new Renderer(content, exprs, items).render(obj)
    }

    _renderIn(obj, el) {
        if (el.__plutoRenderer) {
            el.__plutoRenderer.render(obj)
        } else {
            var doc = this.render(obj)
            el.replaceWith(doc)
            el.__plutoRenderer = doc
            el.remove = doc.remove.bind(doc)
        }
    }

    compile() {
        var exprs = []
        var clone = this.cloneNode(true)
        var elements = [{ el: clone.content, path: [] }]
        while (elements.length > 0) {
            var { el, path } = elements.shift()

            if (el.localName === 'template') {
                // nested templates are coerced to Pluto Templates. This
                // prevents the need to repeatedly mark templates with pluto-tpl
                // with the trade-off of not supporting a mixture of template
                // libraries.
                var render = (el, _, obj) => pluto(el)._renderIn(obj, el)
                exprs.push({ path, render })
                continue
            }

            // inner content expressions
            if (el.nodeName === '#text') {
                var expr = isExpressions(el.textContent)
                if (expr) {
                    el.textContent = ''
                    var render = (el, v) => (el.textContent = v || '')
                    exprs.push({ expr, path, render })
                }
            }

            // attributes
            Array.from(el.attributes || []).forEach(function(attr) {
                var expr = isExpressions(attr.value)
                if (expr === null) {
                    return
                }

                // avoid having the attribute on import as it might arrive
                // un-rendered to web-components. NB: this means that the
                // constructor of elements wouldn't have access to the rendered
                // values initially. Perhaps we should initially render into a
                // clone before finally importing.
                el.removeAttribute(attr.name)
                attr = attr.name
                var evName, prop
                if (attr.startsWith('on-')) {
                    evName = attr.slice(3)
                    var render = function(el, v) {
                        var evs = el.__plutoEvs || (el.__plutoEvs = {})
                        if (evs[evName] !== v) {
                            el.removeEventListener(evName, evs[evName])
                            el.addEventListener(evName, evs[evName] = v)
                        }
                    }
                } else if (['style', 'class'].indexOf(attr) !== -1) {
                    var render = (el, v) => v
                        ? el.setAttribute(attr, v)
                        : el.removeAttribute(attr)
                } else {
                    prop = snakeToCamelCase(attr)
                    var render = (el, v) => el[prop] = v
                }

                exprs.push({ expr, path, attr, evName, prop, render })
            }, this)

            // enqueue children
            el.childNodes.forEach(function(el, i) {
                elements.push({ el, path: path.concat(['childNodes', i]) })
            })
        }

        var repeat = this.getAttribute('repeat') || this.getAttribute('for')
        if (repeat) {
            repeat = compileExpressions([{ expr: repeat }])
            clone.items = (obj) => repeat(obj)[0] || []
        }

        var elseIf = this.getAttribute('else-if')
        var cond = this.getAttribute('if') || elseIf
        if (cond) {
            cond = compileExpressions([{ expr: cond }])
            clone.items = (obj) => Boolean(cond(obj)[0])
        }

        var else_ = this.hasAttribute('else') || elseIf
        if (else_) {
            var else_ = clone.items || Array
            clone.items = (obj) => obj.__plutoElse ? [] : else_(obj)
        }

        // we opt to compile the repeat/cond expressions separately than the
        // rest of this template - because (a) the template might relay on a
        // repeated ${item} property that doesn't yet exist in the repeat
        // expression, and (b) it's must smaller/faster than the complete
        // expressions list.
        // NB: It might not be that beneficial for cond though.
        clone.exprs = Object.assign(exprs, { eval: compileExpressions(exprs) })
        return { content: clone.content, exprs: clone.exprs, items: clone.items }
    }
}

class Renderer extends DocumentFragment {
    constructor(content, exprs, items) {
        super()
        this.tpl = content
        this.exprs = exprs
        this.items = items

        this.elements = []
        this.paths = {}

        if (items) {
            this.placeholder = document.createTextNode('')
            this.appendChild(this.placeholder)
        } else {
            this.appendChild(document.importNode(this.tpl, true))

            // copy the list of generated elements from the template in order
            // to support removals
            this.elements = [].map.call(this.childNodes, child => child)
            this.paths = this.exprs.map((expr) => select(this, expr.path))
        }
    }

    remove() {
        while (this.elements.length > 0) {
            this.elements.pop().remove()
        }
    }

    render(obj) {
        if (!this.items) {
            return this._renderOne(obj)
        }

        var items = this.items(obj)
        var item = obj.item
        if (!Array.isArray(items) && typeof items === 'object') {
            items = Object.keys(items).map(function(k) {
                return { key: k, value: items[k] }
            })
        }

        if (typeof items === 'boolean') {
            items = Number(items) // 0 or 1
        }

        if (typeof items === 'number') {
            items = new Array(items) // range-items, repeat N times.
            items = Array.from(items).map(() => item)
        }

        obj.__plutoElse = obj.__plutoElse || items && items.length > 0

        // remove obsolete items
        while (this.elements.length > items.length) {
            this.elements.pop().remove()
        }

        // update existing items
        for (var i = 0; i < this.elements.length; i += 1) {
            obj.item = items[i]
            this.elements[i].render(obj)
        }

        // create new items
        while (this.elements.length < items.length) {
            var i = this.elements.length
            obj.item = items[i]
            var doc = new Renderer(this.tpl, this.exprs).render(obj)
            this.elements.push(doc)
            this.placeholder.before(doc)
        }

        obj.item = item // restore previous item value.
        return this
    }

    _renderOne(obj) {
        var else_ = obj.__plutoElse
        obj.__plutoElse = false

        var values = this.exprs.eval(obj)
        var subtpls = []
        for (var i = 0 ; i < this.exprs.length ; i += 1) {
            var expr = this.exprs[i]
            var el = this.paths[i]
            var v = values[i]
            expr.render(el, v, obj)
        }

        obj.__plutoElse = else_
        return this
    }
}

// -- HELPER FUNCTIONS

// Searches for an element from root based on the property-path to the child
// example: root = <body>, path = childNodes.3.childNode.7. Resolved by walking
// the path down to the child.
function select(root, path) {
    var el = root
    for (var i = 0; el !== undefined && i < path.length; i += 1) {
        el = el[path[i]]
    }
    return el
}

const SNAKE_RE = /-([a-z])/g
function snakeToCamelCase(s) {
    return s.replace(SNAKE_RE, g => g[1].toUpperCase())
}

// extract expressions in template-literal syntax out of a string
var EXPR_RE = /\$\{[^\}]*\}/
function isExpressions(s) {
    return EXPR_RE.test(s) ? s : null
}

// compile a list of template-literal expressions into a function that evaluates
// these expression for the provided input object
function compileExpressions(exprs) {
    var refs = []
    var code = 'this.__plutoT || (this.__plutoT = T.bind(this));\n'
    code += exprs.map(function(expr, i) {
        if (expr.expr === undefined) {
            return '' // can happen in nested templates
        }

        if (expr.expr) {
            refs = refs.concat(getIdentifiers(expr.expr))
        }

        var tagFn = ({
            'class': 'classNameT',
            'style': 'styleT'
        })[expr.attr] || 'this.__plutoT'

        return `arguments[0][${i}] = ${tagFn}\`${expr.expr}\``
    }).join(';\n')

    // define the local variables and bind root-level functions to the provided
    // rendered object.
    var keys = refs.reduce((keys, k) => (keys[k] = true, keys), {})
    var locals = Object.keys(keys).map(function (k) {
        return `
            var ${k} = this["${k}"];
            typeof ${k} === 'function' && (${k} = bindFn(this, ${k}))
        `
    }).join(';\n')

    var fn = eval('(function () {\n' + locals + '\n' + code + '\n})')
    return function(obj) {
        var res = []
        try {
            fn.call(obj, res)
        } catch (e) {
            console.warn(fn)
            throw e
        }

        return res
    }

    function bindFn(obj, fn) {
        var bound = fn.__plutoBound || (fn.__plutoBound = {})
        if (bound.to !== obj) {
            bound.to = obj
            bound.fn = fn.bind(obj)
        }

        return bound.fn
    }

    function T(s, v) {
        return arguments.length > 2 || typeof v === 'string'
            ? String.raw.apply(null, arguments)
            : v
    }

    function classNameT(s, v) {
        if (typeof v === 'object') {
            if (!Array.isArray(v)) {
                v = Object.keys(v).filter((k) => v[k])
            }

            return v.join(' ')
        }

        return String.raw.apply(null, arguments)
    }

    function styleT(s, v) {
        if (typeof v === 'object') {
            return Object.keys(v).map((k) => k + ':' + v[k]).join('; ')
        }

        return String.raw.apply(null, arguments)
    }
}

// generate the list of identifiers found in the code.
function getIdentifiers(expr) {
    var re = /[$A-Z_][0-9A-Z_$]*/ig
    var whitespace = ' \n\r\t'
    var disallowed = '\'\".'
    var skip = ['true', 'false', 'if', 'for', 'while', 'do', 'try', 'catch',
        'break', 'continue', 'switch', 'throw', 'this', 'instanceof', 'in',
        'function', 'delete', 'default', 'case', 'debugger', 'const', 'var',
        'with', 'typeof', 'super', 'class', 'new', 'null', 'return', 'let',
        'import', 'else', 'enum', 'extends', 'finally', '$']

    // We first match for the valid identifier, and then check the previous
    // non-whitespace character preceeding the identifier to verify that it's
    // not a string or nested element.
    var refs = {}
    var match
    while (match = re.exec(expr)) {
        if (skip.indexOf(match[0]) !== -1) {
            continue // skipped or reserved keyword
        }

        if (window[match[0]] !== undefined) {
            continue // keep global functions (Object, Array, etc.)
        }

        var lastChar = undefined
        do {
            match.index -= 1
            if (whitespace.indexOf(expr[match.index]) === -1) {
                lastChar = expr[match.index]
            }
        } while (match.index > -1 && !lastChar)

        if (disallowed.indexOf(lastChar) === -1) {
            refs[match[0]] = true
        }
    }

    return Object.keys(refs)
}

// upgrade an element
// NOTE this will be unnecessary with customElements
function pluto(el) {
    if (typeof el === 'string') {
        // support HTML-imported selections
        var doc = document._currentScript // used by pollyfills
            || document.currentScript // native.
            || document // not an import.
        el = (doc.ownerDocument || doc).querySelector(el)
    }

    return !el || el instanceof Template
        ? el
        : Object.setPrototypeOf(el, Template.prototype)
}

pluto.Template = Template
pluto.RepeatRenderer = Renderer
window.pluto = pluto
})();

(function() {

    // placed here in order to have its own scope clear of any of the pluto
    // local variables.
    pluto._eval = function(code) {
        return eval(code)
    }
})();
<commit_msg>Compile can now execute on any root node, not just a template<commit_after>(function() {
/**
 * PLUTO
 * Native HTML Template Rendering
 *
 *
 * The MIT License (MIT)
 * Copyright (c) 2013 Roi Avinoam
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
class Template extends HTMLTemplateElement {
    render(obj) {
        var compiled = this._compiled || (this._compiled = {})
        if (compiled.html !== this.innerHTML) { // recompile
            // console.log('RECOMPILE', this) // bad - nested cloned templates are re-compiled on every item
            var content = this.cloneNode(true).content
            Object.assign(compiled, this.compile(content), {
                html: this.innerHTML
            })
        }

        var { content, exprs, items } = compiled
        return new Renderer(content, exprs, items).render(obj)
    }

    _renderIn(obj, el) {
        if (el.__plutoRenderer) {
            el.__plutoRenderer.render(obj)
        } else {
            var doc = this.render(obj)
            el.replaceWith(doc)
            el.__plutoRenderer = doc
            el.remove = doc.remove.bind(doc)
        }
    }

    compile(content) {
        var exprs = []
        var clone = this.cloneNode(true)
        var elements = [{ el: content, path: [] }]
        while (elements.length > 0) {
            var { el, path } = elements.shift()

            if (el.localName === 'template') {
                // nested templates are coerced to Pluto Templates. This
                // prevents the need to repeatedly mark templates with pluto-tpl
                // with the trade-off of not supporting a mixture of template
                // libraries.
                var render = (el, _, obj) => pluto(el)._renderIn(obj, el)
                exprs.push({ path, render })
                continue
            }

            // inner content expressions
            if (el.nodeName === '#text') {
                var expr = isExpressions(el.textContent)
                if (expr) {
                    el.textContent = ''
                    var render = (el, v) => (el.textContent = v || '')
                    exprs.push({ expr, path, render })
                }
            }

            // attributes
            Array.from(el.attributes || []).forEach(function(attr) {
                var expr = isExpressions(attr.value)
                if (expr === null) {
                    return
                }

                // avoid having the attribute on import as it might arrive
                // un-rendered to web-components. NB: this means that the
                // constructor of elements wouldn't have access to the rendered
                // values initially. Perhaps we should initially render into a
                // clone before finally importing.
                el.removeAttribute(attr.name)
                attr = attr.name
                var evName, prop
                if (attr.startsWith('on-')) {
                    evName = attr.slice(3)
                    var render = function(el, v) {
                        var evs = el.__plutoEvs || (el.__plutoEvs = {})
                        if (evs[evName] !== v) {
                            el.removeEventListener(evName, evs[evName])
                            el.addEventListener(evName, evs[evName] = v)
                        }
                    }
                } else if (['style', 'class'].indexOf(attr) !== -1) {
                    var render = (el, v) => v
                        ? el.setAttribute(attr, v)
                        : el.removeAttribute(attr)
                } else {
                    prop = snakeToCamelCase(attr)
                    var render = (el, v) => el[prop] = v
                }

                exprs.push({ expr, path, attr, evName, prop, render })
            }, this)

            // enqueue children
            el.childNodes.forEach(function(el, i) {
                elements.push({ el, path: path.concat(['childNodes', i]) })
            })
        }

        var items
        var repeat = this.getAttribute('repeat') || this.getAttribute('for')
        if (repeat) {
            repeat = compileExpressions([{ expr: repeat }])
            items = (obj) => repeat(obj)[0] || []
        }

        var elseIf = this.getAttribute('else-if')
        var cond = this.getAttribute('if') || elseIf
        if (cond) {
            cond = compileExpressions([{ expr: cond }])
            items = (obj) => Boolean(cond(obj)[0])
        }

        var else_ = this.hasAttribute('else') || elseIf
        if (else_) {
            var else_ = clone.items || Array
            items = (obj) => obj.__plutoElse ? [] : else_(obj)
        }

        // we opt to compile the repeat/cond expressions separately than the
        // rest of this template - because (a) the template might relay on a
        // repeated ${item} property that doesn't yet exist in the repeat
        // expression, and (b) it's must smaller/faster than the complete
        // expressions list.
        // NB: It might not be that beneficial for cond though.
        exprs = Object.assign(exprs, { eval: compileExpressions(exprs) })
        return { content, exprs, items }
    }
}

class Renderer extends DocumentFragment {
    constructor(content, exprs, items) {
        super()
        this.tpl = content
        this.exprs = exprs
        this.items = items

        this.elements = []
        this.paths = {}

        if (items) {
            this.placeholder = document.createTextNode('')
            this.appendChild(this.placeholder)
        } else {
            this.appendChild(document.importNode(this.tpl, true))

            // copy the list of generated elements from the template in order
            // to support removals
            this.elements = [].map.call(this.childNodes, child => child)
            this.paths = this.exprs.map((expr) => select(this, expr.path))
        }
    }

    remove() {
        while (this.elements.length > 0) {
            this.elements.pop().remove()
        }
    }

    render(obj) {
        if (!this.items) {
            return this._renderOne(obj)
        }

        var items = this.items(obj)
        var item = obj.item
        if (!Array.isArray(items) && typeof items === 'object') {
            items = Object.keys(items).map(function(k) {
                return { key: k, value: items[k] }
            })
        }

        if (typeof items === 'boolean') {
            items = Number(items) // 0 or 1
        }

        if (typeof items === 'number') {
            items = new Array(items) // range-items, repeat N times.
            items = Array.from(items).map(() => item)
        }

        obj.__plutoElse = obj.__plutoElse || items && items.length > 0

        // remove obsolete items
        while (this.elements.length > items.length) {
            this.elements.pop().remove()
        }

        // update existing items
        for (var i = 0; i < this.elements.length; i += 1) {
            obj.item = items[i]
            this.elements[i].render(obj)
        }

        // create new items
        while (this.elements.length < items.length) {
            var i = this.elements.length
            obj.item = items[i]
            var doc = new Renderer(this.tpl, this.exprs).render(obj)
            this.elements.push(doc)
            this.placeholder.before(doc)
        }

        obj.item = item // restore previous item value.
        return this
    }

    _renderOne(obj) {
        var else_ = obj.__plutoElse
        obj.__plutoElse = false

        var values = this.exprs.eval(obj)
        var subtpls = []
        for (var i = 0 ; i < this.exprs.length ; i += 1) {
            var expr = this.exprs[i]
            var el = this.paths[i]
            var v = values[i]
            expr.render(el, v, obj)
        }

        obj.__plutoElse = else_
        return this
    }
}

// -- HELPER FUNCTIONS

// Searches for an element from root based on the property-path to the child
// example: root = <body>, path = childNodes.3.childNode.7. Resolved by walking
// the path down to the child.
function select(root, path) {
    var el = root
    for (var i = 0; el !== undefined && i < path.length; i += 1) {
        el = el[path[i]]
    }
    return el
}

const SNAKE_RE = /-([a-z])/g
function snakeToCamelCase(s) {
    return s.replace(SNAKE_RE, g => g[1].toUpperCase())
}

// extract expressions in template-literal syntax out of a string
var EXPR_RE = /\$\{[^\}]*\}/
function isExpressions(s) {
    return EXPR_RE.test(s) ? s : null
}

// compile a list of template-literal expressions into a function that evaluates
// these expression for the provided input object
function compileExpressions(exprs) {
    var refs = []
    var code = 'this.__plutoT || (this.__plutoT = T.bind(this));\n'
    code += exprs.map(function(expr, i) {
        if (expr.expr === undefined) {
            return '' // can happen in nested templates
        }

        if (expr.expr) {
            refs = refs.concat(getIdentifiers(expr.expr))
        }

        var tagFn = ({
            'class': 'classNameT',
            'style': 'styleT'
        })[expr.attr] || 'this.__plutoT'

        return `arguments[0][${i}] = ${tagFn}\`${expr.expr}\``
    }).join(';\n')

    // define the local variables and bind root-level functions to the provided
    // rendered object.
    var keys = refs.reduce((keys, k) => (keys[k] = true, keys), {})
    var locals = Object.keys(keys).map(function (k) {
        return `
            var ${k} = this["${k}"];
            typeof ${k} === 'function' && (${k} = bindFn(this, ${k}))
        `
    }).join(';\n')

    var fn = eval('(function () {\n' + locals + '\n' + code + '\n})')
    return function(obj) {
        var res = []
        try {
            fn.call(obj, res)
        } catch (e) {
            console.warn(fn)
            throw e
        }

        return res
    }

    function bindFn(obj, fn) {
        var bound = fn.__plutoBound || (fn.__plutoBound = {})
        if (bound.to !== obj) {
            bound.to = obj
            bound.fn = fn.bind(obj)
        }

        return bound.fn
    }

    function T(s, v) {
        return arguments.length > 2 || typeof v === 'string'
            ? String.raw.apply(null, arguments)
            : v
    }

    function classNameT(s, v) {
        if (typeof v === 'object') {
            if (!Array.isArray(v)) {
                v = Object.keys(v).filter((k) => v[k])
            }

            return v.join(' ')
        }

        return String.raw.apply(null, arguments)
    }

    function styleT(s, v) {
        if (typeof v === 'object') {
            return Object.keys(v).map((k) => k + ':' + v[k]).join('; ')
        }

        return String.raw.apply(null, arguments)
    }
}

// generate the list of identifiers found in the code.
function getIdentifiers(expr) {
    var re = /[$A-Z_][0-9A-Z_$]*/ig
    var whitespace = ' \n\r\t'
    var disallowed = '\'\".'
    var skip = ['true', 'false', 'if', 'for', 'while', 'do', 'try', 'catch',
        'break', 'continue', 'switch', 'throw', 'this', 'instanceof', 'in',
        'function', 'delete', 'default', 'case', 'debugger', 'const', 'var',
        'with', 'typeof', 'super', 'class', 'new', 'null', 'return', 'let',
        'import', 'else', 'enum', 'extends', 'finally', '$']

    // We first match for the valid identifier, and then check the previous
    // non-whitespace character preceeding the identifier to verify that it's
    // not a string or nested element.
    var refs = {}
    var match
    while (match = re.exec(expr)) {
        if (skip.indexOf(match[0]) !== -1) {
            continue // skipped or reserved keyword
        }

        if (window[match[0]] !== undefined) {
            continue // keep global functions (Object, Array, etc.)
        }

        var lastChar = undefined
        do {
            match.index -= 1
            if (whitespace.indexOf(expr[match.index]) === -1) {
                lastChar = expr[match.index]
            }
        } while (match.index > -1 && !lastChar)

        if (disallowed.indexOf(lastChar) === -1) {
            refs[match[0]] = true
        }
    }

    return Object.keys(refs)
}

// upgrade an element
// NOTE this will be unnecessary with customElements
function pluto(el) {
    if (typeof el === 'string') {
        // support HTML-imported selections
        var doc = document._currentScript // used by pollyfills
            || document.currentScript // native.
            || document // not an import.
        el = (doc.ownerDocument || doc).querySelector(el)
    }

    return !el || el instanceof Template
        ? el
        : Object.setPrototypeOf(el, Template.prototype)
}

pluto.Template = Template
pluto.RepeatRenderer = Renderer
window.pluto = pluto
})();

(function() {

    // placed here in order to have its own scope clear of any of the pluto
    // local variables.
    pluto._eval = function(code) {
        return eval(code)
    }
})();
<|endoftext|>


<commit_before>/**
 * Handling of tags input fields.
 *
 * @mixin
 * @namespace Bolt.fields.tags
 *
 * @param {Object} bolt - The Bolt module.
 * @param {Object} $ - jQuery.
 */
(function (bolt, $) {

    /**
     * Bolt.fields.tags mixin container.
     *
     * @private
     * @type {Object}
     */
    var tags = {};

    /**
     * Bind tags field.
     *
     * @static
     * @function init
     * @memberof Bolt.fields.tags
     *
     * @param {Object} fieldset
     * @param {FieldConf} fconf
     */
    tags.init = function (fieldset, fconf) {
        var slug = fconf.slug,
            idTagcloud = '#tagcloud-' + slug,
            taxonomy = $(fieldset).find('input');

        // Load all tags.
        $.ajax({
            url: bolt.conf('paths.root') + 'async/tags/' + slug,
            dataType: 'json',
            success: function (data) {
                var results = [];

                $.each(data, function (index, item) {
                    results.push( item.slug );
                });

                taxonomy.select2({
                    tags: results,
                    minimumInputLength: 1,
                    tokenSeparators: [',', ' ']
                });
            },
            error: function () {
                taxonomy.select2({
                    tags: [],
                    minimumInputLength: 1,
                    tokenSeparators: [',', ' ']
                });
            }
        });

        // Popular tags.
        if (fconf.tagcloud) {
            $.ajax({
                url: bolt.conf('paths.root') + 'async/populartags/' + slug,
                dataType: 'json',
                data : {
                    limit: 40
                },
                success: function(data) {
                    if (data.length > 0) {
                        $.each(data, function(index, item){
                            $(idTagcloud).append('' + item.slug + '');
                        });

                        $(idTagcloud + ' a').on('click', function (e) {
                            var data;

                            e.preventDefault();
                            data = taxonomy.select2('data');
                            data.push({
                                id: $(this).text(),
                                text: $(this).text()
                            });
                            taxonomy.select2('data', data);
                        });

                        $.fn.tagcloud.defaults = {
                            size: {
                                start: 12,
                                end: 22,
                                unit: 'px'
                            },
                            color: {
                                start: '#888',
                                end: '#194770'
                            }
                        };
                        $(idTagcloud + ' a').tagcloud();
                    }
                }
            });
        }
    };

    // Apply mixin container
    bolt.fields.tags = tags;

})(Bolt || {}, jQuery);
<commit_msg>Find tagcloud fieldset relative<commit_after>/**
 * Handling of tags input fields.
 *
 * @mixin
 * @namespace Bolt.fields.tags
 *
 * @param {Object} bolt - The Bolt module.
 * @param {Object} $ - jQuery.
 */
(function (bolt, $) {

    /**
     * Bolt.fields.tags mixin container.
     *
     * @private
     * @type {Object}
     */
    var tags = {};

    /**
     * Bind tags field.
     *
     * @static
     * @function init
     * @memberof Bolt.fields.tags
     *
     * @param {Object} fieldset
     * @param {FieldConf} fconf
     */
    tags.init = function (fieldset, fconf) {
        var slug = fconf.slug,
            taxonomy = $(fieldset).find('input'),
            tagcloud = $(fieldset).find('div.tagcloud');

        // Load all tags.
        $.ajax({
            url: bolt.conf('paths.root') + 'async/tags/' + slug,
            dataType: 'json',
            success: function (data) {
                var results = [];

                $.each(data, function (index, item) {
                    results.push( item.slug );
                });

                taxonomy.select2({
                    tags: results,
                    minimumInputLength: 1,
                    tokenSeparators: [',', ' ']
                });
            },
            error: function () {
                taxonomy.select2({
                    tags: [],
                    minimumInputLength: 1,
                    tokenSeparators: [',', ' ']
                });
            }
        });

        // Popular tags.
        if (fconf.tagcloud) {
            $.ajax({
                url: bolt.conf('paths.root') + 'async/populartags/' + slug,
                dataType: 'json',
                data : {
                    limit: 40
                },
                success: function(data) {
                    if (data.length > 0) {
                        $.each(data, function(index, item){
                            tagcloud.append('' + item.slug + '');
                        });

                        tagcloud.find('a').on('click', function (e) {
                            var data;

                            e.preventDefault();
                            data = taxonomy.select2('data');
                            data.push({
                                id: $(this).text(),
                                text: $(this).text()
                            });
                            taxonomy.select2('data', data);
                        });

                        $.fn.tagcloud.defaults = {
                            size: {
                                start: 12,
                                end: 22,
                                unit: 'px'
                            },
                            color: {
                                start: '#888',
                                end: '#194770'
                            }
                        };
                        tagcloud.find('a').tagcloud();
                    }
                }
            });
        }
    };

    // Apply mixin container
    bolt.fields.tags = tags;

})(Bolt || {}, jQuery);
<|endoftext|>


<commit_before>/**
 * See (http://jquery.com/).
 * @name jQuery
 * @class
 * See the jQuery Library  (http://jquery.com/) for full details. This just
 * documents the function and classes that are added to jQuery by this plug-in.
 */

/**
 * See (http://jquery.com/)
 * @name widget
 * @class
 * See the jQuery Library  (http://jquery.com/) for full details. This just
 * documents the function and classes that are added to jQuery by this plug-in.
 * @memberOf jQuery
 */

/**
 * See (http://jquery.com/)
 * @name bolt
 * @class
 * @memberOf jQuery.widget
 * @param {object} $ - Global jQuery object
 */
(function ($) {
    'use strict';

    /**
     * Bolt select.
     *
     * @class select
     * @memberOf jQuery.widget.bolt
     * @license http://opensource.org/licenses/mit-license.php MIT License
     * @author rarila
     */
    $.widget('bolt.select', /** @lends jQuery.widget.bolt.select */ {
        /**
         * The constructor of the select widget.
         *
         * @private
         */
        _create: function () {
            var self = this;

            // Private properties
            this.select = this.element.find('select');
            this.buttonAll = this.element.find('.select-all');
            this.buttonNone = this.element.find('.select-none');

            // Initialize the select-all button.
            this.buttonAll
                .prop('title', this.buttonAll.text().trim())
                .on('click', function () {
                    self.all();
                    this.blur();
                });

            // Initialize the select-none button.
            this.buttonNone
                .prop('title', this.buttonNone.text().trim())
                .on('click', function () {
                    self.none();
                    this.blur();
                });

            // Enable/disable buttons.
            this._updateButtons();
        },

        /**
         * Enable/disable buttons based on selection state.
         *
         * @private
         */
        _updateButtons: function () {
            var options = this.select.find('option'),
                count = options.length,
                selected = options.filter(':selected').length,
                empty = this.select.prop('multiple') ? selected === 0 : this.select.val() === '';

            this.buttonAll.prop('disabled', selected === count);
            this.buttonNone.prop('disabled', empty);
        },

        /**
         * Selects all options.
         */
        all: function () {
            this.select.find('option').prop('selected', true);
            this._updateButtons();
        },

        /**
         * Unselects all options.
         */
        none: function () {
            this.select.val(null);
            this._updateButtons();
        }
    });
})(jQuery);
<commit_msg>Fix selecting all/none<commit_after>/**
 * See (http://jquery.com/).
 * @name jQuery
 * @class
 * See the jQuery Library  (http://jquery.com/) for full details. This just
 * documents the function and classes that are added to jQuery by this plug-in.
 */

/**
 * See (http://jquery.com/)
 * @name widget
 * @class
 * See the jQuery Library  (http://jquery.com/) for full details. This just
 * documents the function and classes that are added to jQuery by this plug-in.
 * @memberOf jQuery
 */

/**
 * See (http://jquery.com/)
 * @name bolt
 * @class
 * @memberOf jQuery.widget
 * @param {object} $ - Global jQuery object
 */
(function ($) {
    'use strict';

    /**
     * Bolt select.
     *
     * @class select
     * @memberOf jQuery.widget.bolt
     * @license http://opensource.org/licenses/mit-license.php MIT License
     * @author rarila
     */
    $.widget('bolt.select', /** @lends jQuery.widget.bolt.select */ {
        /**
         * The constructor of the select widget.
         *
         * @private
         */
        _create: function () {
            var self = this;

            // Private properties
            this.select = this.element.find('select');
            this.buttonAll = this.element.find('.select-all');
            this.buttonNone = this.element.find('.select-none');

            // Initialize the select-all button.
            this.buttonAll
                .prop('title', this.buttonAll.text().trim())
                .on('click', function () {
                    self.all();
                    this.blur();
                });

            // Initialize the select-none button.
            this.buttonNone
                .prop('title', this.buttonNone.text().trim())
                .on('click', function () {
                    self.none();
                    this.blur();
                });

            // Enable/disable buttons.
            this._updateButtons();
            this.select.on('change', function () {
                self._updateButtons();
            });
        },

        /**
         * Enable/disable buttons based on selection state.
         *
         * @private
         */
        _updateButtons: function () {
            var options = this.select.find('option'),
                count = options.length,
                selected = options.filter(':selected').length,
                empty = this.select.prop('multiple') ? selected === 0 : this.select.val() === '';

            this.buttonAll.prop('disabled', selected === count);
            this.buttonNone.prop('disabled', empty);
        },

        /**
         * Selects all options.
         */
        all: function () {
            this.select
                .find('option')
                .prop('selected', true)
                .trigger('change');
        },

        /**
         * Unselects all options.
         */
        none: function () {
            this.select
                .val(null)
                .trigger('change');
        }
    });
})(jQuery);
<|endoftext|>


<commit_before>define(['js/svg/SvgElement', 'sprd/entity/TextConfiguration', 'sprd/entity/DesignConfiguration', 'sprd/view/svg/TextConfigurationRenderer', 'sprd/view/svg/DesignConfigurationRenderer'],
    function (SvgElement, TextConfiguration, DesignConfiguration, TextConfigurationRenderer, DesignConfigurationRenderer) {

        return SvgElement.inherit({

            defaults: {
                tagName: 'g',
                "class": 'configuration-viewer'
            },

            $classAttributes: ["configuration"],

            ctor: function (attributes) {

                this.callBase();

                var configuration = attributes.configuration;

                if (!configuration) {
                    throw "Configuration for viewer not defined";
                }

                this.$configuration = configuration;

            },

            render: function() {

            }

//            _transform: function (svg) {
//
//                svg = svg || this.$svg;
//
//                if (!this.$configuration) {
//                    return;
//                }
//
//                var matrix = Raphael.matrix();
//                matrix.translate(this.$configuration.get('offset.x'), this.$configuration.get('offset.y'));
//                matrix.rotate(this.$configuration.get('rotation'), 0, 0);
//
//                if (this.$printAreaViewer) {
//                    this.$printAreaViewer.transform(matrix);
//                }
//
//                svg.transform(matrix.toTransformString());
//
//            }
        });
    });<commit_msg>removed unused code<commit_after>define(['js/svg/SvgElement', 'sprd/entity/TextConfiguration', 'sprd/entity/DesignConfiguration', 'sprd/view/svg/TextConfigurationRenderer', 'sprd/view/svg/DesignConfigurationRenderer'],
    function (SvgElement, TextConfiguration, DesignConfiguration, TextConfigurationRenderer, DesignConfigurationRenderer) {

        return SvgElement.inherit({

            defaults: {
                tagName: 'g',
                "class": 'configuration-viewer'
            },

            $classAttributes: ["configuration"],

            ctor: function (attributes) {

                this.callBase();

                var configuration = attributes.configuration;

                if (!configuration) {
                    throw "Configuration for viewer not defined";
                }

                this.$configuration = configuration;

            }
        });
    });<|endoftext|>