<commit_before>describe("Element-Event", function () {

    it("bind click", function (done) {
        var clicked = 0;

        var MyComponent = san.defineComponent({
            template: '{{name}}, please click here!',

            mainClicker: function () {
                expect(clicked).toBe(1);
                clicked++;
            },

            clicker: function (name, email, event) {
                expect(name).toBe('errorrik');
                expect(email).toBe('errorrik@gmail.com');
                expect(event.target || event.srcElement).toBe(span);

                expect(clicked).toBe(0);
                clicked++;
            }
        });
        var myComponent = new MyComponent();
        myComponent.data.set('name', 'errorrik');
        myComponent.data.set('email', 'errorrik@gmail.com');

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);

        var span = wrap.firstChild.firstChild;
        expect(span.getAttribute('title')).toBe('errorrik');

        function doneSpec() {

            if (clicked) {
                done();
                myComponent.dispose();
                document.body.removeChild(wrap);

                return;
            }

            setTimeout(doneSpec, 500);
        }

        triggerEvent('#' + span.id, 'click');

        doneSpec();

    });

    it("bind click fire default event when no args description, empty args description dont add default arg", function (done) {
        var clicked = 0;

        var MyComponent = san.defineComponent({
            template: 'please click here!please click here!',

            clicker: function (event) {
                expect(event == null).toBeTruthy();
                clicked += 1;
            },
            clickerNoArgs: function (event) {
                expect(event.target || event.srcElement).toBe(spanNoArgs);
                clicked += 1;
            }
        });
        var myComponent = new MyComponent();

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);
        var span = wrap.firstChild.firstChild;
        var spanNoArgs = wrap.firstChild.lastChild;
        function doneSpec() {
            if (clicked == 2) {
                done();
                myComponent.dispose();
                document.body.removeChild(wrap);
                return;
            }
            setTimeout(doneSpec, 500);
        }

        triggerEvent('#' + span.id, 'click');
        triggerEvent('#' + spanNoArgs.id, 'click');
        doneSpec();
    });

    it("native bind click", function (done) {
        var clicked = 0;
        var ChildComponent = san.defineComponent({
            template: '

child

'
        });

        var MyComponent = san.defineComponent({
            template:
            '
' +
                '<child-component s-ref="nativeChild" on-click="native:clicker"></child-component>' +
                '<child-component s-ref="child"></child-component>' +
            '
',
            components: {
                'child-component': ChildComponent
            },
            clicker: function (event) {
                var div = this.ref('nativeChild').el;
                expect(event.target || event.srcElement).toBe(div);
                clicked += 1;
            }
        });
        var myComponent = new MyComponent();

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);

        var nativeChildEl = wrap.firstChild.firstChild;
        var childEl = wrap.firstChild.lastChild;

        function doneSpec() {
            if (clicked === 1) {
                done();
                myComponent.dispose();
                document.body.removeChild(wrap);
                return;
            }
            setTimeout(doneSpec, 500);
        }
        // 两次点击，期望只有第一次nativeEvent的点击生效
        triggerEvent('#' + nativeChildEl.id, 'click');
        triggerEvent('#' + childEl.id, 'click');
        doneSpec();
    });

    it("issue-185", function (done) {
        var clicked = 0;

        var Button = san.defineComponent({
            template: '<button>{{text}}</button>'
        });

        var MyComponent = san.defineComponent({
            template:
            '
' +
                '<ui-button on-click="native:clicker(i, $event)" s-ref="btn-{{i}}" text="{{btn.text}}" s-for="btn,i in buttons" />' +
            '
',
            components: {
                'ui-button': Button
            },
            initData: function () {
                return {
                    buttons: [
                        {text: 'a'},
                        {text: 'b'},
                        {text: 'c'}
                    ]
                };
            },
            clicker: function (i, event) {
                var btn = this.ref('btn-' + i);
                expect(event.target || event.srcElement).toBe(btn.el);
                clicked += i;
            }
        });
        var myComponent = new MyComponent();

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);

        var aBtn = wrap.firstChild.children[0];
        var bBtn = wrap.firstChild.children[1];
        var cBtn = wrap.firstChild.children[2];

        function doneSpec() {
            if (clicked === (0 + 1 + 2)) {
                done();
                myComponent.dispose();
                document.body.removeChild(wrap);
                return;
            }
            setTimeout(doneSpec, 500);
        }
        triggerEvent('#' + aBtn.id, 'click');
        triggerEvent('#' + bBtn.id, 'click');
        triggerEvent('#' + cBtn.id, 'click');
        doneSpec();
    });

    it("capture modifier", function (done) {
        if (!document.addEventListener) {
            done();
            return;
        }

        var clicked = 0;

        var MyComponent = san.defineComponent({
            template: '{{name}}, please click here!',

            mainClicker: function () {
                clicked++;
            },

            clicker: function (name, email, event) {
                expect(name).toBe('errorrik');
                expect(email).toBe('errorrik@gmail.com');
                expect(event.target || event.srcElement).toBe(span);

                expect(clicked).toBe(1);
                clicked++;
            }
        });
        var myComponent = new MyComponent();
        myComponent.data.set('name', 'errorrik');
        myComponent.data.set('email', 'errorrik@gmail.com');

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);

        var span = wrap.firstChild.firstChild;
        expect(span.getAttribute('title')).toBe('errorrik');

        function doneSpec() {

            if (clicked) {
                done();
                myComponent.dispose();
                document.body.removeChild(wrap);

                return;
            }

            setTimeout(doneSpec, 500);
        }

        triggerEvent('#' + span.id, 'click');

        doneSpec();

    });
});
<commit_msg>add #243 spec<commit_after>describe("Element-Event", function () {

    it("bind click", function (done) {
        var clicked = 0;

        var MyComponent = san.defineComponent({
            template: '{{name}}, please click here!',

            mainClicker: function () {
                expect(clicked).toBe(1);
                clicked++;
            },

            clicker: function (name, email, event) {
                expect(name).toBe('errorrik');
                expect(email).toBe('errorrik@gmail.com');
                expect(event.target || event.srcElement).toBe(span);

                expect(clicked).toBe(0);
                clicked++;
            }
        });
        var myComponent = new MyComponent();
        myComponent.data.set('name', 'errorrik');
        myComponent.data.set('email', 'errorrik@gmail.com');

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);

        var span = wrap.firstChild.firstChild;
        expect(span.getAttribute('title')).toBe('errorrik');

        function doneSpec() {

            if (clicked) {
                done();
                myComponent.dispose();
                document.body.removeChild(wrap);

                return;
            }

            setTimeout(doneSpec, 500);
        }

        triggerEvent('#' + span.id, 'click');

        doneSpec();

    });

    it("bind click fire default event when no args description, empty args description dont add default arg", function (done) {
        var clicked = 0;

        var MyComponent = san.defineComponent({
            template: 'please click here!please click here!',

            clicker: function (event) {
                expect(event == null).toBeTruthy();
                clicked += 1;
            },
            clickerNoArgs: function (event) {
                expect(event.target || event.srcElement).toBe(spanNoArgs);
                clicked += 1;
            }
        });
        var myComponent = new MyComponent();

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);
        var span = wrap.firstChild.firstChild;
        var spanNoArgs = wrap.firstChild.lastChild;
        function doneSpec() {
            if (clicked == 2) {
                done();
                myComponent.dispose();
                document.body.removeChild(wrap);
                return;
            }
            setTimeout(doneSpec, 500);
        }

        triggerEvent('#' + span.id, 'click');
        triggerEvent('#' + spanNoArgs.id, 'click');
        doneSpec();
    });

    it("native bind click", function (done) {
        var clicked = 0;
        var ChildComponent = san.defineComponent({
            template: '

child

'
        });

        var MyComponent = san.defineComponent({
            template:
            '
' +
                '<child-component s-ref="nativeChild" on-click="native:clicker"></child-component>' +
                '<child-component s-ref="child"></child-component>' +
            '
',
            components: {
                'child-component': ChildComponent
            },
            clicker: function (event) {
                var div = this.ref('nativeChild').el;
                expect(event.target || event.srcElement).toBe(div);
                clicked += 1;
            }
        });
        var myComponent = new MyComponent();

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);

        var nativeChildEl = wrap.firstChild.firstChild;
        var childEl = wrap.firstChild.lastChild;

        function doneSpec() {
            if (clicked === 1) {
                myComponent.dispose();
                document.body.removeChild(wrap);
                done();

                return;
            }
            setTimeout(doneSpec, 500);
        }
        // 两次点击，期望只有第一次nativeEvent的点击生效
        triggerEvent('#' + nativeChildEl.id, 'click');
        triggerEvent('#' + childEl.id, 'click');
        doneSpec();
    });

    it("native bind dont be invoked in fire", function (done) {
        var inCount = 0;
        var outCount = 0;
        var Checkbox = san.defineComponent({
            template: '<input type="checkbox" on-change="onChange" />',

            onChange: function () {
                inCount++;
                this.fire('change');
            }
        });

        var MyComponent = san.defineComponent({
            template: '
<x-checkbox on-change="native:onNativeChange"/>Click me and see console
',

            components: {
                'x-checkbox': Checkbox
            },

            onNativeChange: function () {
                outCount++;
            }
        });
        var myComponent = new MyComponent();

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);

        var input = wrap.getElementsByTagName('input')[0];

        function doneSpec() {
            if (inCount > 0) {
                expect(inCount).toBe(1);
                expect(outCount).toBe(1);

                myComponent.dispose();
                document.body.removeChild(wrap);
                done();
                return;
            }

            setTimeout(doneSpec, 500);
        }

        triggerEvent('#' + input.id, 'click');
        doneSpec();
    });

    it("issue-185", function (done) {
        var clicked = 0;

        var Button = san.defineComponent({
            template: '<button>{{text}}</button>'
        });

        var MyComponent = san.defineComponent({
            template:
            '
' +
                '<ui-button on-click="native:clicker(i, $event)" s-ref="btn-{{i}}" text="{{btn.text}}" s-for="btn,i in buttons" />' +
            '
',
            components: {
                'ui-button': Button
            },
            initData: function () {
                return {
                    buttons: [
                        {text: 'a'},
                        {text: 'b'},
                        {text: 'c'}
                    ]
                };
            },
            clicker: function (i, event) {
                var btn = this.ref('btn-' + i);
                expect(event.target || event.srcElement).toBe(btn.el);
                clicked += i;
            }
        });
        var myComponent = new MyComponent();

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);

        var aBtn = wrap.firstChild.children[0];
        var bBtn = wrap.firstChild.children[1];
        var cBtn = wrap.firstChild.children[2];

        function doneSpec() {
            if (clicked === (0 + 1 + 2)) {
                done();
                myComponent.dispose();
                document.body.removeChild(wrap);
                return;
            }
            setTimeout(doneSpec, 500);
        }
        triggerEvent('#' + aBtn.id, 'click');
        triggerEvent('#' + bBtn.id, 'click');
        triggerEvent('#' + cBtn.id, 'click');
        doneSpec();
    });

    it("capture modifier", function (done) {
        if (!document.addEventListener) {
            done();
            return;
        }

        var clicked = 0;

        var MyComponent = san.defineComponent({
            template: '{{name}}, please click here!',

            mainClicker: function () {
                clicked++;
            },

            clicker: function (name, email, event) {
                expect(name).toBe('errorrik');
                expect(email).toBe('errorrik@gmail.com');
                expect(event.target || event.srcElement).toBe(span);

                expect(clicked).toBe(1);
                clicked++;
            }
        });
        var myComponent = new MyComponent();
        myComponent.data.set('name', 'errorrik');
        myComponent.data.set('email', 'errorrik@gmail.com');

        var wrap = document.createElement('div');
        document.body.appendChild(wrap);
        myComponent.attach(wrap);

        var span = wrap.firstChild.firstChild;
        expect(span.getAttribute('title')).toBe('errorrik');

        function doneSpec() {

            if (clicked) {
                done();
                myComponent.dispose();
                document.body.removeChild(wrap);

                return;
            }

            setTimeout(doneSpec, 500);
        }

        triggerEvent('#' + span.id, 'click');

        doneSpec();

    });
});
<|endoftext|>


<commit_before>module.exports =
[
  {
    "_id": "5543129258b9383aab07d0fb",
    "x": 123.123,
    "comment": "new MongoDB.Double(123.123)",
    "btype": 1
  },
  {
    "_id": "5543129258b9383aab07d0fc",
    "x": 456.456,
    "comment": "456.456",
    "btype": 1
  },
  {
    "_id": "5543129258b9383aab07d0fd",
    "x": "abc",
    "comment": "abc",
    "btype": 2
  },
  {
    "_id": "5543129258b9383aab07d0fe",
    "x": {
      "z": 5
    },
    "comment": "{\"z\": 5}",
    "btype": 3
  },
  {
    "_id": "5543129258b9383aab07d0ff",
    "x": [
      9,
      8,
      7
    ],
    "comment": "[9, 8, 7]",
    "btype": 16
  },
  {
    "_id": "5543129258b9383aab07d100",
    "x": [
      {
        "y": 4
      },
      {
        "z": 5
      }
    ],
    "comment": "[{\"y\": 4}, {\"z\": 5}]",
    "btype": 3
  },
  {
    "_id": "5543129258b9383aab07d101",
    "x": "YmluYXJ5",
    "comment": "new MongoDB.Binary(\"binary\")",
    "btype": 5
  },
  {
    "_id": "5543129258b9383aab07d102",
    "x": "5040dc5d40b67c681d000001",
    "comment": "new MongoDB.ObjectID(\"5040dc5d40b67c681d000001\")",
    "btype": 7
  },
  {
    "_id": "5543129258b9383aab07d103",
    "x": false,
    "comment": "false",
    "btype": 8
  },
  {
    "_id": "5543129258b9383aab07d104",
    "x": true,
    "comment": "true",
    "btype": 8
  },
  {
    "_id": "5543129258b9383aab07d105",
    "x": "2012-08-31T12:13:14.156Z",
    "comment": "new Date(\"2012-08-31 12:13:14:156 UTC\")",
    "btype": 9
  },
  {
    "_id": "5543129258b9383aab07d106",
    "x": null,
    "comment": "null",
    "btype": 10
  },
  {
    "_id": "5543129258b9383aab07d107",
    "x": {},
    "comment": "new RegExp(\"abc\")",
    "btype": 11
  },
  {
    "_id": "5543129258b9383aab07d108",
    "x": {},
    "comment": "new RegExp(\"abc\", \"i\")",
    "btype": 11
  },
  {
    "_id": "5543129258b9383aab07d109",
    "x": {
      "$ref": "types",
      "$id": "040dc5d40b67c681d000001",
      "$db": "types"
    },
    "comment": "new MongoDB.DBRef(\"types\", \"5040dc5d40b67c681d000001\", \"types\")",
    "btype": 3
  },
  {
    "_id": "5543129258b9383aab07d10a",
    "x": {
      "scope": {},
      "code": "function () { return 'test'; }"
    },
    "comment": "new MongoDB.Code(\"function () { return ' test'; }\")",
    "btype": 13
  },
  {
    "_id": "5543129258b9383aab07d10b",
    "x": "def15",
    "comment": "new MongoDB.Symbol(\"def15\")",
    "btype": 14
  },
  {
    "_id": "5543129258b9383aab07d10c",
    "x": {
      "scope": {
        "a": 4
      },
      "code": "function () { return a; }"
    },
    "comment": " new MongoDB.Code(\"function () { return a; }\", {\"a\": 4})",
    "btype": 15
  },
  {
    "_id": "5543129258b9383aab07d10d",
    "x": 123456,
    "comment": "123456",
    "btype": 16
  },
  {
    "_id": "5543129258b9383aab07d10e",
    "x": "8589934593",
    "comment": "new MongoDB.Timestamp(1, 2)",
    "btype": 17
  },
  {
    "_id": "5543129258b9383aab07d10f",
    "x": 1286608618,
    "comment": "new MongoDB.Long(\"9876543210\")",
    "btype": 18
  },
  {
    "_id": "5543129258b9383aab07d110",
    "x": {
      "_bsontype": "MinKey"
    },
    "comment": "new MongoDB.MinKey()",
    "btype": 255
  },
  {
    "_id": "5543129258b9383aab07d111",
    "x": {
      "_bsontype": "MaxKey"
    },
    "comment": "new MongoDB.MaxKey()",
    "btype": 127
  },
  {
    "_id": "5543129258b9383aab07d112",
    "x": null,
    "comment": "undefined",
    "btype": 10
  },
  {
    "_id": "5543129258b9383aab07d113",
    "x": null,
    "comment": "Number.NaN",
    "btype": 1
  },
  {
    "_id": "5543129258b9383aab07d114",
    "x": null,
    "comment": "Infinity",
    "btype": 1
  },
  {
    "_id": "5543129258b9383aab07d115",
    "x": null,
    "comment": "Number.POSITIVE_INFINITY",
    "btype": 1
  },
  {
    "_id": "5543129258b9383aab07d116",
    "x": null,
    "comment": "Number.NEGATIVE_INFINITY",
    "btype": 1
  },
  {
    "_id": "5543129258b9383aab07d117",
    "x": 5e-324,
    "comment": "MIN_VALUE",
    "btype": 1
  },
  {
    "_id": "5543129258b9383aab07d118",
    "x": 1.7976931348623157e+308,
    "comment": "MAX_VALUE",
    "btype": 1
  }
]
<commit_msg>fix(test): remove old fixtures<commit_after><|endoftext|>


<commit_before>// # res/script.js
//
// This is the script file that gets copied into the output. It mainly manages the display
// of the folder tree. The idea of this script file is to be minimal and standalone. So
// that means no jQuery.

// Use localStorage to store data about the tree's state: whether or not
// the tree is visible and which directories are expanded. Unless the state
var sidebarVisible = (window.localStorage && window.localStorage.docker_showSidebar) ?
                        window.localStorage.docker_showSidebar == 'yes' :
                        defaultSidebar;

/**
 * ## makeTree
 *
 * Consructs the folder tree view
 *
 * @param {object} treeData Folder structure as in [queueFile](../src/docker.js.html#docker.prototype.queuefile)
 * @param {string} root Path from current file to root (ie `'../../'` etc.)
 * @param {string} filename The current file name
 */
function makeTree(treeData, root, filename){
  var treeNode = document.getElementById('tree');
  var treeHandle = document.getElementById('sidebar-toggle');
  treeHandle.addEventListener('click', toggleTree, false);

  // Build the html and add it to the container.
  treeNode.innerHTML = nodeHtml('', treeData, '', root);

  // Root folder (whole tree) should always be open
  treeNode.childNodes[0].className += ' open';

  // Attach click event handler
  treeNode.addEventListener('click', nodeClicked, false);

  if(sidebarVisible) document.body.className += ' sidebar';

  // Restore scroll position from localStorage if set. And attach scroll handler
  if(window.localStorage && window.localStorage.docker_treeScroll) treeNode.scrollTop = window.localStorage.docker_treeScroll;
  treeNode.onscroll = treeScrolled;

  // Only set a class to allow CSS transitions after the tree state has been painted
  setTimeout(function(){ document.body.className += ' slidey'; }, 100);
}

/**
 * ## treeScrolled
 *
 * Called when the tree is scrolled. Stores the scroll position in localStorage
 * so it can be restored on the next pageview.
 */
function treeScrolled(){
  var tree = document.getElementById('tree');
  if(window.localStorage) window.localStorage.docker_treeScroll = tree.scrollTop;
}

/**
 * ## nodeClicked
 *
 * Called when a directory is clicked. Toggles open state of the directory
 *
 * @param {Event} e The click event
 */
function nodeClicked(e){

  // Find the target
  var t = e.target;

  // If the click target is actually a file (rather than a directory), ignore it
  if(t.tagName.toLowerCase() !== 'div' || t.className === 'children') return;

  // Recurse upwards until we find the actual directory node
  while(t && t.className.substring(0,3) != 'dir') t = t.parentNode;

  // If we're at the root node, then do nothing (we don't allow collapsing of the whole tree)
  if(!t || t.parentNode.id == 'tree') return;

  // Find the path and toggle the state, saving the state in the localStorage variable
  var path = t.getAttribute('rel');
  if(t.className.indexOf('open') !== -1){
    t.className=t.className.replace(/\s*open/g,'');
    if(window.localStorage) window.localStorage.removeItem('docker_openPath:' + path);
  }else{
    t.className += ' open';
    if(window.localStorage) window.localStorage['docker_openPath:' + path] = 'yes';
  }
}

/**
 * ## nodeHtml
 *
 * Constructs the markup for a directory in the tree
 *
 * @param {string} nodename The node name.
 * @param {object} node Node object of same format as whole tree.
 * @param {string} path The path form the base to this node
 * @param {string} root Relative path from current page to root
 */
function nodeHtml(nodename, node, path, root){
  // Firstly, figure out whether or not the directory is expanded from localStorage
  var isOpen = window.localStorage && window.localStorage['docker_openPath:' + path] == 'yes';
  var out = '
';
  out += '
' + nodename + '
';
  out += '
';

  // Loop through all child directories first
  if(node.dirs){
    var dirs = [];
    for(var i in node.dirs){
      if(node.dirs.hasOwnProperty(i)) dirs.push({ name: i, html: nodeHtml(i, node.dirs[i], path + i + '/', root) });
    }
    // Have to store them in an array first and then sort them alphabetically here
    dirs.sort(function(a, b){ return (a.name > b.name) ? 1 : (a.name == b.name) ? 0 : -1; });

    for(var k = 0; k < dirs.length; k += 1) out += dirs[k].html;
  }

  // Now loop through all the child files alphabetically
  if(node.files){
    node.files.sort();
    for(var j = 0; j < node.files.length; j += 1){
      out += '' + node.files[j] + '';
    }
  }

  // Close things off
  out += '

';

  return out;
}

/**
 * ## toggleTree
 *
 * Toggles the visibility of the folder tree
 */
function toggleTree(){
  // Do the actual toggling by modifying the class on the body element. That way we can get some nice CSS transitions going.
  if(sidebarVisible){
    document.body.className = document.body.className.replace(/\s*sidebar/g,'');
    sidebarVisible = false;
  }else{
    document.body.className += ' sidebar';
    sidebarVisible = true;
  }
  if(window.localStorage){
    if(sidebarVisible){
      window.localStorage.docker_showSidebar = 'yes';
    }else{
      window.localStorage.docker_showSidebar = 'no';
    }
  }
}

/**
 * ## wireUpTabs
 *
 * Wires up events on the sidebar tabe
 */
function wireUpTabs(){
  var tabEl = document.getElementById('sidebar_switch');
  var children = tabEl.childNodes;

  // Each tab has a class corresponding of the id of its tab pane
  for(var i = 0, l = children.length; i < l;  i += 1){
    // Ignore text nodes
    if(children[i].nodeType !== 1) continue;
    children[i].addEventListener('click', function(c){
      return function(){ switchTab(c); };
    }(children[i].className));
  }
}

/**
 * ## switchTab
 *
 * Switches tabs in the sidebar
 *
 * @param {string} tab The ID of the tab to switch to
 */
function switchTab(tab){
  var tabEl = document.getElementById('sidebar_switch');
  var children = tabEl.childNodes;

  // Easiest way to go through tabs without any kind of selector is just to look at the tab bar
  for(var i = 0, l = children.length; i < l;  i += 1){
    // Ignore text nodes
    if(children[i].nodeType !== 1) continue;

    // Figure out what tab pane this tab button corresponts to
    var t = children[i].className.replace(/\s.*$/,'');
    if(t === tab){
      // Show the tab pane, select the tab button
      document.getElementById(t).style.display = 'block';
      if(children[i].className.indexOf('selected') === -1) children[i].className += ' selected';
    }else{
      // Hide the tab pane, deselect the tab button
      document.getElementById(t).style.display = 'none';
      children[i].className = children[i].className.replace(/\sselected/,'');
    }
  }

  // Store the last open tab in localStorage
  if(window.localStorage) window.localStorage.docker_sidebarTab = tab;
}

/**
 * ## window.onload
 *
 * When the document is ready, make the sidebar and all that jazz
 */
window.onload = function(){
  makeTree(tree, relativeDir, thisFile);
  wireUpTabs();

  // Switch to the last viewed sidebar tab if stored, otherwise default to folder tree
  if(window.localStorage && window.localStorage.docker_sidebarTab){
    switchTab(window.localStorage.docker_sidebarTab);
  }else{
    switchTab('tree');
  }
};<commit_msg>init sidebar before images are loaded (if supported)<commit_after>// # res/script.js
//
// This is the script file that gets copied into the output. It mainly manages the display
// of the folder tree. The idea of this script file is to be minimal and standalone. So
// that means no jQuery.

// Use localStorage to store data about the tree's state: whether or not
// the tree is visible and which directories are expanded. Unless the state
var sidebarVisible = (window.localStorage && window.localStorage.docker_showSidebar) ?
                        window.localStorage.docker_showSidebar == 'yes' :
                        defaultSidebar;

/**
 * ## makeTree
 *
 * Consructs the folder tree view
 *
 * @param {object} treeData Folder structure as in [queueFile](../src/docker.js.html#docker.prototype.queuefile)
 * @param {string} root Path from current file to root (ie `'../../'` etc.)
 * @param {string} filename The current file name
 */
function makeTree(treeData, root, filename){
  var treeNode = document.getElementById('tree');
  var treeHandle = document.getElementById('sidebar-toggle');
  treeHandle.addEventListener('click', toggleTree, false);

  // Build the html and add it to the container.
  treeNode.innerHTML = nodeHtml('', treeData, '', root);

  // Root folder (whole tree) should always be open
  treeNode.childNodes[0].className += ' open';

  // Attach click event handler
  treeNode.addEventListener('click', nodeClicked, false);

  if(sidebarVisible) document.body.className += ' sidebar';

  // Restore scroll position from localStorage if set. And attach scroll handler
  if(window.localStorage && window.localStorage.docker_treeScroll) treeNode.scrollTop = window.localStorage.docker_treeScroll;
  treeNode.onscroll = treeScrolled;

  // Only set a class to allow CSS transitions after the tree state has been painted
  setTimeout(function(){ document.body.className += ' slidey'; }, 100);
}

/**
 * ## treeScrolled
 *
 * Called when the tree is scrolled. Stores the scroll position in localStorage
 * so it can be restored on the next pageview.
 */
function treeScrolled(){
  var tree = document.getElementById('tree');
  if(window.localStorage) window.localStorage.docker_treeScroll = tree.scrollTop;
}

/**
 * ## nodeClicked
 *
 * Called when a directory is clicked. Toggles open state of the directory
 *
 * @param {Event} e The click event
 */
function nodeClicked(e){

  // Find the target
  var t = e.target;

  // If the click target is actually a file (rather than a directory), ignore it
  if(t.tagName.toLowerCase() !== 'div' || t.className === 'children') return;

  // Recurse upwards until we find the actual directory node
  while(t && t.className.substring(0,3) != 'dir') t = t.parentNode;

  // If we're at the root node, then do nothing (we don't allow collapsing of the whole tree)
  if(!t || t.parentNode.id == 'tree') return;

  // Find the path and toggle the state, saving the state in the localStorage variable
  var path = t.getAttribute('rel');
  if(t.className.indexOf('open') !== -1){
    t.className=t.className.replace(/\s*open/g,'');
    if(window.localStorage) window.localStorage.removeItem('docker_openPath:' + path);
  }else{
    t.className += ' open';
    if(window.localStorage) window.localStorage['docker_openPath:' + path] = 'yes';
  }
}

/**
 * ## nodeHtml
 *
 * Constructs the markup for a directory in the tree
 *
 * @param {string} nodename The node name.
 * @param {object} node Node object of same format as whole tree.
 * @param {string} path The path form the base to this node
 * @param {string} root Relative path from current page to root
 */
function nodeHtml(nodename, node, path, root){
  // Firstly, figure out whether or not the directory is expanded from localStorage
  var isOpen = window.localStorage && window.localStorage['docker_openPath:' + path] == 'yes';
  var out = '
';
  out += '
' + nodename + '
';
  out += '
';

  // Loop through all child directories first
  if(node.dirs){
    var dirs = [];
    for(var i in node.dirs){
      if(node.dirs.hasOwnProperty(i)) dirs.push({ name: i, html: nodeHtml(i, node.dirs[i], path + i + '/', root) });
    }
    // Have to store them in an array first and then sort them alphabetically here
    dirs.sort(function(a, b){ return (a.name > b.name) ? 1 : (a.name == b.name) ? 0 : -1; });

    for(var k = 0; k < dirs.length; k += 1) out += dirs[k].html;
  }

  // Now loop through all the child files alphabetically
  if(node.files){
    node.files.sort();
    for(var j = 0; j < node.files.length; j += 1){
      out += '' + node.files[j] + '';
    }
  }

  // Close things off
  out += '

';

  return out;
}

/**
 * ## toggleTree
 *
 * Toggles the visibility of the folder tree
 */
function toggleTree(){
  // Do the actual toggling by modifying the class on the body element. That way we can get some nice CSS transitions going.
  if(sidebarVisible){
    document.body.className = document.body.className.replace(/\s*sidebar/g,'');
    sidebarVisible = false;
  }else{
    document.body.className += ' sidebar';
    sidebarVisible = true;
  }
  if(window.localStorage){
    if(sidebarVisible){
      window.localStorage.docker_showSidebar = 'yes';
    }else{
      window.localStorage.docker_showSidebar = 'no';
    }
  }
}

/**
 * ## wireUpTabs
 *
 * Wires up events on the sidebar tabe
 */
function wireUpTabs(){
  var tabEl = document.getElementById('sidebar_switch');
  var children = tabEl.childNodes;

  // Each tab has a class corresponding of the id of its tab pane
  for(var i = 0, l = children.length; i < l;  i += 1){
    // Ignore text nodes
    if(children[i].nodeType !== 1) continue;
    children[i].addEventListener('click', function(c){
      return function(){ switchTab(c); };
    }(children[i].className));
  }
}

/**
 * ## switchTab
 *
 * Switches tabs in the sidebar
 *
 * @param {string} tab The ID of the tab to switch to
 */
function switchTab(tab){
  var tabEl = document.getElementById('sidebar_switch');
  var children = tabEl.childNodes;

  // Easiest way to go through tabs without any kind of selector is just to look at the tab bar
  for(var i = 0, l = children.length; i < l;  i += 1){
    // Ignore text nodes
    if(children[i].nodeType !== 1) continue;

    // Figure out what tab pane this tab button corresponts to
    var t = children[i].className.replace(/\s.*$/,'');
    if(t === tab){
      // Show the tab pane, select the tab button
      document.getElementById(t).style.display = 'block';
      if(children[i].className.indexOf('selected') === -1) children[i].className += ' selected';
    }else{
      // Hide the tab pane, deselect the tab button
      document.getElementById(t).style.display = 'none';
      children[i].className = children[i].className.replace(/\sselected/,'');
    }
  }

  // Store the last open tab in localStorage
  if(window.localStorage) window.localStorage.docker_sidebarTab = tab;
}

/**
 * ## window.onload
 *
 * When the document is ready, make the sidebar and all that jazz
 */
(function (init) {
  if (window.addEventListener) {
    window.addEventListener('DOMContentLoaded', init);
  } else { // IE8 and below
    window.onload = init;
  }
}(function(){
  makeTree(tree, relativeDir, thisFile);
  wireUpTabs();

  // Switch to the last viewed sidebar tab if stored, otherwise default to folder tree
  if(window.localStorage && window.localStorage.docker_sidebarTab){
    switchTab(window.localStorage.docker_sidebarTab);
  }else{
    switchTab('tree');
  }
}));

<|endoftext|>


<commit_before>Array.prototype.unique = function() {
	var tmp = {}, out = [];
	for(var i = 0, n = this.length; i < n; ++i) {
		if(!tmp[this[i]]) { tmp[this[i]] = true; out.push(this[i]); }
	}
	return out;
};

function getQueryParams(qs) {
	qs = qs.split('+').join(' ');
	var params = {},
		tokens,
		re = /[?&]?([^=]+)=([^&]*)/g;
	while (tokens = re.exec(qs)) {
		params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
	}
	return params;
}
function merge(o1, o2) {
	for (var k in o2) {
		if (typeof(o2[k]) != "object") {
			o1[k] = o2[k];
		} else {
			merge(o1[k], o2[k]);
		}
	}
}
<commit_msg>fixed minor bugs<commit_after>Array.prototype.unique = function() {
	var tmp = {}, out = [];
	for(var i = 0, n = this.length; i < n; ++i) {
		if(!tmp[this[i]]) { tmp[this[i]] = true; out.push(this[i]); }
	}
	return out;
};

function getQueryParams(qs) {
	qs = qs.split('+').join(' ');
	var params = {},
		tokens,
		re = /[?&]?([^=]+)=([^&]*)/g;
	while (tokens = re.exec(qs)) {
		params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
	}
	return params;
}
function merge(o1, o2) {
	for (var k in o2) {
		if (typeof(o2[k]) == "object" && ! Array.isArray(o2[k])) {
			merge(o1[k], o2[k]);
		} else {
			if (typeof (o1) == "undefined")
				o1 = o2;
			else
				o1[k] = o2[k];
		}
	}
}
<|endoftext|>


<commit_before>/* -*- Mode: js; js-indent-level: 2; -*- */
/*
 * Copyright 2011 Mozilla Foundation and contributors
 * Licensed under the New BSD license. See LICENSE or:
 * http://opensource.org/licenses/BSD-3-Clause
 */
if (typeof define !== 'function') {
    var define = require('amdefine')(module, require);
}
define(function (require, exports, module) {

  var util = require('./util');
  var binarySearch = require('./binary-search');
  var ArraySet = require('./array-set').ArraySet;
  var base64VLQ = require('./base64-vlq');

  /**
   * A SourceMapConsumer instance represents a parsed source map which we can
   * query for information about the original file positions by giving it a file
   * position in the generated source.
   *
   * The only parameter is the raw source map (either as a JSON string, or
   * already parsed to an object). According to the spec, source maps have the
   * following attributes:
   *
   *   - version: Which version of the source map spec this map is following.
   *   - sources: An array of URLs to the original source files.
   *   - names: An array of identifiers which can be referrenced by individual mappings.
   *   - sourceRoot: Optional. The URL root from which all sources are relative.
   *   - sourcesContent: Optional. An array of contents of the original source files.
   *   - mappings: A string of base64 VLQs which contain the actual mappings.
   *   - file: The generated file this source map is associated with.
   *
   * Here is an example source map, taken from the source map spec[0]:
   *
   *     {
   *       version : 3,
   *       file: "out.js",
   *       sourceRoot : "",
   *       sources: ["foo.js", "bar.js"],
   *       names: ["src", "maps", "are", "fun"],
   *       mappings: "AA,AB;;ABCDE;"
   *     }
   *
   * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1#
   */
  function SourceMapConsumer(aSourceMap) {
    var sourceMap = aSourceMap;
    if (typeof aSourceMap === 'string') {
      sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));
    }

    var version = util.getArg(sourceMap, 'version');
    var sources = util.getArg(sourceMap, 'sources');
    var names = util.getArg(sourceMap, 'names');
    var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
    var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
    var mappings = util.getArg(sourceMap, 'mappings');
    var file = util.getArg(sourceMap, 'file');

    if (version !== this._version) {
      throw new Error('Unsupported version: ' + version);
    }

    this._names = ArraySet.fromArray(names);
    this._sources = ArraySet.fromArray(sources);
    this.sourceRoot = sourceRoot;
    this.sourcesContent = sourcesContent;
    this.file = file;

    // `this._generatedMappings` and `this._originalMappings` hold the parsed
    // mapping coordinates from the source map's "mappings" attribute. Each
    // object in the array is of the form
    //
    //     {
    //       generatedLine: The line number in the generated code,
    //       generatedColumn: The column number in the generated code,
    //       source: The path to the original source file that generated this
    //               chunk of code,
    //       originalLine: The line number in the original source that
    //                     corresponds to this chunk of generated code,
    //       originalColumn: The column number in the original source that
    //                       corresponds to this chunk of generated code,
    //       name: The name of the original symbol which generated this chunk of
    //             code.
    //     }
    //
    // All properties except for `generatedLine` and `generatedColumn` can be
    // `null`.
    //
    // `this._generatedMappings` is ordered by the generated positions.
    //
    // `this._originalMappings` is ordered by the original positions.
    this._generatedMappings = [];
    this._originalMappings = [];
    this._parseMappings(mappings, sourceRoot);
  }

  /**
   * The version of the source mapping spec that we are consuming.
   */
  SourceMapConsumer.prototype._version = 3;

  /**
   * The list of original sources.
   */
  Object.defineProperty(SourceMapConsumer.prototype, 'sources', {
    get: function () {
      return this._sources.toArray().map(function (s) {
        return this.sourceRoot ? util.join(this.sourceRoot, s) : s;
      }, this);
    }
  });

  /**
   * Parse the mappings in a string in to a data structure which we can easily
   * query (an ordered list in this._generatedMappings).
   */
  SourceMapConsumer.prototype._parseMappings =
    function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
      var generatedLine = 1;
      var previousGeneratedColumn = 0;
      var previousOriginalLine = 0;
      var previousOriginalColumn = 0;
      var previousSource = 0;
      var previousName = 0;
      var mappingSeparator = /^[,;]/;
      var str = aStr;
      var mapping;
      var temp;

      while (str.length > 0) {
        if (str.charAt(0) === ';') {
          generatedLine++;
          str = str.slice(1);
          previousGeneratedColumn = 0;
        }
        else if (str.charAt(0) === ',') {
          str = str.slice(1);
        }
        else {
          mapping = {};
          mapping.generatedLine = generatedLine;

          // Generated column.
          temp = base64VLQ.decode(str);
          mapping.generatedColumn = previousGeneratedColumn + temp.value;
          previousGeneratedColumn = mapping.generatedColumn;
          str = temp.rest;

          if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
            // Original source.
            temp = base64VLQ.decode(str);
            mapping.source = this._sources.at(previousSource + temp.value);
            previousSource += temp.value;
            str = temp.rest;
            if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
              throw new Error('Found a source, but no line and column');
            }

            // Original line.
            temp = base64VLQ.decode(str);
            mapping.originalLine = previousOriginalLine + temp.value;
            previousOriginalLine = mapping.originalLine;
            // Lines are stored 0-based
            mapping.originalLine += 1;
            str = temp.rest;
            if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
              throw new Error('Found a source and line, but no column');
            }

            // Original column.
            temp = base64VLQ.decode(str);
            mapping.originalColumn = previousOriginalColumn + temp.value;
            previousOriginalColumn = mapping.originalColumn;
            str = temp.rest;

            if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
              // Original name.
              temp = base64VLQ.decode(str);
              mapping.name = this._names.at(previousName + temp.value);
              previousName += temp.value;
              str = temp.rest;
            }
          }

          this._generatedMappings.push(mapping);
          if (typeof mapping.originalLine === 'number') {
            this._originalMappings.push(mapping);
          }
        }
      }

      this._originalMappings.sort(this._compareOriginalPositions);
    };

  /**
   * Comparator between two mappings where the original positions are compared.
   */
  SourceMapConsumer.prototype._compareOriginalPositions =
    function SourceMapConsumer_compareOriginalPositions(mappingA, mappingB) {
      if (mappingA.source > mappingB.source) {
        return 1;
      }
      else if (mappingA.source < mappingB.source) {
        return -1;
      }
      else {
        var cmp = mappingA.originalLine - mappingB.originalLine;
        return cmp === 0
          ? mappingA.originalColumn - mappingB.originalColumn
          : cmp;
      }
    };

  /**
   * Comparator between two mappings where the generated positions are compared.
   */
  SourceMapConsumer.prototype._compareGeneratedPositions =
    function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) {
      var cmp = mappingA.generatedLine - mappingB.generatedLine;
      return cmp === 0
        ? mappingA.generatedColumn - mappingB.generatedColumn
        : cmp;
    };

  /**
   * Find the mapping that best matches the hypothetical "needle" mapping that
   * we are searching for in the given "haystack" of mappings.
   */
  SourceMapConsumer.prototype._findMapping =
    function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName,
                                           aColumnName, aComparator) {
      // To return the position we are searching for, we must first find the
      // mapping for the given position and then return the opposite position it
      // points to. Because the mappings are sorted, we can use binary search to
      // find the best mapping.

      if (aNeedle[aLineName] <= 0) {
        throw new TypeError('Line must be greater than or equal to 1, got '
                            + aNeedle[aLineName]);
      }
      if (aNeedle[aColumnName] < 0) {
        throw new TypeError('Column must be greater than or equal to 0, got '
                            + aNeedle[aColumnName]);
      }

      return binarySearch.search(aNeedle, aMappings, aComparator);
    };

  /**
   * Returns the original source, line, and column information for the generated
   * source's line and column positions provided. The only argument is an object
   * with the following properties:
   *
   *   - line: The line number in the generated source.
   *   - column: The column number in the generated source.
   *
   * and an object is returned with the following properties:
   *
   *   - source: The original source file, or null.
   *   - line: The line number in the original source, or null.
   *   - column: The column number in the original source, or null.
   *   - name: The original identifier, or null.
   */
  SourceMapConsumer.prototype.originalPositionFor =
    function SourceMapConsumer_originalPositionFor(aArgs) {
      var needle = {
        generatedLine: util.getArg(aArgs, 'line'),
        generatedColumn: util.getArg(aArgs, 'column')
      };

      var mapping = this._findMapping(needle,
                                      this._generatedMappings,
                                      "generatedLine",
                                      "generatedColumn",
                                      this._compareGeneratedPositions);

      if (mapping) {
        var source = util.getArg(mapping, 'source', null);
        if (source && this.sourceRoot) {
          source = util.join(this.sourceRoot, source);
        }
        return {
          source: source,
          line: util.getArg(mapping, 'originalLine', null),
          column: util.getArg(mapping, 'originalColumn', null),
          name: util.getArg(mapping, 'name', null)
        };
      }

      return {
        source: null,
        line: null,
        column: null,
        name: null
      };
    };

  /**
   * Returns the original source content. The only argument is the url of the
   * original source file. Returns null if no original source content is
   * availible.
   */
  SourceMapConsumer.prototype.sourceContentFor =
    function SourceMapConsumer_sourceContentFor(aSource) {
      if (!this.sourcesContent) {
        return null;
      }

      if (this.sourceRoot) {
        aSource = util.relative(this.sourceRoot, aSource);
      }

      if (this._sources.has(aSource)) {
        return this.sourcesContent[this._sources.indexOf(aSource)];
      }

      var url;
      if (this.sourceRoot
          && (url = util.urlParse(this.sourceRoot))) {
        // XXX: file:// URIs and absolute paths lead to unexpected behavior for
        // many users. We can help them out when they expect file:// URIs to
        // behave like it would if they were running a local HTTP server. See
        // https://bugzilla.mozilla.org/show_bug.cgi?id=885597.
        var fileUriAbsPath = aSource.replace(/^file:\/\//, "");
        if (url.scheme == "file"
            && this._sources.has(fileUriAbsPath)) {
          return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]
        }

        if ((!url.path || url.path == "/")
            && this._sources.has("/" + aSource)) {
          return this.sourcesContent[this._sources.indexOf("/" + aSource)];
        }
      }

      throw new Error('"' + aSource + '" is not in the SourceMap.');
    };

  /**
   * Returns the generated line and column information for the original source,
   * line, and column positions provided. The only argument is an object with
   * the following properties:
   *
   *   - source: The filename of the original source.
   *   - line: The line number in the original source.
   *   - column: The column number in the original source.
   *
   * and an object is returned with the following properties:
   *
   *   - line: The line number in the generated source, or null.
   *   - column: The column number in the generated source, or null.
   */
  SourceMapConsumer.prototype.generatedPositionFor =
    function SourceMapConsumer_generatedPositionFor(aArgs) {
      var needle = {
        source: util.getArg(aArgs, 'source'),
        originalLine: util.getArg(aArgs, 'line'),
        originalColumn: util.getArg(aArgs, 'column')
      };

      if (this.sourceRoot) {
        needle.source = util.relative(this.sourceRoot, needle.source);
      }

      var mapping = this._findMapping(needle,
                                      this._originalMappings,
                                      "originalLine",
                                      "originalColumn",
                                      this._compareOriginalPositions);

      if (mapping) {
        return {
          line: util.getArg(mapping, 'generatedLine', null),
          column: util.getArg(mapping, 'generatedColumn', null)
        };
      }

      return {
        line: null,
        column: null
      };
    };

  SourceMapConsumer.GENERATED_ORDER = 1;
  SourceMapConsumer.ORIGINAL_ORDER = 2;

  /**
   * Iterate over each mapping between an original source/line/column and a
   * generated line/column in this source map.
   *
   * @param Function aCallback
   *        The function that is called with each mapping.
   * @param Object aContext
   *        Optional. If specified, this object will be the value of `this` every
   *        time that `aCallback` is called.
   * @param aOrder
   *        Either `SourceMapConsumer.GENERATED_ORDER` or
   *        `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to
   *        iterate over the mappings sorted by the generated file's line/column
   *        order or the original's source/line/column order, respectively. Defaults to
   *        `SourceMapConsumer.GENERATED_ORDER`.
   */
  SourceMapConsumer.prototype.eachMapping =
    function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) {
      var context = aContext || null;
      var order = aOrder || SourceMapConsumer.GENERATED_ORDER;

      var mappings;
      switch (order) {
      case SourceMapConsumer.GENERATED_ORDER:
        mappings = this._generatedMappings;
        break;
      case SourceMapConsumer.ORIGINAL_ORDER:
        mappings = this._originalMappings;
        break;
      default:
        throw new Error("Unknown order of iteration.");
      }

      var sourceRoot = this.sourceRoot;
      mappings.map(function (mapping) {
        var source = mapping.source;
        if (source && sourceRoot) {
          source = util.join(sourceRoot, source);
        }
        return {
          source: source,
          generatedLine: mapping.generatedLine,
          generatedColumn: mapping.generatedColumn,
          originalLine: mapping.originalLine,
          originalColumn: mapping.originalColumn,
          name: mapping.name
        };
      }).forEach(aCallback, context);
    };

  exports.SourceMapConsumer = SourceMapConsumer;

});
<commit_msg>Make file parameter optional for SourceMapConsumer<commit_after>/* -*- Mode: js; js-indent-level: 2; -*- */
/*
 * Copyright 2011 Mozilla Foundation and contributors
 * Licensed under the New BSD license. See LICENSE or:
 * http://opensource.org/licenses/BSD-3-Clause
 */
if (typeof define !== 'function') {
    var define = require('amdefine')(module, require);
}
define(function (require, exports, module) {

  var util = require('./util');
  var binarySearch = require('./binary-search');
  var ArraySet = require('./array-set').ArraySet;
  var base64VLQ = require('./base64-vlq');

  /**
   * A SourceMapConsumer instance represents a parsed source map which we can
   * query for information about the original file positions by giving it a file
   * position in the generated source.
   *
   * The only parameter is the raw source map (either as a JSON string, or
   * already parsed to an object). According to the spec, source maps have the
   * following attributes:
   *
   *   - version: Which version of the source map spec this map is following.
   *   - sources: An array of URLs to the original source files.
   *   - names: An array of identifiers which can be referrenced by individual mappings.
   *   - sourceRoot: Optional. The URL root from which all sources are relative.
   *   - sourcesContent: Optional. An array of contents of the original source files.
   *   - mappings: A string of base64 VLQs which contain the actual mappings.
   *   - file: The generated file this source map is associated with.
   *
   * Here is an example source map, taken from the source map spec[0]:
   *
   *     {
   *       version : 3,
   *       file: "out.js",
   *       sourceRoot : "",
   *       sources: ["foo.js", "bar.js"],
   *       names: ["src", "maps", "are", "fun"],
   *       mappings: "AA,AB;;ABCDE;"
   *     }
   *
   * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1#
   */
  function SourceMapConsumer(aSourceMap) {
    var sourceMap = aSourceMap;
    if (typeof aSourceMap === 'string') {
      sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, ''));
    }

    var version = util.getArg(sourceMap, 'version');
    var sources = util.getArg(sourceMap, 'sources');
    var names = util.getArg(sourceMap, 'names');
    var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null);
    var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null);
    var mappings = util.getArg(sourceMap, 'mappings');
    var file = util.getArg(sourceMap, 'file', null);

    if (version !== this._version) {
      throw new Error('Unsupported version: ' + version);
    }

    this._names = ArraySet.fromArray(names);
    this._sources = ArraySet.fromArray(sources);
    this.sourceRoot = sourceRoot;
    this.sourcesContent = sourcesContent;
    this.file = file;

    // `this._generatedMappings` and `this._originalMappings` hold the parsed
    // mapping coordinates from the source map's "mappings" attribute. Each
    // object in the array is of the form
    //
    //     {
    //       generatedLine: The line number in the generated code,
    //       generatedColumn: The column number in the generated code,
    //       source: The path to the original source file that generated this
    //               chunk of code,
    //       originalLine: The line number in the original source that
    //                     corresponds to this chunk of generated code,
    //       originalColumn: The column number in the original source that
    //                       corresponds to this chunk of generated code,
    //       name: The name of the original symbol which generated this chunk of
    //             code.
    //     }
    //
    // All properties except for `generatedLine` and `generatedColumn` can be
    // `null`.
    //
    // `this._generatedMappings` is ordered by the generated positions.
    //
    // `this._originalMappings` is ordered by the original positions.
    this._generatedMappings = [];
    this._originalMappings = [];
    this._parseMappings(mappings, sourceRoot);
  }

  /**
   * The version of the source mapping spec that we are consuming.
   */
  SourceMapConsumer.prototype._version = 3;

  /**
   * The list of original sources.
   */
  Object.defineProperty(SourceMapConsumer.prototype, 'sources', {
    get: function () {
      return this._sources.toArray().map(function (s) {
        return this.sourceRoot ? util.join(this.sourceRoot, s) : s;
      }, this);
    }
  });

  /**
   * Parse the mappings in a string in to a data structure which we can easily
   * query (an ordered list in this._generatedMappings).
   */
  SourceMapConsumer.prototype._parseMappings =
    function SourceMapConsumer_parseMappings(aStr, aSourceRoot) {
      var generatedLine = 1;
      var previousGeneratedColumn = 0;
      var previousOriginalLine = 0;
      var previousOriginalColumn = 0;
      var previousSource = 0;
      var previousName = 0;
      var mappingSeparator = /^[,;]/;
      var str = aStr;
      var mapping;
      var temp;

      while (str.length > 0) {
        if (str.charAt(0) === ';') {
          generatedLine++;
          str = str.slice(1);
          previousGeneratedColumn = 0;
        }
        else if (str.charAt(0) === ',') {
          str = str.slice(1);
        }
        else {
          mapping = {};
          mapping.generatedLine = generatedLine;

          // Generated column.
          temp = base64VLQ.decode(str);
          mapping.generatedColumn = previousGeneratedColumn + temp.value;
          previousGeneratedColumn = mapping.generatedColumn;
          str = temp.rest;

          if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
            // Original source.
            temp = base64VLQ.decode(str);
            mapping.source = this._sources.at(previousSource + temp.value);
            previousSource += temp.value;
            str = temp.rest;
            if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
              throw new Error('Found a source, but no line and column');
            }

            // Original line.
            temp = base64VLQ.decode(str);
            mapping.originalLine = previousOriginalLine + temp.value;
            previousOriginalLine = mapping.originalLine;
            // Lines are stored 0-based
            mapping.originalLine += 1;
            str = temp.rest;
            if (str.length === 0 || mappingSeparator.test(str.charAt(0))) {
              throw new Error('Found a source and line, but no column');
            }

            // Original column.
            temp = base64VLQ.decode(str);
            mapping.originalColumn = previousOriginalColumn + temp.value;
            previousOriginalColumn = mapping.originalColumn;
            str = temp.rest;

            if (str.length > 0 && !mappingSeparator.test(str.charAt(0))) {
              // Original name.
              temp = base64VLQ.decode(str);
              mapping.name = this._names.at(previousName + temp.value);
              previousName += temp.value;
              str = temp.rest;
            }
          }

          this._generatedMappings.push(mapping);
          if (typeof mapping.originalLine === 'number') {
            this._originalMappings.push(mapping);
          }
        }
      }

      this._originalMappings.sort(this._compareOriginalPositions);
    };

  /**
   * Comparator between two mappings where the original positions are compared.
   */
  SourceMapConsumer.prototype._compareOriginalPositions =
    function SourceMapConsumer_compareOriginalPositions(mappingA, mappingB) {
      if (mappingA.source > mappingB.source) {
        return 1;
      }
      else if (mappingA.source < mappingB.source) {
        return -1;
      }
      else {
        var cmp = mappingA.originalLine - mappingB.originalLine;
        return cmp === 0
          ? mappingA.originalColumn - mappingB.originalColumn
          : cmp;
      }
    };

  /**
   * Comparator between two mappings where the generated positions are compared.
   */
  SourceMapConsumer.prototype._compareGeneratedPositions =
    function SourceMapConsumer_compareGeneratedPositions(mappingA, mappingB) {
      var cmp = mappingA.generatedLine - mappingB.generatedLine;
      return cmp === 0
        ? mappingA.generatedColumn - mappingB.generatedColumn
        : cmp;
    };

  /**
   * Find the mapping that best matches the hypothetical "needle" mapping that
   * we are searching for in the given "haystack" of mappings.
   */
  SourceMapConsumer.prototype._findMapping =
    function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName,
                                           aColumnName, aComparator) {
      // To return the position we are searching for, we must first find the
      // mapping for the given position and then return the opposite position it
      // points to. Because the mappings are sorted, we can use binary search to
      // find the best mapping.

      if (aNeedle[aLineName] <= 0) {
        throw new TypeError('Line must be greater than or equal to 1, got '
                            + aNeedle[aLineName]);
      }
      if (aNeedle[aColumnName] < 0) {
        throw new TypeError('Column must be greater than or equal to 0, got '
                            + aNeedle[aColumnName]);
      }

      return binarySearch.search(aNeedle, aMappings, aComparator);
    };

  /**
   * Returns the original source, line, and column information for the generated
   * source's line and column positions provided. The only argument is an object
   * with the following properties:
   *
   *   - line: The line number in the generated source.
   *   - column: The column number in the generated source.
   *
   * and an object is returned with the following properties:
   *
   *   - source: The original source file, or null.
   *   - line: The line number in the original source, or null.
   *   - column: The column number in the original source, or null.
   *   - name: The original identifier, or null.
   */
  SourceMapConsumer.prototype.originalPositionFor =
    function SourceMapConsumer_originalPositionFor(aArgs) {
      var needle = {
        generatedLine: util.getArg(aArgs, 'line'),
        generatedColumn: util.getArg(aArgs, 'column')
      };

      var mapping = this._findMapping(needle,
                                      this._generatedMappings,
                                      "generatedLine",
                                      "generatedColumn",
                                      this._compareGeneratedPositions);

      if (mapping) {
        var source = util.getArg(mapping, 'source', null);
        if (source && this.sourceRoot) {
          source = util.join(this.sourceRoot, source);
        }
        return {
          source: source,
          line: util.getArg(mapping, 'originalLine', null),
          column: util.getArg(mapping, 'originalColumn', null),
          name: util.getArg(mapping, 'name', null)
        };
      }

      return {
        source: null,
        line: null,
        column: null,
        name: null
      };
    };

  /**
   * Returns the original source content. The only argument is the url of the
   * original source file. Returns null if no original source content is
   * availible.
   */
  SourceMapConsumer.prototype.sourceContentFor =
    function SourceMapConsumer_sourceContentFor(aSource) {
      if (!this.sourcesContent) {
        return null;
      }

      if (this.sourceRoot) {
        aSource = util.relative(this.sourceRoot, aSource);
      }

      if (this._sources.has(aSource)) {
        return this.sourcesContent[this._sources.indexOf(aSource)];
      }

      var url;
      if (this.sourceRoot
          && (url = util.urlParse(this.sourceRoot))) {
        // XXX: file:// URIs and absolute paths lead to unexpected behavior for
        // many users. We can help them out when they expect file:// URIs to
        // behave like it would if they were running a local HTTP server. See
        // https://bugzilla.mozilla.org/show_bug.cgi?id=885597.
        var fileUriAbsPath = aSource.replace(/^file:\/\//, "");
        if (url.scheme == "file"
            && this._sources.has(fileUriAbsPath)) {
          return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)]
        }

        if ((!url.path || url.path == "/")
            && this._sources.has("/" + aSource)) {
          return this.sourcesContent[this._sources.indexOf("/" + aSource)];
        }
      }

      throw new Error('"' + aSource + '" is not in the SourceMap.');
    };

  /**
   * Returns the generated line and column information for the original source,
   * line, and column positions provided. The only argument is an object with
   * the following properties:
   *
   *   - source: The filename of the original source.
   *   - line: The line number in the original source.
   *   - column: The column number in the original source.
   *
   * and an object is returned with the following properties:
   *
   *   - line: The line number in the generated source, or null.
   *   - column: The column number in the generated source, or null.
   */
  SourceMapConsumer.prototype.generatedPositionFor =
    function SourceMapConsumer_generatedPositionFor(aArgs) {
      var needle = {
        source: util.getArg(aArgs, 'source'),
        originalLine: util.getArg(aArgs, 'line'),
        originalColumn: util.getArg(aArgs, 'column')
      };

      if (this.sourceRoot) {
        needle.source = util.relative(this.sourceRoot, needle.source);
      }

      var mapping = this._findMapping(needle,
                                      this._originalMappings,
                                      "originalLine",
                                      "originalColumn",
                                      this._compareOriginalPositions);

      if (mapping) {
        return {
          line: util.getArg(mapping, 'generatedLine', null),
          column: util.getArg(mapping, 'generatedColumn', null)
        };
      }

      return {
        line: null,
        column: null
      };
    };

  SourceMapConsumer.GENERATED_ORDER = 1;
  SourceMapConsumer.ORIGINAL_ORDER = 2;

  /**
   * Iterate over each mapping between an original source/line/column and a
   * generated line/column in this source map.
   *
   * @param Function aCallback
   *        The function that is called with each mapping.
   * @param Object aContext
   *        Optional. If specified, this object will be the value of `this` every
   *        time that `aCallback` is called.
   * @param aOrder
   *        Either `SourceMapConsumer.GENERATED_ORDER` or
   *        `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to
   *        iterate over the mappings sorted by the generated file's line/column
   *        order or the original's source/line/column order, respectively. Defaults to
   *        `SourceMapConsumer.GENERATED_ORDER`.
   */
  SourceMapConsumer.prototype.eachMapping =
    function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) {
      var context = aContext || null;
      var order = aOrder || SourceMapConsumer.GENERATED_ORDER;

      var mappings;
      switch (order) {
      case SourceMapConsumer.GENERATED_ORDER:
        mappings = this._generatedMappings;
        break;
      case SourceMapConsumer.ORIGINAL_ORDER:
        mappings = this._originalMappings;
        break;
      default:
        throw new Error("Unknown order of iteration.");
      }

      var sourceRoot = this.sourceRoot;
      mappings.map(function (mapping) {
        var source = mapping.source;
        if (source && sourceRoot) {
          source = util.join(sourceRoot, source);
        }
        return {
          source: source,
          generatedLine: mapping.generatedLine,
          generatedColumn: mapping.generatedColumn,
          originalLine: mapping.originalLine,
          originalColumn: mapping.originalColumn,
          name: mapping.name
        };
      }).forEach(aCallback, context);
    };

  exports.SourceMapConsumer = SourceMapConsumer;

});
<|endoftext|>


<commit_before>import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { TAPi18n } from 'meteor/tap:i18n';
import { $ } from 'meteor/jquery';
import { Session } from 'meteor/session';
import { Tracker } from 'meteor/tracker';

import { sendDelegationVotes } from '/imports/startup/both/modules/Contract';
import { displayModal } from '/imports/ui/modules/modal';
import { Vote, updateState } from '/imports/ui/modules/Vote';
import { contractReady, purgeBallot, candidateBallot } from '/imports/ui/modules/ballot';
import { clearPopups } from '/imports/ui/modules/popup';

import './power.html';
import '../action/action.js';

/**
* @summary converts a percentage value to pixels for current power bar
* @param {number} percentage percentage value to be converted
* @param {string} voteId where to store the vote
* @return {number} pixels
*/
function percentageToPixel(percentage, voteId) {
  return parseInt(((percentage * $(`#voteBar-${voteId}`).width()) / 100), 10);
}

/**
* @summary given absolute value returns relative pixel width
* @param {number} value nominal votes to pixel width
* @param {object} bar the item being rendered
* @param {string} voteId session var containing vote info
* @param {boolean} interactive return value from slider
*/
function getBarWidth(value, voteId, editable, interactive) {
  if (editable) {
    const wallet = Session.get(voteId);
    if (wallet !== undefined) {
      const percentage = parseFloat((value * 100) / wallet.balance, 10).toFixed(2);
      if (value === 0) {
        return '0px';
      } else if (interactive) {
        return `${parseInt(wallet.sliderWidth, 10)}px`;
      }
      return `${percentageToPixel(percentage, voteId)}px`;
    }
  }
  // profile, only logged user
  const wallet = Meteor.user().profile.wallet;
  return `${percentageToPixel(parseFloat((value * 100) / wallet.balance, 10).toFixed(2), voteId)}px`;
}

Template.power.onCreated(function () {
  const wallet = new Vote(this.data.wallet, this.data.targetId, this.data._id);
  Session.set(this.data._id, wallet);
});

Template.power.onRendered(function render() {
  if (!Meteor.user()) {
    return;
  }

  const wallet = new Vote(this.data.wallet, this.data.targetId, this.data._id);
  Session.set(this.data._id, wallet);

  // real time update
  Tracker.autorun(() => {
    if (this.data.sourceId === Meteor.userId()) {
      const newWallet = new Vote(Meteor.user().profile.wallet, this.data.targetId, this.data._id);
      newWallet.resetSlider();
      Session.set(this.data._id, newWallet);
    }
  });

  // redraw power bar if resize
  $(`#voteBar-${this.data._id}`).resize(function () {
    const voteId = this.id.replace('voteBar-', '');
    $(`#voteSlider-${voteId}`).width(getBarWidth(Session.get(voteId).inBallot, voteId, true));
    if (Session.get(voteId).voteType === 'BALANCE') {
      $(`#votePlaced-${voteId}`).width(getBarWidth(parseFloat(Session.get(voteId).placed, 10), voteId, true));
    } else {
      $(`#votePlaced-${voteId}`).width(getBarWidth(parseFloat((Session.get(voteId).placed - Session.get(voteId).inBallot) + Session.get(voteId).delegated, 10), voteId, true));
    }
  });
  if (this.data.editable) {
    // drag event
    $(`#voteHandle-${this.data._id}`).draggable({
      axis: 'x',
      create() {
        const voteId = this.id.replace('voteHandle-', '');
        this.newVote = new Vote(Session.get(voteId), Session.get(voteId).targetId, voteId);
        Session.set(voteId, this.newVote);
      },
      start(event, ui) {
        const voteId = ui.helper.context.id.replace('voteHandle-', '');
        this.newVote = new Vote(Session.get(voteId), Session.get(voteId).targetId, voteId);
        Session.set(voteId, this.newVote);
        if (Session.get(voteId) !== undefined) {
          $(`#voteSlider-${voteId}`).velocity('stop');
        }
        if (Session.get('candidateBallot') === undefined) {
          candidateBallot(Meteor.userId());
        }
        Session.set('dragging', voteId);
      },
      drag(event, ui) {
        const voteId = ui.helper.context.id.replace('voteHandle-', '');
        this.newVote.sliderInput(ui.position.left);
        Session.set(voteId, this.newVote);
        ui.position.left = 0;
      },
      stop(event, ui) {
        // executes the vote
        const voteId = ui.helper.context.id.replace('voteHandle-', '');

        const cancel = () => {
          if (this.newVote.inBallot === 0 && this.newVote.voteType === 'VOTE') {
            Session.set('candidateBallot', undefined);
          }
          Session.set('dragging', false);
          this.newVote.resetSlider();
          Session.set(voteId, this.newVote);
        };

        if ((this.newVote.allocateQuantity === 0 && this.newVote.inBallot === 0) || (this.newVote.voteType === 'VOTE' && purgeBallot(Session.get('candidateBallot')).length === 0)) {
          cancel();
          if (this.newVote.voteType === 'VOTE') {
            Session.set('noSelectedOption', true);
          }
        } else if (contractReady(this.newVote) || this.newVote.voteType === 'DELEGATION') {
          clearPopups();

          // democracy wins
          this.newVote.execute(cancel);
        }
      },
    });
  }
});

Template.power.helpers({
  isDelegation() {
    return (Session.get(this._id).voteType === 'DELEGATION');
  },
  rightToVote() {
    return Session.get('rightToVote');
  },
  confirmationRequired() {
    if (Session.get('contract').kind === 'DELEGATION') {
      const signatures = Session.get('contract').signatures;
      for (const i in signatures) {
        if (signatures[i].role === 'DELEGATE' && signatures[i].status === 'PENDING' && signatures[i]._id === Meteor.user()._id) {
          return true;
        }
      }
    }
    return false;
  },
});

Template.power.events({
  'click #confirmation'() {
    let counterPartyId;
    for (const stamp in Session.get('contract').signatures) {
      if (Session.get('contract').signatures[stamp]._id !== Meteor.user()._id) {
        counterPartyId = Session.get('contract').signatures[stamp]._id;
      }
    }
    displayModal(
      true,
      {
        icon: 'images/modal-delegation.png',
        title: TAPi18n.__('confirm-delegation-votes'),
        message: TAPi18n.__('confirm-delegation-warning').replace('<quantity>', Session.get('contract').wallet.available),
        cancel: TAPi18n.__('not-now'),
        action: TAPi18n.__('confirm-votes'),
        displayProfile: true,
        profileId: counterPartyId,
      },
      function () {
        const settings = {
          condition: {
            transferable: Session.get('contract').transferable,
            portable: Session.get('contract').portable,
            tags: Session.get('contract').tags,
          },
          currency: 'VOTES',
          kind: Session.get('contract').kind,
          contractId: Session.get('contract')._id, // _getContractId(senderId, receiverId, settings.kind),
        };
        sendDelegationVotes(
          Session.get('contract')._id,
          Session.get('contract').signatures[1]._id,
          Session.get('contract').wallet.available,
          settings,
          'CONFIRMED'
        );
      }
    );
  },
  'click #rejection'() {
    let counterPartyId;
    for (const stamp in Session.get('contract').signatures) {
      if (Session.get('contract').signatures[stamp]._id !== Meteor.user()._id) {
        counterPartyId = Session.get('contract').signatures[stamp]._id;
      }
    }
    displayModal(
      true,
      {
        icon: 'images/modal-delegation.png',
        title: TAPi18n.__('reject-delegation-votes'),
        message: TAPi18n.__('reject-delegation-warning').replace('<quantity>', Session.get('contract').wallet.available),
        cancel: TAPi18n.__('not-now'),
        action: TAPi18n.__('reject-votes'),
        displayProfile: true,
        profileId: counterPartyId,
      },
      function () {
        const settings = {
          condition: {
            transferable: Session.get('contract').transferable,
            portable: Session.get('contract').portable,
            tags: Session.get('contract').tags,
          },
          currency: 'VOTES',
          kind: Session.get('contract').kind,
          contractId: Session.get('contract')._id, // _getContractId(senderId, receiverId, settings.kind),
        };
        sendDelegationVotes(
          Session.get('contract')._id,
          Session.get('contract').signatures[0]._id,
          Session.get('contract').wallet.available,
          settings,
          'REJECTED'
        );
      }
    );
  },
});

Template.capital.helpers({
  getVotes(value) {
    let label;
    const inBallot = Session.get(this._id).inBallot;
    if (Session.get(this._id) !== undefined) {
      switch (value) {
        case 'available': {
          if (inBallot === 0) {
            let available;
            if (Session.get(this._id).voteType === 'BALANCE') {
              available = Session.get(this._id).available;
              if (available === 0) { available = TAPi18n.__('none'); }
            } else {
              available = parseInt((Session.get(this._id).available + Session.get(this._id).inBallot) - Session.get(this._id).allocateQuantity, 10);
            }
            if (Session.get(this._id).allocateQuantity > 0 && (available <= 0)) {
              label = `<strong>${TAPi18n.__('none')}</strong> ${TAPi18n.__('available-votes')}`;
            } else {
              label = `<strong>${available}</strong> ${TAPi18n.__('available-votes')}`;
            }
          }
          break;
        }
        case 'inBallot':
          if (Session.get(this._id).voteType === 'DELEGATION') {
            if (inBallot === 0) {
              label = `<strong>${TAPi18n.__('no')}</strong> ${TAPi18n.__('delegated-votes')}`;
            } else {
              label = `<strong>${inBallot}</strong> ${TAPi18n.__('delegated-votes')}`;
            }
          } else if (inBallot === 0) {
            label = `<strong>${TAPi18n.__('none')}</strong> ${TAPi18n.__('on-this-ballot')}`;
          } else if (Session.get(this._id).voteType === 'BALANCE') {
            label = `<strong>${inBallot}</strong> ${TAPi18n.__('available-votes')}`;
          } else {
            label = `<strong>${inBallot}</strong> ${TAPi18n.__('on-this-ballot')}`;
          }
          break;
        case 'allocateQuantity': {
          const quantity = parseInt(Session.get(this._id)[value] - inBallot, 10);
          if (Math.abs(quantity) === inBallot && (quantity < 0)) {
            label = TAPi18n.__('remove-all-votes');
          } else if (Session.get(this._id).voteType === 'DELEGATION') {
            label = `<strong>${Math.abs(inBallot + quantity)}</strong> ${TAPi18n.__('votes-to-delegate')}`;
          } else {
            label = `<strong>${Math.abs(inBallot + quantity)}</strong> ${TAPi18n.__('place-in-ballot')}`;
          }
          break;
        }
        case 'placed':
        default:
          if (Meteor.user().profile.wallet.placed === 0) {
            label = `<strong>${TAPi18n.__('none')}</strong>  ${TAPi18n.__('placed-votes')}`;
          } else if (Session.get(this._id).voteType === 'BALANCE') {
            label = `<strong>${Meteor.user().profile.wallet.placed}</strong>  ${TAPi18n.__('placed')}`;
          } else {
            label = `<strong>${parseInt(Meteor.user().profile.wallet.placed - inBallot, 10)}</strong>  ${TAPi18n.__('placed-votes')}`;
          }
          break;
      }
    }
    return label;
  },
  style(value) {
    const inBallot = Session.get(this._id).inBallot;
    switch (value) {
      case 'available': {
        if (inBallot === 0 && (Session.get('dragging') === false || Session.get('dragging') === undefined || Session.get('dragging') !== this._id)) {
          const available = parseInt((Session.get(this._id).available + Session.get(this._id).inBallot) - Session.get(this._id).allocateQuantity, 10);
          if (Session.get(this._id).allocateQuantity > 0 && (available <= 0)) {
            return 'stage-finish-rejected';
          }
          return 'stage-inballot';
        }
        return 'hide';
      }
      case 'inBallot':
        if (Session.get('dragging') === false || Session.get('dragging') === undefined || Session.get('dragging') !== this._id) {
          if (inBallot === 0) {
            if (Session.get(this._id).voteType === 'DELEGATION') {
              return 'stage-placed';
            }
            return 'hide';
          }
          return 'stage-finish-approved';
        }
        return 'hide';
      case 'allocateQuantity': {
        const quantity = parseInt(Session.get(this._id)[value] - inBallot, 10);
        if (Session.get('dragging') === this._id) {
          if (Math.abs(quantity) === inBallot && (quantity < 0)) {
            return 'stage-finish-rejected';
          }
          return 'stage-live';
        }
        return 'hide';
      }
      case 'placed':
        return 'stage-placed';
      default:
        return 'stage-finish-alternative';
    }
  },
  negativeAllocation() {
    return (Session.get(this._id).inBallot > Session.get(this._id).allocateQuantity);
  },
});

Template.bar.helpers({
  available() {
    return getBarWidth(Session.get(this._id).available, this._id, this.editable, true);
  },
  placed() {
    if (Session.get(this._id).voteType === 'BALANCE') {
      return getBarWidth(Session.get(this._id).placed, this._id, true);
    }
    return getBarWidth(parseFloat((Session.get(this._id).placed - Session.get(this._id).inBallot) + Session.get(this._id).delegated, 10), this._id, this.editable);
  },
  unanimous(value) {
    if (Session.get(this._id)[value] === Session.get(this._id).balance) {
      return 'unanimous';
    }
    return '';
  },
});
<commit_msg>abstracted agreement function on liquid vote component<commit_after>import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
import { TAPi18n } from 'meteor/tap:i18n';
import { $ } from 'meteor/jquery';
import { Session } from 'meteor/session';
import { Tracker } from 'meteor/tracker';

import { sendDelegationVotes } from '/imports/startup/both/modules/Contract';
import { displayModal } from '/imports/ui/modules/modal';
import { Vote } from '/imports/ui/modules/Vote';
import { contractReady, purgeBallot, candidateBallot } from '/imports/ui/modules/ballot';
import { clearPopups } from '/imports/ui/modules/popup';

import './power.html';
import '../action/action.js';

/**
* @summary converts a percentage value to pixels for current power bar
* @param {number} percentage percentage value to be converted
* @param {string} voteId where to store the vote
* @return {number} pixels
*/
function percentageToPixel(percentage, voteId) {
  return parseInt(((percentage * $(`#voteBar-${voteId}`).width()) / 100), 10);
}

/**
* @summary given absolute value returns relative pixel width
* @param {number} value nominal votes to pixel width
* @param {object} bar the item being rendered
* @param {string} voteId session var containing vote info
* @param {boolean} interactive return value from slider
*/
function getBarWidth(value, voteId, editable, interactive) {
  if (editable) {
    const wallet = Session.get(voteId);
    if (wallet !== undefined) {
      const percentage = parseFloat((value * 100) / wallet.balance, 10).toFixed(2);
      if (value === 0) {
        return '0px';
      } else if (interactive) {
        return `${parseInt(wallet.sliderWidth, 10)}px`;
      }
      return `${percentageToPixel(percentage, voteId)}px`;
    }
  }
  // profile, only logged user
  const wallet = Meteor.user().profile.wallet;
  return `${percentageToPixel(parseFloat((value * 100) / wallet.balance, 10).toFixed(2), voteId)}px`;
}

/**
* @summary decides what to display in liquid bar as counterparty value
* @param {string} voteId vote controller for gui
* @param {boolean} editable if its an editable liquid vote
*/
function agreement(voteId, editable) {
  if (Session.get(voteId).voteType === 'BALANCE') {
    return getBarWidth(Session.get(voteId).placed, voteId, true);
  }
  return getBarWidth(parseFloat((Session.get(voteId).placed - Session.get(voteId).inBallot) + Session.get(voteId).delegated, 10), voteId, editable);
}

Template.power.onCreated(function () {
  const wallet = new Vote(this.data.wallet, this.data.targetId, this.data._id);
  Session.set(this.data._id, wallet);
});

Template.power.onRendered(function render() {
  if (!Meteor.user()) {
    return;
  }

  const wallet = new Vote(this.data.wallet, this.data.targetId, this.data._id);
  Session.set(this.data._id, wallet);

  // real time update
  Tracker.autorun(() => {
    if (this.data.sourceId === Meteor.userId()) {
      const newWallet = new Vote(Meteor.user().profile.wallet, this.data.targetId, this.data._id);
      newWallet.resetSlider();
      Session.set(this.data._id, newWallet);
    }
  });

  // redraw power bar if resize
  $(`#voteBar-${this.data._id}`).resize(function () {
    const voteId = this.id.replace('voteBar-', '');
    $(`#voteSlider-${voteId}`).width(getBarWidth(Session.get(voteId).inBallot, voteId, true));
    $(`#votePlaced-${voteId}`).width(agreement(voteId, true));
  });
  if (this.data.editable) {
    // drag event
    $(`#voteHandle-${this.data._id}`).draggable({
      axis: 'x',
      create() {
        const voteId = this.id.replace('voteHandle-', '');
        this.newVote = new Vote(Session.get(voteId), Session.get(voteId).targetId, voteId);
        Session.set(voteId, this.newVote);
      },
      start(event, ui) {
        const voteId = ui.helper.context.id.replace('voteHandle-', '');
        this.newVote = new Vote(Session.get(voteId), Session.get(voteId).targetId, voteId);
        Session.set(voteId, this.newVote);
        if (Session.get(voteId) !== undefined) {
          $(`#voteSlider-${voteId}`).velocity('stop');
        }
        if (Session.get('candidateBallot') === undefined) {
          candidateBallot(Meteor.userId());
        }
        Session.set('dragging', voteId);
      },
      drag(event, ui) {
        const voteId = ui.helper.context.id.replace('voteHandle-', '');
        this.newVote.sliderInput(ui.position.left);
        Session.set(voteId, this.newVote);
        ui.position.left = 0;
      },
      stop(event, ui) {
        // executes the vote
        const voteId = ui.helper.context.id.replace('voteHandle-', '');

        const cancel = () => {
          if (this.newVote.inBallot === 0 && this.newVote.voteType === 'VOTE') {
            Session.set('candidateBallot', undefined);
          }
          Session.set('dragging', false);
          this.newVote.resetSlider();
          Session.set(voteId, this.newVote);
        };

        if ((this.newVote.allocateQuantity === 0 && this.newVote.inBallot === 0) || (this.newVote.voteType === 'VOTE' && purgeBallot(Session.get('candidateBallot')).length === 0)) {
          cancel();
          if (this.newVote.voteType === 'VOTE') {
            Session.set('noSelectedOption', true);
          }
        } else if (contractReady(this.newVote) || this.newVote.voteType === 'DELEGATION') {
          clearPopups();

          // democracy wins
          this.newVote.execute(cancel);
        }
      },
    });
  }
});

Template.power.helpers({
  isDelegation() {
    return (Session.get(this._id).voteType === 'DELEGATION');
  },
  rightToVote() {
    return Session.get('rightToVote');
  },
  confirmationRequired() {
    if (Session.get('contract').kind === 'DELEGATION') {
      const signatures = Session.get('contract').signatures;
      for (const i in signatures) {
        if (signatures[i].role === 'DELEGATE' && signatures[i].status === 'PENDING' && signatures[i]._id === Meteor.user()._id) {
          return true;
        }
      }
    }
    return false;
  },
});

Template.power.events({
  'click #confirmation'() {
    let counterPartyId;
    for (const stamp in Session.get('contract').signatures) {
      if (Session.get('contract').signatures[stamp]._id !== Meteor.user()._id) {
        counterPartyId = Session.get('contract').signatures[stamp]._id;
      }
    }
    displayModal(
      true,
      {
        icon: 'images/modal-delegation.png',
        title: TAPi18n.__('confirm-delegation-votes'),
        message: TAPi18n.__('confirm-delegation-warning').replace('<quantity>', Session.get('contract').wallet.available),
        cancel: TAPi18n.__('not-now'),
        action: TAPi18n.__('confirm-votes'),
        displayProfile: true,
        profileId: counterPartyId,
      },
      function () {
        const settings = {
          condition: {
            transferable: Session.get('contract').transferable,
            portable: Session.get('contract').portable,
            tags: Session.get('contract').tags,
          },
          currency: 'VOTES',
          kind: Session.get('contract').kind,
          contractId: Session.get('contract')._id, // _getContractId(senderId, receiverId, settings.kind),
        };
        sendDelegationVotes(
          Session.get('contract')._id,
          Session.get('contract').signatures[1]._id,
          Session.get('contract').wallet.available,
          settings,
          'CONFIRMED'
        );
      }
    );
  },
  'click #rejection'() {
    let counterPartyId;
    for (const stamp in Session.get('contract').signatures) {
      if (Session.get('contract').signatures[stamp]._id !== Meteor.user()._id) {
        counterPartyId = Session.get('contract').signatures[stamp]._id;
      }
    }
    displayModal(
      true,
      {
        icon: 'images/modal-delegation.png',
        title: TAPi18n.__('reject-delegation-votes'),
        message: TAPi18n.__('reject-delegation-warning').replace('<quantity>', Session.get('contract').wallet.available),
        cancel: TAPi18n.__('not-now'),
        action: TAPi18n.__('reject-votes'),
        displayProfile: true,
        profileId: counterPartyId,
      },
      function () {
        const settings = {
          condition: {
            transferable: Session.get('contract').transferable,
            portable: Session.get('contract').portable,
            tags: Session.get('contract').tags,
          },
          currency: 'VOTES',
          kind: Session.get('contract').kind,
          contractId: Session.get('contract')._id, // _getContractId(senderId, receiverId, settings.kind),
        };
        sendDelegationVotes(
          Session.get('contract')._id,
          Session.get('contract').signatures[0]._id,
          Session.get('contract').wallet.available,
          settings,
          'REJECTED'
        );
      }
    );
  },
});

Template.capital.helpers({
  getVotes(value) {
    let label;
    const inBallot = Session.get(this._id).inBallot;
    if (Session.get(this._id) !== undefined) {
      switch (value) {
        case 'available': {
          if (inBallot === 0) {
            let available;
            if (Session.get(this._id).voteType === 'BALANCE') {
              available = Session.get(this._id).available;
              if (available === 0) { available = TAPi18n.__('none'); }
            } else {
              available = parseInt((Session.get(this._id).available + Session.get(this._id).inBallot) - Session.get(this._id).allocateQuantity, 10);
            }
            if (Session.get(this._id).allocateQuantity > 0 && (available <= 0)) {
              label = `<strong>${TAPi18n.__('none')}</strong> ${TAPi18n.__('available-votes')}`;
            } else {
              label = `<strong>${available}</strong> ${TAPi18n.__('available-votes')}`;
            }
          }
          break;
        }
        case 'inBallot':
          if (Session.get(this._id).voteType === 'DELEGATION') {
            if (inBallot === 0) {
              label = `<strong>${TAPi18n.__('no')}</strong> ${TAPi18n.__('delegated-votes')}`;
            } else {
              label = `<strong>${inBallot}</strong> ${TAPi18n.__('delegated-votes')}`;
            }
          } else if (inBallot === 0) {
            label = `<strong>${TAPi18n.__('none')}</strong> ${TAPi18n.__('on-this-ballot')}`;
          } else if (Session.get(this._id).voteType === 'BALANCE') {
            label = `<strong>${inBallot}</strong> ${TAPi18n.__('available-votes')}`;
          } else {
            label = `<strong>${inBallot}</strong> ${TAPi18n.__('on-this-ballot')}`;
          }
          break;
        case 'allocateQuantity': {
          const quantity = parseInt(Session.get(this._id)[value] - inBallot, 10);
          if (Math.abs(quantity) === inBallot && (quantity < 0)) {
            label = TAPi18n.__('remove-all-votes');
          } else if (Session.get(this._id).voteType === 'DELEGATION') {
            label = `<strong>${Math.abs(inBallot + quantity)}</strong> ${TAPi18n.__('votes-to-delegate')}`;
          } else {
            label = `<strong>${Math.abs(inBallot + quantity)}</strong> ${TAPi18n.__('place-in-ballot')}`;
          }
          break;
        }
        case 'placed':
        default:
          if (Meteor.user().profile.wallet.placed === 0) {
            label = `<strong>${TAPi18n.__('none')}</strong>  ${TAPi18n.__('placed-votes')}`;
          } else if (Session.get(this._id).voteType === 'BALANCE') {
            label = `<strong>${Meteor.user().profile.wallet.placed}</strong>  ${TAPi18n.__('placed')}`;
          } else {
            label = `<strong>${parseInt(Meteor.user().profile.wallet.placed - inBallot, 10)}</strong>  ${TAPi18n.__('placed-votes')}`;
          }
          break;
      }
    }
    return label;
  },
  style(value) {
    const inBallot = Session.get(this._id).inBallot;
    switch (value) {
      case 'available': {
        if (inBallot === 0 && (Session.get('dragging') === false || Session.get('dragging') === undefined || Session.get('dragging') !== this._id)) {
          const available = parseInt((Session.get(this._id).available + Session.get(this._id).inBallot) - Session.get(this._id).allocateQuantity, 10);
          if (Session.get(this._id).allocateQuantity > 0 && (available <= 0)) {
            return 'stage-finish-rejected';
          }
          return 'stage-inballot';
        }
        return 'hide';
      }
      case 'inBallot':
        if (Session.get('dragging') === false || Session.get('dragging') === undefined || Session.get('dragging') !== this._id) {
          if (inBallot === 0) {
            if (Session.get(this._id).voteType === 'DELEGATION') {
              return 'stage-placed';
            }
            return 'hide';
          }
          return 'stage-finish-approved';
        }
        return 'hide';
      case 'allocateQuantity': {
        const quantity = parseInt(Session.get(this._id)[value] - inBallot, 10);
        if (Session.get('dragging') === this._id) {
          if (Math.abs(quantity) === inBallot && (quantity < 0)) {
            return 'stage-finish-rejected';
          }
          return 'stage-live';
        }
        return 'hide';
      }
      case 'placed':
        return 'stage-placed';
      default:
        return 'stage-finish-alternative';
    }
  },
  negativeAllocation() {
    return (Session.get(this._id).inBallot > Session.get(this._id).allocateQuantity);
  },
});

Template.bar.helpers({
  available() {
    return getBarWidth(Session.get(this._id).available, this._id, this.editable, true);
  },
  placed() {
    return agreement(this._id, this.editable);
  },
  unanimous(value) {
    if (Session.get(this._id)[value] === Session.get(this._id).balance) {
      return 'unanimous';
    }
    return '';
  },
});
<|endoftext|>