<commit_before>/*
 * Copyright (c) 2009 Nicholas C. Zakas
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
/*
	mousewheel (deprecated) -> IE6.0, Chrome, Opera, Safari
	DOMMouseScroll (deprecated) -> Firefox 1.0
	wheel (standard) -> Chrome 31, Firefox 17, IE9, Firefox Mobile 17.0

	//No need to use, use DOMMouseScroll
	MozMousePixelScroll -> Firefox 3.5, Firefox Mobile 1.0

	//Events
	WheelEvent -> see wheel
	MouseWheelEvent -> see mousewheel
	MouseScrollEvent -> Firefox 3.5, Firefox Mobile 1.0
*/
(function ($) {

    $.idleTimer = function (firstParam, elem) {
        var opts;
        if ( typeof firstParam === "object" ) {
            opts = firstParam;
            firstParam = null;
        } else if (typeof firstParam === "number") {
            opts = { timeout: firstParam };
            firstParam = null;
        }

        // element to watch
        elem = elem || document;

        // defaults that are to be stored as instance props on the elem
        opts = $.extend({
            idle: false,                // indicates if the user is idle
            timeout: 30000,             // the amount of time (ms) before the user is considered idle
            events: "mousemove keydown wheel DOMMouseScroll mousewheel mousedown" // define active events
        }, opts);

        var jqElem = $(elem),
            obj = jqElem.data("idleTimerObj") || {},

            /* (intentionally not documented)
             * Toggles the idle state and fires an appropriate event.
             * @return {void}
             */
            toggleIdleState = function (e) {
                var obj = $.data(elem, "idleTimerObj") || {};

                // toggle the state
                obj.idle = !obj.idle;

                // store toggle state date time
                obj.olddate = +new Date();

                // create a custom event, with state and name space
                var event = $.Event((obj.idle ? "idle" : "active") + ".idleTimer");

                // trigger event on object with elem and copy of obj
                $(elem).trigger(event, [elem, $.extend({}, obj), e]);
            },
            /**
             * Handle event triggers
             * @return {void}
             * @method event
             * @static
             */
            handleEvent = function (e) {
                var obj = $.data(elem, "idleTimerObj") || {};

		// ignore writting to storage unless related to idleTimer
                if (e.type === "storage" && e.originalEvent.key !== obj.timerSyncId) {
                    return;
                }

                // this is already paused, ignore events for now
                if (obj.remaining != null) { return; }

                /*
                mousemove is kinda buggy, it can be triggered when it should be idle.
                Typically is happening between 115 - 150 milliseconds after idle triggered.
                @psyafter & @kaellis report "always triggered if using modal (jQuery ui, with overlay)"
                @thorst has similar issues on ios7 "after $.scrollTop() on text area"
                */
                if (e.type === "mousemove") {
                    // if coord are same, it didn't move
                    if (e.pageX === obj.pageX && e.pageY === obj.pageY) {
                        return;
                    }
                    // if coord don't exist how could it move
                    if (typeof e.pageX === "undefined" && typeof e.pageY === "undefined") {
                        return;
                    }
                    // under 200 ms is hard to do, and you would have to stop, as continuous activity will bypass this
                    var elapsed = (+new Date()) - obj.olddate;
                    if (elapsed < 200) {
                        return;
                    }
                }

                // clear any existing timeout
                clearTimeout(obj.tId);

                // if the idle timer is enabled, flip
                if (obj.idle) {
                    toggleIdleState(e);
                }

                // store when user was last active
                obj.lastActive = +new Date();

                // update mouse coord
                obj.pageX = e.pageX;
                obj.pageY = e.pageY;

                // sync lastActive
                if (e.type !== "storage" && obj.timerSyncId) {
                  if (typeof(localStorage) !== "undefined") {
                    localStorage.setItem(obj.timerSyncId, obj.lastActive);
                  }
                }

                // set a new timeout
                obj.tId = setTimeout(toggleIdleState, obj.timeout);
            },
            /**
             * Restore initial settings and restart timer
             * @return {void}
             * @method reset
             * @static
             */
            reset = function () {

                var obj = $.data(elem, "idleTimerObj") || {};

                // reset settings
                obj.idle = obj.idleBackup;
                obj.olddate = +new Date();
                obj.lastActive = obj.olddate;
                obj.remaining = null;

                // reset Timers
                clearTimeout(obj.tId);
                if (!obj.idle) {
                    obj.tId = setTimeout(toggleIdleState, obj.timeout);
                }

            },
            /**
             * Store remaining time, stop timer
             * You can pause from an idle OR active state
             * @return {void}
             * @method pause
             * @static
             */
            pause = function () {

                var obj = $.data(elem, "idleTimerObj") || {};

                // this is already paused
                if ( obj.remaining != null ) { return; }

                // define how much is left on the timer
                obj.remaining = obj.timeout - ((+new Date()) - obj.olddate);

                // clear any existing timeout
                clearTimeout(obj.tId);
            },
            /**
             * Start timer with remaining value
             * @return {void}
             * @method resume
             * @static
             */
            resume = function () {

                var obj = $.data(elem, "idleTimerObj") || {};

                // this isn't paused yet
                if ( obj.remaining == null ) { return; }

                // start timer
                if ( !obj.idle ) {
                    obj.tId = setTimeout(toggleIdleState, obj.remaining);
                }

                // clear remaining
                obj.remaining = null;
            },
            /**
             * Stops the idle timer. This removes appropriate event handlers
             * and cancels any pending timeouts.
             * @return {void}
             * @method destroy
             * @static
             */
            destroy = function () {

                var obj = $.data(elem, "idleTimerObj") || {};

                //clear any pending timeouts
                clearTimeout(obj.tId);

                //Remove data
                jqElem.removeData("idleTimerObj");

                //detach the event handlers
                jqElem.off("._idleTimer");
            },
            /**
            * Returns the time until becoming idle
            * @return {number}
            * @method remainingtime
            * @static
            */
            remainingtime = function () {

                var obj = $.data(elem, "idleTimerObj") || {};

                //If idle there is no time remaining
                if ( obj.idle ) { return 0; }

                //If its paused just return that
                if ( obj.remaining != null ) { return obj.remaining; }

                //Determine remaining, if negative idle didn't finish flipping, just return 0
                var remaining = obj.timeout - ((+new Date()) - obj.lastActive);
                if (remaining < 0) { remaining = 0; }

                //If this is paused return that number, else return current remaining
                return remaining;
            };

        // determine which function to call
        if (firstParam === null && typeof obj.idle !== "undefined") {
            // they think they want to init, but it already is, just reset
            reset();
            return jqElem;
        } else if (firstParam === null) {
            // they want to init
        } else if (firstParam !== null && typeof obj.idle === "undefined") {
            // they want to do something, but it isnt init
            // not sure the best way to handle this
            return false;
        } else if (firstParam === "destroy") {
            destroy();
            return jqElem;
        } else if (firstParam === "pause") {
            pause();
            return jqElem;
        } else if (firstParam === "resume") {
            resume();
            return jqElem;
        } else if (firstParam === "reset") {
            reset();
            return jqElem;
        } else if (firstParam === "getRemainingTime") {
            return remainingtime();
        } else if (firstParam === "getElapsedTime") {
            return (+new Date()) - obj.olddate;
        } else if (firstParam === "getLastActiveTime") {
            return obj.lastActive;
        } else if (firstParam === "isIdle") {
            return obj.idle;
        }

	// Test via a getter in the options object to see if the passive property is accessed
	// This isnt working in jquery, though is planned for 4.0
	// https://github.com/jquery/jquery/issues/2871
        /*var supportsPassive = false;
        try {
            var Popts = Object.defineProperty({}, "passive", {
                get: function() {
                    supportsPassive = true;
                }
            });
            window.addEventListener("test", null, Popts);
        } catch (e) {}
	*/

        /* (intentionally not documented)
         * Handles a user event indicating that the user isn't idle. namespaced with internal idleTimer
         * @param {Event} event A DOM2-normalized event object.
         * @return {void}
         */
        jqElem.on($.trim((opts.events + " ").split(" ").join("._idleTimer ")), function (e) {
            handleEvent(e);
        });
        //}, supportsPassive ? { passive: true } : false);

        if (opts.timerSyncId) {
            $(window).bind("storage", handleEvent);
        }

        // Internal Object Properties, This isn't all necessary, but we
        // explicitly define all keys here so we know what we are working with
        obj = $.extend({}, {
            olddate : +new Date(),          // the last time state changed
            lastActive: +new Date(),       // the last time timer was active
            idle : opts.idle,               // current state
            idleBackup : opts.idle,         // backup of idle parameter since it gets modified
            timeout : opts.timeout,         // the interval to change state
            remaining : null,               // how long until state changes
            timerSyncId : opts.timerSyncId, // localStorage key to use for syncing this timer
            tId : null,                     // the idle timer setTimeout
            pageX : null,                   // used to store the mouse coord
            pageY : null
        });

        // set a timeout to toggle state. May wish to omit this in some situations
        if (!obj.idle) {
            obj.tId = setTimeout(toggleIdleState, obj.timeout);
        }

        // store our instance on the object
        $.data(elem, "idleTimerObj", obj);

        return jqElem;
    };

    // This allows binding to element
    $.fn.idleTimer = function (firstParam) {
        if (this[0]) {
            return $.idleTimer(firstParam, this[0]);
        }

        return this;
    };

})(jQuery);
<commit_msg>add support for multiple idle monitors on same element<commit_after>/*
 * Copyright (c) 2009 Nicholas C. Zakas
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sub-license, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
/*
	mousewheel (deprecated) -> IE6.0, Chrome, Opera, Safari
	DOMMouseScroll (deprecated) -> Firefox 1.0
	wheel (standard) -> Chrome 31, Firefox 17, IE9, Firefox Mobile 17.0

	//No need to use, use DOMMouseScroll
	MozMousePixelScroll -> Firefox 3.5, Firefox Mobile 1.0

	//Events
	WheelEvent -> see wheel
	MouseWheelEvent -> see mousewheel
	MouseScrollEvent -> Firefox 3.5, Firefox Mobile 1.0
*/
(function ($) {

    $.idleTimer = function (firstParam, elem, uniqueId) {
        var opts;
        if ( typeof firstParam === "object" ) {
            opts = firstParam;
            firstParam = null;
        } else if (typeof firstParam === "number") {
            opts = { timeout: firstParam };
            firstParam = null;
        }

        // element to watch
        elem = elem || document;

        uniqueId = uniqueId || "";

        // defaults that are to be stored as instance props on the elem
        opts = $.extend({
            idle: false,                // indicates if the user is idle
            timeout: 30000,             // the amount of time (ms) before the user is considered idle
            events: "mousemove keydown wheel DOMMouseScroll mousewheel mousedown" // define active events
        }, opts);

        var jqElem = $(elem),
            obj = jqElem.data("idleTimerObj" + uniqueId) || {},

            /* (intentionally not documented)
             * Toggles the idle state and fires an appropriate event.
             * @return {void}
             */
            toggleIdleState = function (e) {
                var obj = $.data(elem, "idleTimerObj" + uniqueId) || {};

                // toggle the state
                obj.idle = !obj.idle;

                // store toggle state date time
                obj.olddate = +new Date();

                // create a custom event, with state and name space
                var event = $.Event((obj.idle ? "idle" : "active") + ".idleTimer" + uniqueId);

                // trigger event on object with elem and copy of obj
                $(elem).trigger(event, [elem, $.extend({}, obj), e]);
            },
            /**
             * Handle event triggers
             * @return {void}
             * @method event
             * @static
             */
            handleEvent = function (e) {
                var obj = $.data(elem, "idleTimerObj" + uniqueId) || {};

		// ignore writting to storage unless related to idleTimer
                if (e.type === "storage" && e.originalEvent.key !== obj.timerSyncId) {
                    return;
                }

                // this is already paused, ignore events for now
                if (obj.remaining != null) { return; }

                /*
                mousemove is kinda buggy, it can be triggered when it should be idle.
                Typically is happening between 115 - 150 milliseconds after idle triggered.
                @psyafter & @kaellis report "always triggered if using modal (jQuery ui, with overlay)"
                @thorst has similar issues on ios7 "after $.scrollTop() on text area"
                */
                if (e.type === "mousemove") {
                    // if coord are same, it didn't move
                    if (e.pageX === obj.pageX && e.pageY === obj.pageY) {
                        return;
                    }
                    // if coord don't exist how could it move
                    if (typeof e.pageX === "undefined" && typeof e.pageY === "undefined") {
                        return;
                    }
                    // under 200 ms is hard to do, and you would have to stop, as continuous activity will bypass this
                    var elapsed = (+new Date()) - obj.olddate;
                    if (elapsed < 200) {
                        return;
                    }
                }

                // clear any existing timeout
                clearTimeout(obj.tId);

                // if the idle timer is enabled, flip
                if (obj.idle) {
                    toggleIdleState(e);
                }

                // store when user was last active
                obj.lastActive = +new Date();

                // update mouse coord
                obj.pageX = e.pageX;
                obj.pageY = e.pageY;

                // sync lastActive
                if (e.type !== "storage" && obj.timerSyncId) {
                  if (typeof(localStorage) !== "undefined") {
                    localStorage.setItem(obj.timerSyncId, obj.lastActive);
                  }
                }

                // set a new timeout
                obj.tId = setTimeout(toggleIdleState, obj.timeout);
            },
            /**
             * Restore initial settings and restart timer
             * @return {void}
             * @method reset
             * @static
             */
            reset = function () {

                var obj = $.data(elem, "idleTimerObj" + uniqueId) || {};

                // reset settings
                obj.idle = obj.idleBackup;
                obj.olddate = +new Date();
                obj.lastActive = obj.olddate;
                obj.remaining = null;

                // reset Timers
                clearTimeout(obj.tId);
                if (!obj.idle) {
                    obj.tId = setTimeout(toggleIdleState, obj.timeout);
                }

            },
            /**
             * Store remaining time, stop timer
             * You can pause from an idle OR active state
             * @return {void}
             * @method pause
             * @static
             */
            pause = function () {

                var obj = $.data(elem, "idleTimerObj" + uniqueId) || {};

                // this is already paused
                if ( obj.remaining != null ) { return; }

                // define how much is left on the timer
                obj.remaining = obj.timeout - ((+new Date()) - obj.olddate);

                // clear any existing timeout
                clearTimeout(obj.tId);
            },
            /**
             * Start timer with remaining value
             * @return {void}
             * @method resume
             * @static
             */
            resume = function () {

                var obj = $.data(elem, "idleTimerObj" + uniqueId) || {};

                // this isn't paused yet
                if ( obj.remaining == null ) { return; }

                // start timer
                if ( !obj.idle ) {
                    obj.tId = setTimeout(toggleIdleState, obj.remaining);
                }

                // clear remaining
                obj.remaining = null;
            },
            /**
             * Stops the idle timer. This removes appropriate event handlers
             * and cancels any pending timeouts.
             * @return {void}
             * @method destroy
             * @static
             */
            destroy = function () {

                var obj = $.data(elem, "idleTimerObj" + uniqueId) || {};

                //clear any pending timeouts
                clearTimeout(obj.tId);

                //Remove data
                jqElem.removeData("idleTimerObj" + uniqueId);

                //detach the event handlers
                jqElem.off("._idleTimer" + uniqueId);
            },
            /**
            * Returns the time until becoming idle
            * @return {number}
            * @method remainingtime
            * @static
            */
            remainingtime = function () {

                var obj = $.data(elem, "idleTimerObj" + uniqueId) || {};

                //If idle there is no time remaining
                if ( obj.idle ) { return 0; }

                //If its paused just return that
                if ( obj.remaining != null ) { return obj.remaining; }

                //Determine remaining, if negative idle didn't finish flipping, just return 0
                var remaining = obj.timeout - ((+new Date()) - obj.lastActive);
                if (remaining < 0) { remaining = 0; }

                //If this is paused return that number, else return current remaining
                return remaining;
            };

        // determine which function to call
        if (firstParam === null && typeof obj.idle !== "undefined") {
            // they think they want to init, but it already is, just reset
            reset();
            return jqElem;
        } else if (firstParam === null) {
            // they want to init
        } else if (firstParam !== null && typeof obj.idle === "undefined") {
            // they want to do something, but it isnt init
            // not sure the best way to handle this
            return false;
        } else if (firstParam === "destroy") {
            destroy();
            return jqElem;
        } else if (firstParam === "pause") {
            pause();
            return jqElem;
        } else if (firstParam === "resume") {
            resume();
            return jqElem;
        } else if (firstParam === "reset") {
            reset();
            return jqElem;
        } else if (firstParam === "getRemainingTime") {
            return remainingtime();
        } else if (firstParam === "getElapsedTime") {
            return (+new Date()) - obj.olddate;
        } else if (firstParam === "getLastActiveTime") {
            return obj.lastActive;
        } else if (firstParam === "isIdle") {
            return obj.idle;
        }

	// Test via a getter in the options object to see if the passive property is accessed
	// This isnt working in jquery, though is planned for 4.0
	// https://github.com/jquery/jquery/issues/2871
        /*var supportsPassive = false;
        try {
            var Popts = Object.defineProperty({}, "passive", {
                get: function() {
                    supportsPassive = true;
                }
            });
            window.addEventListener("test", null, Popts);
        } catch (e) {}
	*/

        /* (intentionally not documented)
         * Handles a user event indicating that the user isn't idle. namespaced with internal idleTimer
         * @param {Event} event A DOM2-normalized event object.
         * @return {void}
         */
        jqElem.on($.trim((opts.events + " ").split(" ").join("._idleTimer" + uniqueId + " ")), function (e) {
            handleEvent(e);
        });
        //}, supportsPassive ? { passive: true } : false);

        if (opts.timerSyncId) {
            $(window).bind("storage", handleEvent);
        }

        // Internal Object Properties, This isn't all necessary, but we
        // explicitly define all keys here so we know what we are working with
        obj = $.extend({}, {
            olddate : +new Date(),          // the last time state changed
            lastActive: +new Date(),       // the last time timer was active
            idle : opts.idle,               // current state
            idleBackup : opts.idle,         // backup of idle parameter since it gets modified
            timeout : opts.timeout,         // the interval to change state
            remaining : null,               // how long until state changes
            timerSyncId : opts.timerSyncId, // localStorage key to use for syncing this timer
            tId : null,                     // the idle timer setTimeout
            pageX : null,                   // used to store the mouse coord
            pageY : null
        });

        // set a timeout to toggle state. May wish to omit this in some situations
        if (!obj.idle) {
            obj.tId = setTimeout(toggleIdleState, obj.timeout);
        }

        // store our instance on the object
        $.data(elem, "idleTimerObj" + uniqueId, obj);

        return jqElem;
    };

    // This allows binding to element
    $.fn.idleTimer = function (firstParam, uniqueId) {
        if (this[0]) {
            return $.idleTimer(firstParam, this[0], uniqueId);
        }

        return this;
    };

})(jQuery);
<|endoftext|>


<commit_before>// initializes the application
// and links it with the GUI

'use strict'

// require keybindings
const keybindings = require('../src/keybindings.js')

// require core modules
// const nodeInfo = require('./src/core/nodeInfo.js')
const printTotalNodes = require('../src/core/printTotalNodes.js')
const hoverNodeInfo = require('../src/core/hoverNodeInfo.js')
const editMenu = require('../src/core/editMenu.js')

const buttons = require('./buttons.js')

// require helper functions
const rmElement = require('../src/helpers/rmElement.js')

module.exports = function initialize (cy, phase) {
  // initial label render
  cy.nodes().addClass('label-nodes')
  cy.edges().addClass('label-edges')

  // global variables, used in cy.on
  let selectedNode = {}
  let oldSelectedNode = {}
  let selectedEdge = {}
  let srcNode = {}
  let trgNode = {}
  // initialize export variables to prevent undefined errors
  selectedNode.out = {}
  oldSelectedNode.out = {}
  selectedEdge.out = {}
  srcNode.out = {}
  trgNode.out = {}

  // counter variable to create unique sequential node ids in addComponents.js
  const initialCount = cy.nodes().length

  // cy.on does stuff when intrecting with the graph
  // actions when tapping on node
  cy.on('tap', 'node', selection => {
    // removes previous selections
    cy.elements().removeClass('selection')
    cy.elements().removeClass('attention')
    cy.elements().removeClass('protect')
    cy.nodes().removeClass('old-selection')

    oldSelectedNode.out = selectedNode.out
    selectedNode.out = selection.target[0]
    selectedNode.out.addClass('selection')

    // adds the old-selection class to the previous selection
    if (Object.keys(oldSelectedNode.out).length !== 0) {
      oldSelectedNode.out.addClass('old-selection')
    }

    srcNode.out = trgNode.out // second selection
    trgNode.out = selectedNode.out.data()

    selectedEdge.out = {} // clear token

    printTotalNodes(cy) // initial node count

    rmElement('info-nodes-id', 'form-id') // remove the edit node element
    rmElement('window-id', 'nodeMenu-id') // remove node menu element
    rmElement('window-id', 'stageMenu-id') // remove stage menu element
  })
  // actions when tapping on an edge
  cy.on('tap', 'edge', selection => {
    // removes previous selections
    cy.elements().removeClass('selection')
    cy.elements().removeClass('attention')
    cy.elements().removeClass('protect')
    cy.nodes().removeClass('old-selection')
    selection.target.addClass('selection')

    selectedNode.out = {} // clear token
    oldSelectedNode.out = {} // clear token

    selectedEdge.out = selection.target[0]

    printTotalNodes(cy) // initial node count

    rmElement('info-nodes-id', 'form-id') // remove the edit node element
    rmElement('window-id', 'nodeMenu-id') // remove node menu element
    rmElement('window-id', 'stageMenu-id') // remove stage menu element
  })
  // actions when tapping the stage
  cy.on('tap', selection => {
    // checks if only the stage was clicked
    if (selection.target === cy) {
      // removes previous selections
      cy.elements().removeClass('faded')
      cy.elements().removeClass('selection')
      cy.elements().removeClass('attention')
      cy.elements().removeClass('protect')
      cy.nodes().removeClass('old-selection')

      // clear tokens
      selectedNode.out = {}
      oldSelectedNode.out = {}
      selectedEdge.out = {}

      printTotalNodes(cy) // initial node count

      rmElement('info-nodes-id', 'form-id') // remove the edit node element
      rmElement('window-id', 'nodeMenu-id') // remove node menu element
      rmElement('window-id', 'stageMenu-id') // remove stage menu element
    }
  })
  // right clicking
  cy.on('cxttap', 'node', selection => {
    selectedNode.out = selection.target[0]
    editMenu.nodeMenu(cy, selection, selectedNode.out)

    // clear tokens
    selectedNode.out = {}
    oldSelectedNode.out = {}
    selectedEdge.out = {}

    rmElement('window-id', 'stageMenu-id') // remove stage menu element
  })
  // right clicking on stage
  cy.on('cxttap', selection => {
    // checks if only the stage was clicked
    if (selection.target === cy) {
      // removes the stage menu if it exists
      rmElement('window-id', 'stageMenu-id')
      editMenu.stageMenu(cy, selection)
    }
  })
  // actions when hovering over a node
  cy.on('mouseover', 'node', event => {
    hoverNodeInfo(event.target[0]) // global module
  })
  // actions when hovering out of a node
  cy.on('mouseout', 'node', event => {
    // hides the hover container
    document.getElementById('container-node-id').style.display = 'none'
  })

  // load the buttons for each phase

  // declaration of global buttons
  buttons(cy, selectedNode, selectedEdge, srcNode, trgNode, initialCount, phase) // delete elements

  printTotalNodes(cy) // initial node count

  // enable keybindings
  keybindings(cy, selectedNode, selectedEdge, srcNode, trgNode, phase)
}
<commit_msg>:fire: remove unused comments<commit_after>// initializes the application
// and links it with the GUI

'use strict'

// require keybindings
const keybindings = require('../src/keybindings.js')

// require core modules
// const nodeInfo = require('./src/core/nodeInfo.js')
const printTotalNodes = require('../src/core/printTotalNodes.js')
const hoverNodeInfo = require('../src/core/hoverNodeInfo.js')
const editMenu = require('../src/core/editMenu.js')

const buttons = require('./buttons.js')

// require helper functions
const rmElement = require('../src/helpers/rmElement.js')

module.exports = function initialize (cy, phase) {
  // initial label render
  cy.nodes().addClass('label-nodes')
  cy.edges().addClass('label-edges')

  // global variables, used in cy.on
  let selectedNode = {}
  let oldSelectedNode = {}
  let selectedEdge = {}
  let srcNode = {}
  let trgNode = {}
  // initialize export variables to prevent undefined errors
  selectedNode.out = {}
  oldSelectedNode.out = {}
  selectedEdge.out = {}
  srcNode.out = {}
  trgNode.out = {}

  // counter variable to create unique sequential node ids in addComponents.js
  const initialCount = cy.nodes().length

  // cy.on does stuff when intrecting with the graph
  // actions when tapping on node
  cy.on('tap', 'node', selection => {
    // removes previous selections
    cy.elements().removeClass('selection')
    cy.elements().removeClass('attention')
    cy.elements().removeClass('protect')
    cy.nodes().removeClass('old-selection')

    oldSelectedNode.out = selectedNode.out
    selectedNode.out = selection.target[0]
    selectedNode.out.addClass('selection')

    // adds the old-selection class to the previous selection
    if (Object.keys(oldSelectedNode.out).length !== 0) {
      oldSelectedNode.out.addClass('old-selection')
    }

    srcNode.out = trgNode.out // second selection
    trgNode.out = selectedNode.out.data()

    selectedEdge.out = {} // clear token

    printTotalNodes(cy) // initial node count

    rmElement('info-nodes-id', 'form-id') // remove the edit node element
    rmElement('window-id', 'nodeMenu-id') // remove node menu element
    rmElement('window-id', 'stageMenu-id') // remove stage menu element
  })
  // actions when tapping on an edge
  cy.on('tap', 'edge', selection => {
    // removes previous selections
    cy.elements().removeClass('selection')
    cy.elements().removeClass('attention')
    cy.elements().removeClass('protect')
    cy.nodes().removeClass('old-selection')
    selection.target.addClass('selection')

    selectedNode.out = {} // clear token
    oldSelectedNode.out = {} // clear token

    selectedEdge.out = selection.target[0]

    printTotalNodes(cy) // initial node count

    rmElement('info-nodes-id', 'form-id') // remove the edit node element
    rmElement('window-id', 'nodeMenu-id') // remove node menu element
    rmElement('window-id', 'stageMenu-id') // remove stage menu element
  })
  // actions when tapping the stage
  cy.on('tap', selection => {
    // checks if only the stage was clicked
    if (selection.target === cy) {
      // removes previous selections
      cy.elements().removeClass('faded')
      cy.elements().removeClass('selection')
      cy.elements().removeClass('attention')
      cy.elements().removeClass('protect')
      cy.nodes().removeClass('old-selection')

      // clear tokens
      selectedNode.out = {}
      oldSelectedNode.out = {}
      selectedEdge.out = {}

      printTotalNodes(cy) // initial node count

      rmElement('info-nodes-id', 'form-id') // remove the edit node element
      rmElement('window-id', 'nodeMenu-id') // remove node menu element
      rmElement('window-id', 'stageMenu-id') // remove stage menu element
    }
  })
  // right clicking
  cy.on('cxttap', 'node', selection => {
    selectedNode.out = selection.target[0]
    editMenu.nodeMenu(cy, selection, selectedNode.out)

    // clear tokens
    selectedNode.out = {}
    oldSelectedNode.out = {}
    selectedEdge.out = {}

    rmElement('window-id', 'stageMenu-id') // remove stage menu element
  })
  // right clicking on stage
  cy.on('cxttap', selection => {
    // checks if only the stage was clicked
    if (selection.target === cy) {
      // removes the stage menu if it exists
      rmElement('window-id', 'stageMenu-id')
      editMenu.stageMenu(cy, selection)
    }
  })
  // actions when hovering over a node
  cy.on('mouseover', 'node', event => {
    hoverNodeInfo(event.target[0]) // global module
  })
  // actions when hovering out of a node
  cy.on('mouseout', 'node', event => {
    // hides the hover container
    document.getElementById('container-node-id').style.display = 'none'
  })

  // load the buttons for each phase

  // declaration of global buttons
  buttons(cy, selectedNode, selectedEdge, srcNode, trgNode, initialCount, phase)

  printTotalNodes(cy) // initial node count

  // enable keybindings
  keybindings(cy, selectedNode, selectedEdge, srcNode, trgNode, phase)
}
<|endoftext|>


<commit_before>Group = Item.extend({
	beans: true,
	initialize: function(items) {
		this.base();
		this.children = [];
		if (items) {
			for (var i = 0, l = items.length; i < l; i++) {
				this.appendTop(items[i]);
			}
		}
		this.clipped = false;
	},

	draw: function(ctx) {
		if (!this.visible)
			return;
		// If the group has an opacity of less then 1, draw its children on a
		// temporary canvas, and then draw that canvas onto ctx afterwards
		// with globalAlpha set.
		if (this.opacity < 1) {
			var originalCtx = ctx;
			var size = this.document.size;
			var tempCanvas = CanvasProvider.getCanvas(size.width, size.height);
			ctx = tempCanvas.getContext('2d');
		}
		for (var i = 0, l = this.children.length; i < l; i++) {
			this.children[i].draw(ctx);
			if (this.clipped & i == 0)
				ctx.clip();
		}
		if (tempCanvas) {
			originalCtx.globalAlpha = this.opacity;
			originalCtx.drawImage(tempCanvas, 0, 0);
			// Return the canvas, so it can be reused
			CanvasProvider.returnCanvas(tempCanvas);
		}
	},

	getBounds: function() {
		if (this.children.length) {
			var rect = this.children[0].bounds;
			var x1 = rect.x;
			var y1 = rect.y;
			var x2 = rect.x + rect.width;
			var y2 = rect.y + rect.height;
			for (var i = 1, l = this.children.length; i < l; i++) {
				var rect2 = this.children[i].bounds;
				x1 = Math.min(rect2.x, x1);
				y1 = Math.min(rect2.y, y1);
				x2 = Math.max(rect2.x + rect2.width, x1 + x2 - x1);
				y2 = Math.max(rect2.y + rect2.height, y1 + y2 - y1);
			}
		}
		return new Rectangle(x1, y1, x2 - x1, y2 - y1);
	},

	/**
	 * Specifies whether the group item is to be clipped.
	 * When setting to true, the first child in the group is automatically
	 * defined as the clipping mask.
	 *
	 * Sample code:
	 *
	 * var group = new Group();
	 * group.appendChild(path);
	 * group.clipped = true;
	 *
	 * @return {@true if the group item is to be clipped}
	 */
	isClipped: function() {
		return this._clipped;
	},

	setClipped: function(clipped) {
		this._clipped = clipped;
		var child = this.firstChild;
		if (child)
			child.setClipMask(clipped);
	}
});
<commit_msg>Clean up Group#draw and save/restore context state when drawing group with opacity.<commit_after>Group = Item.extend({
	beans: true,
	initialize: function(items) {
		this.base();
		this.children = [];
		if (items) {
			for (var i = 0, l = items.length; i < l; i++) {
				this.appendTop(items[i]);
			}
		}
		this.clipped = false;
	},

	draw: function(ctx) {
		if (!this.visible)
			return;
		// If the group has an opacity of less then 1, draw its children on a
		// temporary canvas, and then draw that canvas onto ctx afterwards
		// with globalAlpha set.
		var tempCanvas, originalCtx;
		if (this.opacity < 1) {
			var originalCtx = ctx;
			tempCanvas = CanvasProvider.getCanvas(this.document.size);
			ctx = tempCanvas.getContext('2d');
		}
		for (var i = 0, l = this.children.length; i < l; i++) {
			this.children[i].draw(ctx);
			if (this.clipped & i == 0)
				ctx.clip();
		}
		if (tempCanvas) {
			originalCtx.save();
			originalCtx.globalAlpha = this.opacity;
			originalCtx.drawImage(tempCanvas, 0, 0);
			originalCtx.restore();
			// Return the canvas, so it can be reused
			CanvasProvider.returnCanvas(tempCanvas);
		}
	},

	getBounds: function() {
		if (this.children.length) {
			var rect = this.children[0].bounds;
			var x1 = rect.x;
			var y1 = rect.y;
			var x2 = rect.x + rect.width;
			var y2 = rect.y + rect.height;
			for (var i = 1, l = this.children.length; i < l; i++) {
				var rect2 = this.children[i].bounds;
				x1 = Math.min(rect2.x, x1);
				y1 = Math.min(rect2.y, y1);
				x2 = Math.max(rect2.x + rect2.width, x1 + x2 - x1);
				y2 = Math.max(rect2.y + rect2.height, y1 + y2 - y1);
			}
		}
		return new Rectangle(x1, y1, x2 - x1, y2 - y1);
	},

	/**
	 * Specifies whether the group item is to be clipped.
	 * When setting to true, the first child in the group is automatically
	 * defined as the clipping mask.
	 *
	 * Sample code:
	 *
	 * var group = new Group();
	 * group.appendChild(path);
	 * group.clipped = true;
	 *
	 * @return {@true if the group item is to be clipped}
	 */
	isClipped: function() {
		return this._clipped;
	},

	setClipped: function(clipped) {
		this._clipped = clipped;
		var child = this.firstChild;
		if (child)
			child.setClipMask(clipped);
	}
});
<|endoftext|>


<commit_before>/*
 * This file is part of the Arnapou jqCron package.
 *
 * (c) Arnaud Buathier <arnaud@arnapou.net>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
var jqCronDefaultSettings={texts:{fr:{empty:"-tout-",name_minute:"minute",name_hour:"heure",name_day:"jour",name_week:"semaine",name_month:"mois",name_year:"année",text_period:"Chaque ",text_mins:"à  minutes",text_time:"à :",text_dow:"le ",text_month:"de ",text_dom:"le ",error1:"La balise %s n'est pas supportée !",error2:"Mauvais nombre d'éléments",error3:"La propriété jquery_element doit être définie dans les paramètres jqCron",error4:"Expression non reconnue",weekdays:["lundi","mardi","mercredi","jeudi","vendredi","samedi","dimanche"],months:["janvier","février","mars","avril","mai","juin","juillet","août","septembre","octobre","novembre","décembre"]},en:{empty:"-all-",name_minute:"minute",name_hour:"hour",name_day:"day",name_week:"week",name_month:"month",name_year:"year",text_period:"Every ",text_mins:"at  minutes past the hour",text_time:"at :",text_dow:"on ",text_month:"of ",text_dom:"on the ",error1:"The tag %s is not supported !",error2:"Bad number of elements",error3:"The jquery_element should be set into jqCron settings",error4:"Unrecognized expression",weekdays:["monday","tuesday","wednesday","thursday","friday","saturday","sunday"],months:["january","february","march","april","may","june","july","august","september","october","november","december"]},de:{empty:"-Alle-",name_minute:"Minute",name_hour:"Stunde",name_day:"Tag",name_week:"Woche",name_month:"Monat",name_year:"Jahr",text_period:"Jede ",text_mins:"um  minuten nach der Stunde",text_time:"um :",text_dow:"am ",text_month:"im ",text_dom:"am ",error1:"Der Tag %s wird nicht unterstützt!",error2:"Ungültige Anzahl an Werten!",error3:"Das jquery_element sollte in den jqCron-Einstellungen gesetzt werden!",error4:"Ungültiger Ausdruck",weekdays:["Montag","Dienstag","Mittwoch","Donnerstag","Freitag","Samstag","Sonntag"],months:["Jänner","Februar","März","April","Mai","Juni","Juli","August","September","Oktober","November","Dezember"]}},monthdays:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31],hours:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23],minutes:[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59],lang:"fr",enabled_minute:false,enabled_hour:true,enabled_day:true,enabled_week:true,enabled_month:true,enabled_year:true,multiple_dom:false,multiple_month:false,multiple_mins:false,multiple_dow:false,multiple_time_hours:false,multiple_time_minutes:false,numeric_zero_pad:false,default_period:"day",default_value:"",no_reset_button:true,disabled:false,bind_to:null,bind_method:{set:function(e,t){e.is(":input")?e.val(t):e.data("jqCronValue",t)},get:function(e){return e.is(":input")?e.val():e.data("jqCronValue")}}};(function(e){var t=function(n,r){for(var i in r){if(e.isPlainObject(r[i])){n[i]=t(n[i]&&e.isPlainObject(n[i])?n[i]:{},r[i])}else if(e.isArray(r[i])){n[i]=r[i].slice(0)}else if(r[i]!==undefined){n[i]=r[i]}}return n};this.jqCronMergeSettings=function(e){return t(t({},jqCronDefaultSettings),e||{})}}).call(this,jQuery);(function(e){e.fn.jqCronGetInstance=function(){return this.data("jqCron")}}).call(this,jQuery);(function(e){e.fn.jqCron=function(t){var n=t;return this.each(function(){var t,r;var i=e(this);var s=jqCronMergeSettings(n);if(!s.jquery_container){if(i.is(":container")){s.jquery_element=i.uniqueId("jqCron")}else if(i.is(":autoclose")){if(i.next(".jqCron").length==1){i.next(".jqCron").remove()}s.jquery_element=e('').uniqueId("jqCron").insertAfter(i)}else{console&&console.error(s.texts[s.lang].error1.replace("%s",this.tagName));return}}if(i.is(":input")){s.bind_to=s.bind_to||i}if(s.bind_to){if(s.bind_to.is(":input")){s.bind_to.blur(function(){var e=s.bind_method.get(s.bind_to);i.jqCronGetInstance().setCron(e)})}r=s.bind_method.get(s.bind_to);t=new jqCron(s);t.setCron(r)}else{t=new jqCron(s)}e(this).data("jqCron",t)})}}).call(this,jQuery);(function(e){function n(n){function x(e,s,u){var a=new jqCronSelector(i,e,s,u);a.$.bind("selector:open",function(){for(var e=t.length;e--;){if(t[e]!=i){t[e].closeSelectors()}else{for(var n=v.length;n--;){if(v[n]!=a){v[n].close()}}}}});a.$.bind("selector:change",function(){var e=false;if(!r)return;if(n.multiple_mins==n.multiple_time_minutes){if(a==g){e=b.setValue(g.getValue())}else if(a==b){e=g.setValue(b.getValue())}}e||o.trigger("cron:change",i.getCron())});v.push(a);return a}var r=false;var i=this;var s=this;var o=e('');var u=e('');var a=e('');var f=e('');var l=e('');var c=e('');var h=e('');var p=e('');var d=e('✘');var v=[];var m,g,y,b,w,E,S;this.disable=function(){o.addClass("disable");n.disable=true;i.closeSelectors()};this.isDisabled=function(){return n.disable==true};this.enable=function(){o.removeClass("disable");n.disable=false};this.getCron=function(){var e=m.getValue();var t=["*","*","*","*","*"];if(e=="hour"){t[0]=g.getCronValue()}if(e=="day"||e=="week"||e=="month"||e=="year"){t[0]=b.getCronValue();t[1]=y.getCronValue()}if(e=="month"||e=="year"){t[2]=E.getCronValue()}if(e=="year"){t[3]=S.getCronValue()}if(e=="week"){t[4]=w.getCronValue()}return t.join(" ")};this.setCron=function(e){if(!e)return;try{e=e.replace(/\s+/g," ").replace(/^ +/,"").replace(/ +$/,"");var t=e.replace(/[^\* ]/g,"-").replace(/-+/g,"-").replace(/ +/g,"");var n=e.split(" ");if(n.length!=5)i.error(i.getText("error2"));if(t=="*****"){m.setValue("minute")}else if(t=="-****"){m.setValue("hour");g.setCronValue(n[0]);b.setCronValue(n[0])}else if(t.substring(2,t.length)=="***"){m.setValue("day");g.setCronValue(n[0]);b.setCronValue(n[0]);y.setCronValue(n[1])}else if(t.substring(2,t.length)=="-**"){m.setValue("month");g.setCronValue(n[0]);b.setCronValue(n[0]);y.setCronValue(n[1]);E.setCronValue(n[2])}else if(t.substring(2,t.length)=="**-"){m.setValue("week");g.setCronValue(n[0]);b.setCronValue(n[0]);y.setCronValue(n[1]);w.setCronValue(n[4])}else if(t.substring(3,t.length)=="-*"){m.setValue("year");g.setCronValue(n[0]);b.setCronValue(n[0]);y.setCronValue(n[1]);E.setCronValue(n[2]);S.setCronValue(n[3])}else{i.error(i.getText("error4"))}i.clearError()}catch(r){}};this.closeSelectors=function(){for(var e=v.length;e--;){v[e].close()}};this.getId=function(){return s.attr("id")};this.getText=function(e){var t=n.texts[n.lang][e]||null;if(typeof t=="string"&&t.match("<b")){t=t.replace(/()/gi,'');t=''+t+""}return t};this.getHumanText=function(){var t=[];o.find("> span > span:visible").find(".jqCron-text, .jqCron-selector > span").each(function(){var n=e(this).text().replace(/\s+$/g,"").replace(/^\s+/g,"");n&&t.push(n)});return t.join(" ").replace(/\s:\s/g,":")};this.getSettings=function(){return n};this.error=function(e){console&&console.error("[jqCron Error] "+e);o.addClass("jqCron-error").attr("title",e);throw e};this.clearError=function(){o.attr("title","").removeClass("jqCron-error")};this.clear=function(){E.setValue([]);w.setValue([]);g.setValue([]);S.setValue([]);y.setValue([]);b.setValue([]);i.triggerChange()};this.init=function(){var t,T,N;if(r)return;n=jqCronMergeSettings(n);n.jquery_element||i.error(i.getText("error3"));s=n.jquery_element;s.append(o);o.data("id",n.id);o.data("jqCron",i);o.append(u);n.no_reset_button||o.append(d);!n.disable||o.addClass("disable");u.append(a);u.append(f);u.append(l);u.append(c);u.append(h);u.append(p);d.click(function(){i.isDisabled()||i.clear()});o.bind("cron:change",function(e,t){if(!n.bind_to)return;n.bind_method.set&&n.bind_method.set(n.bind_to,t);i.clearError()});a.append(i.getText("text_period"));m=x(a,false,"period");n.enabled_minute&&m.add("minute",i.getText("name_minute"));n.enabled_hour&&m.add("hour",i.getText("name_hour"));n.enabled_day&&m.add("day",i.getText("name_day"));n.enabled_week&&m.add("week",i.getText("name_week"));n.enabled_month&&m.add("month",i.getText("name_month"));n.enabled_year&&m.add("year",i.getText("name_year"));m.$.bind("selector:change",function(e,t){f.hide();l.hide();c.hide();h.hide();p.hide();if(t=="hour"){c.show()}else if(t=="day"){p.show()}else if(t=="week"){h.show();p.show()}else if(t=="month"){f.show();p.show()}else if(t=="year"){f.show();l.show();p.show()}});m.setValue(n.default_period);c.append(i.getText("text_mins"));g=x(c,n.multiple_mins,"minutes");for(T=0,N=n.minutes;T<N.length;T++){g.add(N[T],N[T])}p.append(i.getText("text_time"));y=x(p,n.multiple_time_hours,"time_hours");for(T=0,N=n.hours;T<N.length;T++){y.add(N[T],N[T])}b=x(p,n.multiple_time_minutes,"time_minutes");for(T=0,N=n.minutes;T<N.length;T++){b.add(N[T],N[T])}h.append(i.getText("text_dow"));w=x(h,n.multiple_dow,"day_of_week");for(T=0,N=i.getText("weekdays");T<N.length;T++){w.add(T+1,N[T])}f.append(i.getText("text_dom"));E=x(f,n.multiple_dom,"day_of_month");for(T=0,N=n.monthdays;T<N.length;T++){E.add(N[T],N[T])}l.append(i.getText("text_month"));S=x(l,n.multiple_month,"month");for(T=0,N=i.getText("months");T<N.length;T++){S.add(T+1,N[T])}e("body").click(function(){var e,t=v.length;for(e=0;e<t;e++){v[e].close()}});r=true;if(n.default_value){i.setCron(n.default_value)}};this.triggerChange=function(){o.trigger("cron:change",i.getCron())};t.push(this);this.$=o;try{this.init();i.triggerChange()}catch(T){}}var t=[];this.jqCron=n}).call(this,jQuery);(function(e){function t(t,n,r,i){function p(e){var t=0,n=e.length,r={},i=[];while(t<n){r[e[t]]||(r[e[t]]=1&&i.push(e[t]));t++}return i}var s=this;var o=e('

');var u=e('');var a=e('');var f={};var l=[];var c=true;var h=t.getSettings().numeric_zero_pad;this.getValue=function(){return r?l:l[0]};this.getCronValue=function(){if(l.length==0)return"*";var e=[l[0]],t,n=l[0],r=l[0],i=l.length;for(t=1;t<i;t++){if(l[t]==r+1){r=l[t];e[e.length-1]=n+"-"+r}else{n=r=l[t];e.push(r)}}return e.join(",")};this.setCronValue=function(e){var t=[],n,r,i;if(e!=="*"){while(e!=""){n=e.match(/^\*\/([0-9]+),?/);if(n&&n.length==2){for(r=0;r<=59;r+=n[1]|0){t.push(r)}e=e.replace(n[0],"");continue}n=e.match(/^([0-9]+)-([0-9]+)\/([0-9]+),?/);if(n&&n.length==4){for(r=n[1]|0;r<=(n[2]|0);r+=n[3]|0){t.push(r)}e=e.replace(n[0],"");continue}n=e.match(/^([0-9]+)-([0-9]+),?/);if(n&&n.length==3){for(r=n[1]|0;r<=(n[2]|0);r++){t.push(r)}e=e.replace(n[0],"");continue}n=e.match(/^([0-9]+),?/);if(n&&n.length==2){t.push(n[1]|0);e=e.replace(n[0],"");continue}return}}s.setValue(t)};this.close=function(){a.trigger("selector:close")};this.open=function(){a.trigger("selector:open")};this.isOpened=function(){return o.is(":visible")};this.addValue=function(e){var t=r?l.slice(0):[];t.push(e);s.setValue(t)};this.removeValue=function(e){if(r){var t,n=[];for(t=0;t<l.length;t++){if(e!=[l[t]]){n.push(l[t])}}s.setValue(n)}else{s.clear()}};this.setValue=function(t){var n,i=[],s=l.join(" ");if(!e.isArray(t))t=[t];o.find("li").removeClass("selected");t=p(t);t.sort(function(e,t){var n=typeof e;var r=typeof t;if(n==r&&n=="number")return e-t;else return String(e)==String(t)?0:String(e)<String(t)?-1:1});if(r){for(n=0;n<t.length;n++){if(t[n]in f){f[t[n]].addClass("selected");i.push(t[n])}}}else{if(t[0]in f){f[t[0]].addClass("selected");i.push(t[0])}}l=i;if(s!=l.join(" ")){a.trigger("selector:change",r?t:t[0]);return true}return false};this.getTitleText=function(){var e=function(e){return e in f?f[e].text():e};if(l.length==0){return t.getText("empty_"+i)||t.getText("empty")}var n=[e(l[0])],r,s=l[0],o=l[0],u=l.length;for(r=1;r<u;r++){if(l[r]==o+1){o=l[r];n[n.length-1]=e(s)+"-"+e(o)}else{s=o=l[r];n.push(e(o))}}return n.join(",")};this.clear=function(){f={};s.setValue([]);o.empty()};this.add=function(t,n){if(!(n+"").match(/^[0-9]+$/))c=false;if(h&&c&&n<10){n="0"+n}var i=e("
"+n+"
");o.append(i);f[t]=i;i.click(function(){if(r&&e(this).hasClass("selected")){s.removeValue(t)}else{s.addValue(t);if(!r)s.close()}})};this.$=a;n.find("b:eq(0)").after(a).remove();a.addClass("jqCron-selector-"+n.find(".jqCron-selector").length).append(u).append(o).bind("selector:open",function(){if(c){var e=1,t=o.find("li").length;if(t>5&&t<=16)e=2;else if(t>16&&t<=23)e=3;else if(t>23&&t<=40)e=4;else if(t>40)e=5;o.addClass("cols"+e)}o.show()}).bind("selector:close",function(){o.hide()}).bind("selector:change",function(){u.html(s.getTitleText())}).click(function(e){e.stopPropagation()}).trigger("selector:change");e.fn.disableSelection&&a.disableSelection();u.click(function(e){s.isOpened()||t.isDisabled()?s.close():s.open()});s.close();s.clear()}this.jqCronSelector=t}).call(this,jQuery);(function(e){var t=0;var n=function(e){var n;while(1){t++;n=(e||"JQUID")+""+t;if(!document.getElementById(n))return n}};e.fn.uniqueId=function(t){return this.each(function(){if(e(this).attr("id"))return;var r=n(t);e(this).attr("id",r)})}}).call(this,jQuery);(function(e){e.extend(e.expr[":"],{container:function(e){return(e.tagName+"").toLowerCase()in{a:1,abbr:1,acronym:1,address:1,b:1,big:1,blockquote:1,button:1,cite:1,code:1,dd:1,del:1,dfn:1,div:1,dt:1,em:1,fieldset:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,i:1,ins:1,kbd:1,label:1,li:1,p:1,pre:1,q:1,samp:1,small:1,span:1,strong:1,sub:1,sup:1,td:1,tt:1}},autoclose:function(e){return(e.tagName+"").toLowerCase()in{area:1,base:1,basefont:1,br:1,col:1,frame:1,hr:1,img:1,input:1,link:1,meta:1,param:1}}})}).call(this,jQuery)
<commit_msg>Delete jqCron.min.js<commit_after><|endoftext|>


<commit_before>/* ========================================
 * CORS Planner - App Main
 *
 * Author: Wang Zhuochun
 * Last Edit: 23/Jul/2012 09:33 PM
 * ========================================
 * <License>
 * ======================================== */

define(function(require, exports) {

    "use strict";
    /*jshint jquery:true, laxcomma:true, maxerr:50*/

    // include jQuery plugins
    require("jquery-ui");
    require("bootstrap");
    // include the jQuery Pub/Sub plugin
    require("util/pubsub");

    // include app view
    var version = "0.0.5"
    // include components
      , store = require("util/store")
      , appView = require("view/appView");

    // exports module
    exports.init = function(v) {
        // send greeting messages
        greetUser();
        // initial app views
        appView.render();
    };

    // greeting user according to version
    function greetUser(_version) {
        _version = store.get("version");

        if (!_version) { // new user
            $.publish("app:newUser", [version]);
        } else if (_version < version) { // on older version
            $.publish("app:update", [version]);
        } else { // existing user
            $.publish("app:intro", [version]);
        }

        store.set("version", version); // set version
    }

});
<commit_msg>update app to include planner global<commit_after>/* ========================================
 * CORS Planner - App Main
 *
 * Load all app components required
 *
 * Author: Wang Zhuochun
 * Last Edit: 28/Jul/2012 10:41 PM
 * ========================================
 * <License>
 * ======================================== */

define(function(require, exports) {

    "use strict";
    /*jshint jquery:true, laxcomma:true, maxerr:50*/
    /*globals planner*/

    // include jQuery plugins
    require("jquery-ui");
    require("bootstrap");
    // include the jQuery Pub/Sub plugin
    require("util/pubsub");

    // include third party
    var store = require("util/store")
    // include controllers
    , modulesController = require("controller/modulesController")
    , plannerController = require("controller/plannerController")
    // include app view
    , appView = require("view/appView");

    // expose a planner variable in global namespace
    //
    // Taken from: (in case window is not the point to the global object)
    //   http://stackoverflow.com/questions/3277182/how-to-get-the-global-object-in-javascript
    function _initGlobalPlanner() {
        var Fn = Function, global = (new Fn('return this'))();

        if (!global.planner) {
            global.planner = {};
        }

        // assign CORS Planner Version number
        planner.version = "0.0.6";
        // assign CORS Data latest update time
        planner.dataUpdate = "24 Jul 2012 11:29";
    }

    // check the version between server and user, emits an message to all
    function _versionCheck(_version) {
        // get user's version
        _version = store.get("version");
        // set version again
        store.set("version", planner.version);
        // publish the app wide message related to user
        $.publish("app:user:" + ((!_version) ? "new" :
            (_version < planner.version) ? "updated" : "uptodate"));
    }

    // exports module
    exports.init = function(v) {
        // init app itself
        _initGlobalPlanner();
        // render all the app views
        appView.render();
        // version check
        _versionCheck();
    };

});
<|endoftext|>


<commit_before>;(function($, Planner, Handlebars) { 'use strict';

    // Local data useful for some helpers
    // ----------------------------------

    var dayColumns = [
        {name: 'Monday'},
        {name: 'Tuesday'},
        {name: 'Wednesday'},
        {name: 'Thursday'},
        {name: 'Friday'},
        {name: 'Saturday'},
        {name: 'Sunday'}
    ];

    var hourRows = [
        {name: '00:00'},
        {name: '01:00'},
        {name: '02:00'},
        {name: '03:00'},
        {name: '04:00'},
        {name: '05:00'},
        {name: '06:00'},
        {name: '07:00'},
        {name: '08:00'},
        {name: '09:00'},
        {name: '10:00'},
        {name: '11:00'},
        {name: '12:00'},
        {name: '13:00'},
        {name: '14:00'},
        {name: '15:00'},
        {name: '16:00'},
        {name: '17:00'},
        {name: '18:00'},
        {name: '19:00'},
        {name: '20:00'},
        {name: '21:00'},
        {name: '22:00'},
        {name: '23:00'}
    ];

    // Planner helpers
    // ---------------

    Planner.Helpers = {
        // Generate a computed style node
        computedCSS: function(options) {
            var styleNode = $('<style></style>');

            styleNode.html(Planner.Templates.styles({
                textAlignment: options.textAlignment,
                topPadding: options.timeslotsHeight * 2 + 44,
                rowHeight: options.timeslotsHeight,
                rowPadding: (options.timeslots - 1) * options.timeslotsHeight + 5,
                timeslots: options.timeslots
            }));

            return styleNode;
        },
        // Create HTML string using a default columns configuration
        plannerWeekday: function(options) {
            return Planner.Templates.body({columns: dayColumns, rows: hourRows, timeslots: options.timeslots});
        }
    };

    // Handlebars helpers
    // ------------------

    Handlebars.registerHelper('times', function(n, block) {
        var accumulator = '';

        for (var i = 0; i < n; ++i) {
            accumulator += block.fn(i);
        }

        return accumulator;
    });

})(jQuery, Planner, Handlebars);
<commit_msg>Row padding according to timeslots number and height. Fixed #2<commit_after>;(function($, Planner, Handlebars) { 'use strict';

    // Local data useful for some helpers
    // ----------------------------------

    var dayColumns = [
        {name: 'Monday'},
        {name: 'Tuesday'},
        {name: 'Wednesday'},
        {name: 'Thursday'},
        {name: 'Friday'},
        {name: 'Saturday'},
        {name: 'Sunday'}
    ];

    var hourRows = [
        {name: '00:00'},
        {name: '01:00'},
        {name: '02:00'},
        {name: '03:00'},
        {name: '04:00'},
        {name: '05:00'},
        {name: '06:00'},
        {name: '07:00'},
        {name: '08:00'},
        {name: '09:00'},
        {name: '10:00'},
        {name: '11:00'},
        {name: '12:00'},
        {name: '13:00'},
        {name: '14:00'},
        {name: '15:00'},
        {name: '16:00'},
        {name: '17:00'},
        {name: '18:00'},
        {name: '19:00'},
        {name: '20:00'},
        {name: '21:00'},
        {name: '22:00'},
        {name: '23:00'}
    ];

    // Planner helpers
    // ---------------

    Planner.Helpers = {
        // Generate a computed style node
        computedCSS: function(options) {
            var styleNode = $('<style></style>');

            styleNode.html(Planner.Templates.styles({
                textAlignment: options.textAlignment,
                topPadding: options.timeslotsHeight * 2 + 44,
                rowHeight: options.timeslotsHeight,
                rowPadding: options.timeslots * options.timeslotsHeight - 20,
                timeslots: options.timeslots
            }));

            return styleNode;
        },
        // Create HTML string using a default columns configuration
        plannerWeekday: function(options) {
            return Planner.Templates.body({columns: dayColumns, rows: hourRows, timeslots: options.timeslots});
        }
    };

    // Handlebars helpers
    // ------------------

    Handlebars.registerHelper('times', function(n, block) {
        var accumulator = '';

        for (var i = 0; i < n; ++i) {
            accumulator += block.fn(i);
        }

        return accumulator;
    });

})(jQuery, Planner, Handlebars);
<|endoftext|>


<commit_before>

export function menubar()
{

  // Polyfill
  if (HTMLCollection.prototype.forEach === undefined) { HTMLCollection.prototype.forEach = [].forEach }

  function showMenu(e)
  {
    closeAllMenus();
    this.classList.add('activeMenu');
    e.stopPropagation();
  }

  function closeAllMenus()
  {
    document.getElementsByClassName('activeMenu').forEach(function (node) { node.classList.remove('activeMenu') })
  }

  (function()
  {
    function on(e,f){window.addEventListener(e,f)
  }

  // Show menu event handler
  on('load', function (event)
  {
    document.getElementsByClassName('menuLabel').forEach(function(node) { node.onmouseover = showMenu })
  })

  // Close all open menus on click or escape
  on('click', closeAllMenus, true)
  on('keydown', function (event) { (event.key === "Escape") && closeAllMenus() }, true)

  })();

}

<commit_msg>tweaked menu bar behavior<commit_after>

export function menubar()
{

  // Polyfill
  if (HTMLCollection.prototype.forEach === undefined) { HTMLCollection.prototype.forEach = [].forEach }
  let display_menu = false;

  function showMenu(e)
  {
    closeAllMenus();

    if (e.type == "click"){ display_menu = !display_menu; }

    if (display_menu){
      this.classList.add('activeMenu');
      e.stopPropagation();
    }

  }

  function closeAllMenus()
  {
    document.getElementsByClassName('activeMenu').forEach(function (node) { node.classList.remove('activeMenu') });
  }

  function resetAllMenus()
  {
    display_menu = false;
    closeAllMenus();
  }

  (function()
  {
    function on(e,f){window.addEventListener(e,f)
  }

  // Show menu event handler
  on('load', function (event)
  {
    document.getElementsByClassName('menuLabel').forEach(function(node) {
      node.onmouseover = showMenu ;
      node.onclick = showMenu;
    })
  })

  // Close all open menus on click or escape
  on('click', resetAllMenus, true)
  on('keydown', function (event) { (event.key === "Escape") && closeAllMenus() }, true)

  })();

}

<|endoftext|>


<commit_before>let Utils = require("./lib/utils.js");
let Bacon = require("baconjs");

function saveOptions() {
  chrome.storage.local.set({
    closeTab: document.querySelector("#close_tab").checked,
    pinTab: document.querySelector("#pin_tab").checked,
    autoRefresh: document.querySelector("#autorefresh_tab").checked,
    newTab: document.querySelector("#newtab_tab").checked,
    showDomain: document.querySelector("#show_domain_tab").checked,
  });
}

function restoreOptions() {
  chrome.storage.local.get(["closeTab", "pinTab", "autoRefresh", "newtab", "showDomain"], res => {
    let closetab = res.closeTab;
    let pintab = res.pinTab;
    let autorefresh = res.autoRefresh;
    let newtab = res.newTab;
    let showdomain = res.showDomain;
    document.querySelector("#close_tab").checked = closetab || false;
    document.querySelector("#pin_tab").checked = pintab || false;
    document.querySelector("#autorefresh_tab").checked = autorefresh || false;
    document.querySelector("#newtab_tab").checked = newtab || false;
    document.querySelector("#show_domain_tab").checked = showdomain || false;
  });
}

// Bacon.fromEvent();

document.addEventListener("DOMContentLoaded", restoreOptions);
document.querySelector("form").addEventListener("submit", saveOptions);

// tab backup and restore
document.getElementById("backup_tabs").onclick = function() {
  chrome.tabs.query({}, function(tabs) {
    download(JSON.stringify(tabs, null, " "));
  });
};

let restoreTab = Bacon.fromEvent(document.getElementById("restore_tabs_file"), "change");
let fileinput = document.getElementById("restore_tabs_file");

document.getElementById("restore_tabs").onclick = function() {
  fileinput.click();
};

restoreTab.onValue(() => {
  let filelist = fileinput.files;
  var reader = new FileReader();

  reader.onload = (function() { return function(e) {
    let restoredata = e.target.result.replace(/^[^,]*,/g, "");
    try{
      let data = window.atob(restoredata);
      let json = JSON.parse(data);
      if (json) {
        let wins = Utils.groupByWindow(json);
        for (let [_, tabs] of wins) {
          let links = Utils.getLinksFromTabs(tabs);
          chrome.windows.create({ url: links });
        }
      }
    } catch(e){
      console.error(e);
    }
  }; })();

  reader.readAsDataURL(filelist[0]);
});

function download(data) {
  var blob = new Blob([data], {type: "text/json"});
  var url = window.URL.createObjectURL(blob);
  chrome.downloads.download({url:url, filename:"tabsbackup.json", conflictAction:"uniquify"}, function() {
    // console.log(downloadId);
  });
}
<commit_msg>Slow down the creation of windows to avoid crashes<commit_after>let Utils = require("./lib/utils.js");
let Bacon = require("baconjs");

function saveOptions() {
  chrome.storage.local.set({
    closeTab: document.querySelector("#close_tab").checked,
    pinTab: document.querySelector("#pin_tab").checked,
    autoRefresh: document.querySelector("#autorefresh_tab").checked,
    newTab: document.querySelector("#newtab_tab").checked,
    showDomain: document.querySelector("#show_domain_tab").checked,
  });
}

function restoreOptions() {
  chrome.storage.local.get(["closeTab", "pinTab", "autoRefresh", "newtab", "showDomain"], res => {
    let closetab = res.closeTab;
    let pintab = res.pinTab;
    let autorefresh = res.autoRefresh;
    let newtab = res.newTab;
    let showdomain = res.showDomain;
    document.querySelector("#close_tab").checked = closetab || false;
    document.querySelector("#pin_tab").checked = pintab || false;
    document.querySelector("#autorefresh_tab").checked = autorefresh || false;
    document.querySelector("#newtab_tab").checked = newtab || false;
    document.querySelector("#show_domain_tab").checked = showdomain || false;
  });
}

// Bacon.fromEvent();

document.addEventListener("DOMContentLoaded", restoreOptions);
document.querySelector("form").addEventListener("submit", saveOptions);

// tab backup and restore
document.getElementById("backup_tabs").onclick = function() {
  chrome.tabs.query({}, function(tabs) {
    download(JSON.stringify(tabs, null, " "));
  });
};

let restoreTab = Bacon.fromEvent(document.getElementById("restore_tabs_file"), "change");
let fileinput = document.getElementById("restore_tabs_file");

document.getElementById("restore_tabs").onclick = function() {
  fileinput.click();
};

restoreTab.onValue(() => {
  let filelist = fileinput.files;
  var reader = new FileReader();

  function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  reader.onload = (function() { return async function(e) {
    let restoredata = e.target.result.replace(/^[^,]*,/g, "");
    try{
      let data = window.atob(restoredata);
      let json = JSON.parse(data);
      if (json) {
        let wins = Utils.groupByWindow(json);
        for (let [_, tabs] of wins) {
          let links = Utils.getLinksFromTabs(tabs);
          chrome.windows.create({ url: links });
          await sleep(1000);
        }
      }
    } catch(e){
      console.error(e);
    }
  }; })();

  reader.readAsDataURL(filelist[0]);
});

function download(data) {
  var blob = new Blob([data], {type: "text/json"});
  var url = window.URL.createObjectURL(blob);
  chrome.downloads.download({url:url, filename:"tabsbackup.json", conflictAction:"uniquify"}, function() {
    // console.log(downloadId);
  });
}
<|endoftext|>


<commit_before>/*	Every input option is tested and parsed. This'll prevent
	endless validation in internal methods. These tests are
	structured with an item for every option available. An
	option can be marked as required by setting the 'r' flag.
	The testing function is provided with three arguments:
		- The provided value for the option;
		- A reference to the options object;
		- The name for the option;

	The testing function returns false when an error is detected,
	or true when everything is OK. It can also modify the option
	object, to make sure all values can be correctly looped elsewhere. */

	var defaultFormatter = { 'to': function( value ){
		return value !== undefined && value.toFixed(2);
	}, 'from': Number };

	function testStep ( parsed, entry ) {

		if ( !isNumeric( entry ) ) {
			throw new Error("noUiSlider: 'step' is not numeric.");
		}

		// The step option can still be used to set stepping
		// for linear sliders. Overwritten if set in 'range'.
		parsed.singleStep = entry;
	}

	function testRange ( parsed, entry ) {

		// Filter incorrect input.
		if ( typeof entry !== 'object' || Array.isArray(entry) ) {
			throw new Error("noUiSlider: 'range' is not an object.");
		}

		// Catch missing start or end.
		if ( entry.min === undefined || entry.max === undefined ) {
			throw new Error("noUiSlider: Missing 'min' or 'max' in 'range'.");
		}

		// Catch equal start or end.
		if ( entry.min === entry.max ) {
			throw new Error("noUiSlider: 'range' 'min' and 'max' cannot be equal.");
		}

		parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.dir, parsed.singleStep);
	}

	function testStart ( parsed, entry ) {

		entry = asArray(entry);

		// Validate input. Values aren't tested, as the public .val method
		// will always provide a valid location.
		if ( !Array.isArray( entry ) || !entry.length ) {
			throw new Error("noUiSlider: 'start' option is incorrect.");
		}

		// Store the number of handles.
		parsed.handles = entry.length;

		// When the slider is initialized, the .val method will
		// be called with the start options.
		parsed.start = entry;
	}

	function testSnap ( parsed, entry ) {

		// Enforce 100% stepping within subranges.
		parsed.snap = entry;

		if ( typeof entry !== 'boolean' ){
			throw new Error("noUiSlider: 'snap' option must be a boolean.");
		}
	}

	function testAnimate ( parsed, entry ) {

		// Enforce 100% stepping within subranges.
		parsed.animate = entry;

		if ( typeof entry !== 'boolean' ){
			throw new Error("noUiSlider: 'animate' option must be a boolean.");
		}
	}

	function testAnimationDuration ( parsed, entry ) {

		parsed.animationDuration = entry;

		if ( typeof entry !== 'number' ){
			throw new Error("noUiSlider: 'animationDuration' option must be a number.");
		}
	}

	function testConnect ( parsed, entry ) {

		var connect = [false];
		var i;

		if ( entry === true || entry === false ) {

			for ( i = 1; i < parsed.handles; i++ ) {
				connect.push(entry);
			}

			connect.push(false);
		}

		else if ( !Array.isArray( entry ) || !entry.length || entry.length !== parsed.handles + 1 ) {
			throw new Error("noUiSlider: 'connect' option doesn't match handle count.");
		}

		else {
			connect = entry;
		}

		parsed.connect = connect;
	}

	function testOrientation ( parsed, entry ) {

		// Set orientation to an a numerical value for easy
		// array selection.
		switch ( entry ){
		  case 'horizontal':
			parsed.ort = 0;
			break;
		  case 'vertical':
			parsed.ort = 1;
			break;
		  default:
			throw new Error("noUiSlider: 'orientation' option is invalid.");
		}
	}

	function testMargin ( parsed, entry ) {

		if ( !isNumeric(entry) ){
			throw new Error("noUiSlider: 'margin' option must be numeric.");
		}

		// Issue #582
		if ( entry === 0 ) {
			return;
		}

		parsed.margin = parsed.spectrum.getMargin(entry);

		if ( !parsed.margin ) {
			throw new Error("noUiSlider: 'margin' option is only supported on linear sliders.");
		}
	}

	function testLimit ( parsed, entry ) {

		if ( !isNumeric(entry) ){
			throw new Error("noUiSlider: 'limit' option must be numeric.");
		}

		parsed.limit = parsed.spectrum.getMargin(entry);

		if ( !parsed.limit || parsed.handles < 2 ) {
			throw new Error("noUiSlider: 'limit' option is only supported on linear sliders with 2 or more handles.");
		}
	}

	function testPadding ( parsed, entry ) {

		if ( !isNumeric(entry) ){
			throw new Error("noUiSlider: 'padding' option must be numeric.");
		}

		if ( entry === 0 ) {
			return;
		}

		parsed.padding = parsed.spectrum.getMargin(entry);

		if ( !parsed.padding ) {
			throw new Error("noUiSlider: 'padding' option is only supported on linear sliders.");
		}
	}

	function testDirection ( parsed, entry ) {

		// Set direction as a numerical value for easy parsing.
		// Invert connection for RTL sliders, so that the proper
		// handles get the connect/background classes.
		switch ( entry ) {
		  case 'ltr':
			parsed.dir = 0;
			break;
		  case 'rtl':
			parsed.dir = 1;
			break;
		  default:
			throw new Error("noUiSlider: 'direction' option was not recognized.");
		}
	}

	function testBehaviour ( parsed, entry ) {

		// Make sure the input is a string.
		if ( typeof entry !== 'string' ) {
			throw new Error("noUiSlider: 'behaviour' must be a string containing options.");
		}

		// Check if the string contains any keywords.
		// None are required.
		var tap = entry.indexOf('tap') >= 0;
		var drag = entry.indexOf('drag') >= 0;
		var fixed = entry.indexOf('fixed') >= 0;
		var snap = entry.indexOf('snap') >= 0;
		var hover = entry.indexOf('hover') >= 0;

		if ( fixed ) {

			if ( parsed.handles !== 2 ) {
				throw new Error("noUiSlider: 'fixed' behaviour must be used with 2 handles");
			}

			// Use margin to enforce fixed state
			testMargin(parsed, parsed.start[1] - parsed.start[0]);
		}

		parsed.events = {
			tap: tap || snap,
			drag: drag,
			fixed: fixed,
			snap: snap,
			hover: hover
		};
	}

	function testTooltips ( parsed, entry ) {

		if ( entry === false ) {
			return;
		}

		else if ( entry === true ) {

			parsed.tooltips = [];

			for ( var i = 0; i < parsed.handles; i++ ) {
				parsed.tooltips.push(true);
			}
		}

		else {

			parsed.tooltips = asArray(entry);

			if ( parsed.tooltips.length !== parsed.handles ) {
				throw new Error("noUiSlider: must pass a formatter for all handles.");
			}

			parsed.tooltips.forEach(function(formatter){
				if ( typeof formatter !== 'boolean' && (typeof formatter !== 'object' || typeof formatter.to !== 'function') ) {
					throw new Error("noUiSlider: 'tooltips' must be passed a formatter or 'false'.");
				}
			});
		}
	}

	function testFormat ( parsed, entry ) {

		parsed.format = entry;

		// Any object with a to and from method is supported.
		if ( typeof entry.to === 'function' && typeof entry.from === 'function' ) {
			return true;
		}

		throw new Error("noUiSlider: 'format' requires 'to' and 'from' methods.");
	}

	function testCssPrefix ( parsed, entry ) {

		if ( entry !== undefined && typeof entry !== 'string' && entry !== false ) {
			throw new Error("noUiSlider: 'cssPrefix' must be a string or `false`.");
		}

		parsed.cssPrefix = entry;
	}

	function testCssClasses ( parsed, entry ) {

		if ( entry !== undefined && typeof entry !== 'object' ) {
			throw new Error("noUiSlider: 'cssClasses' must be an object.");
		}

		if ( typeof parsed.cssPrefix === 'string' ) {
			parsed.cssClasses = {};

			for ( var key in entry ) {
				if ( !entry.hasOwnProperty(key) ) { continue; }

				parsed.cssClasses[key] = parsed.cssPrefix + entry[key];
			}
		} else {
			parsed.cssClasses = entry;
		}
	}

	function testUseRaf ( parsed, entry ) {
		if ( entry === true || entry === false ) {
			parsed.useRequestAnimationFrame = entry;
		} else {
			throw new Error("noUiSlider: 'useRequestAnimationFrame' option should be true (default) or false.");
		}
	}

	// Test all developer settings and parse to assumption-safe values.
	function testOptions ( options ) {

		// To prove a fix for #537, freeze options here.
		// If the object is modified, an error will be thrown.
		// Object.freeze(options);

		var parsed = {
			margin: 0,
			limit: 0,
			padding: 0,
			animate: true,
			animationDuration: 300,
			format: defaultFormatter
		}, tests;

		// Tests are executed in the order they are presented here.
		tests = {
			'step': { r: false, t: testStep },
			'start': { r: true, t: testStart },
			'connect': { r: true, t: testConnect },
			'direction': { r: true, t: testDirection },
			'snap': { r: false, t: testSnap },
			'animate': { r: false, t: testAnimate },
			'animationDuration': { r: false, t: testAnimationDuration },
			'range': { r: true, t: testRange },
			'orientation': { r: false, t: testOrientation },
			'margin': { r: false, t: testMargin },
			'limit': { r: false, t: testLimit },
			'padding': { r: false, t: testPadding },
			'behaviour': { r: true, t: testBehaviour },
			'format': { r: false, t: testFormat },
			'tooltips': { r: false, t: testTooltips },
			'cssPrefix': { r: false, t: testCssPrefix },
			'cssClasses': { r: false, t: testCssClasses },
			'useRequestAnimationFrame': { r: false, t: testUseRaf }
		};

		var defaults = {
			'connect': false,
			'direction': 'ltr',
			'behaviour': 'tap',
			'orientation': 'horizontal',
			'cssPrefix' : 'noUi-',
			'cssClasses': {
				target: 'target',
				base: 'base',
				origin: 'origin',
				handle: 'handle',
				horizontal: 'horizontal',
				vertical: 'vertical',
				background: 'background',
				connect: 'connect',
				ltr: 'ltr',
				rtl: 'rtl',
				draggable: 'draggable',
				drag: 'state-drag',
				tap: 'state-tap',
				active: 'active',
				tooltip: 'tooltip',
				pips: 'pips',
				pipsHorizontal: 'pips-horizontal',
				pipsVertical: 'pips-vertical',
				marker: 'marker',
				markerHorizontal: 'marker-horizontal',
				markerVertical: 'marker-vertical',
				markerNormal: 'marker-normal',
				markerLarge: 'marker-large',
				markerSub: 'marker-sub',
				value: 'value',
				valueHorizontal: 'value-horizontal',
				valueVertical: 'value-vertical',
				valueNormal: 'value-normal',
				valueLarge: 'value-large',
				valueSub: 'value-sub'
			},
			'useRequestAnimationFrame': true
		};

		// Run all options through a testing mechanism to ensure correct
		// input. It should be noted that options might get modified to
		// be handled properly. E.g. wrapping integers in arrays.
		Object.keys(tests).forEach(function( name ){

			// If the option isn't set, but it is required, throw an error.
			if ( options[name] === undefined && defaults[name] === undefined ) {

				if ( tests[name].r ) {
					throw new Error("noUiSlider: '" + name + "' is required.");
				}

				return true;
			}

			tests[name].t( parsed, options[name] === undefined ? defaults[name] : options[name] );
		});

		// Forward pips options
		parsed.pips = options.pips;

		var styles = [['left', 'top'], ['right', 'bottom']];

		// Pre-define the styles.
		parsed.style = styles[parsed.dir][parsed.ort];
		parsed.styleOposite = styles[parsed.dir?0:1][parsed.ort];

		return parsed;
	}
<commit_msg>Add padding option constraints<commit_after>/*	Every input option is tested and parsed. This'll prevent
	endless validation in internal methods. These tests are
	structured with an item for every option available. An
	option can be marked as required by setting the 'r' flag.
	The testing function is provided with three arguments:
		- The provided value for the option;
		- A reference to the options object;
		- The name for the option;

	The testing function returns false when an error is detected,
	or true when everything is OK. It can also modify the option
	object, to make sure all values can be correctly looped elsewhere. */

	var defaultFormatter = { 'to': function( value ){
		return value !== undefined && value.toFixed(2);
	}, 'from': Number };

	function testStep ( parsed, entry ) {

		if ( !isNumeric( entry ) ) {
			throw new Error("noUiSlider: 'step' is not numeric.");
		}

		// The step option can still be used to set stepping
		// for linear sliders. Overwritten if set in 'range'.
		parsed.singleStep = entry;
	}

	function testRange ( parsed, entry ) {

		// Filter incorrect input.
		if ( typeof entry !== 'object' || Array.isArray(entry) ) {
			throw new Error("noUiSlider: 'range' is not an object.");
		}

		// Catch missing start or end.
		if ( entry.min === undefined || entry.max === undefined ) {
			throw new Error("noUiSlider: Missing 'min' or 'max' in 'range'.");
		}

		// Catch equal start or end.
		if ( entry.min === entry.max ) {
			throw new Error("noUiSlider: 'range' 'min' and 'max' cannot be equal.");
		}

		parsed.spectrum = new Spectrum(entry, parsed.snap, parsed.dir, parsed.singleStep);
	}

	function testStart ( parsed, entry ) {

		entry = asArray(entry);

		// Validate input. Values aren't tested, as the public .val method
		// will always provide a valid location.
		if ( !Array.isArray( entry ) || !entry.length ) {
			throw new Error("noUiSlider: 'start' option is incorrect.");
		}

		// Store the number of handles.
		parsed.handles = entry.length;

		// When the slider is initialized, the .val method will
		// be called with the start options.
		parsed.start = entry;
	}

	function testSnap ( parsed, entry ) {

		// Enforce 100% stepping within subranges.
		parsed.snap = entry;

		if ( typeof entry !== 'boolean' ){
			throw new Error("noUiSlider: 'snap' option must be a boolean.");
		}
	}

	function testAnimate ( parsed, entry ) {

		// Enforce 100% stepping within subranges.
		parsed.animate = entry;

		if ( typeof entry !== 'boolean' ){
			throw new Error("noUiSlider: 'animate' option must be a boolean.");
		}
	}

	function testAnimationDuration ( parsed, entry ) {

		parsed.animationDuration = entry;

		if ( typeof entry !== 'number' ){
			throw new Error("noUiSlider: 'animationDuration' option must be a number.");
		}
	}

	function testConnect ( parsed, entry ) {

		var connect = [false];
		var i;

		if ( entry === true || entry === false ) {

			for ( i = 1; i < parsed.handles; i++ ) {
				connect.push(entry);
			}

			connect.push(false);
		}

		else if ( !Array.isArray( entry ) || !entry.length || entry.length !== parsed.handles + 1 ) {
			throw new Error("noUiSlider: 'connect' option doesn't match handle count.");
		}

		else {
			connect = entry;
		}

		parsed.connect = connect;
	}

	function testOrientation ( parsed, entry ) {

		// Set orientation to an a numerical value for easy
		// array selection.
		switch ( entry ){
		  case 'horizontal':
			parsed.ort = 0;
			break;
		  case 'vertical':
			parsed.ort = 1;
			break;
		  default:
			throw new Error("noUiSlider: 'orientation' option is invalid.");
		}
	}

	function testMargin ( parsed, entry ) {

		if ( !isNumeric(entry) ){
			throw new Error("noUiSlider: 'margin' option must be numeric.");
		}

		// Issue #582
		if ( entry === 0 ) {
			return;
		}

		parsed.margin = parsed.spectrum.getMargin(entry);

		if ( !parsed.margin ) {
			throw new Error("noUiSlider: 'margin' option is only supported on linear sliders.");
		}
	}

	function testLimit ( parsed, entry ) {

		if ( !isNumeric(entry) ){
			throw new Error("noUiSlider: 'limit' option must be numeric.");
		}

		parsed.limit = parsed.spectrum.getMargin(entry);

		if ( !parsed.limit || parsed.handles < 2 ) {
			throw new Error("noUiSlider: 'limit' option is only supported on linear sliders with 2 or more handles.");
		}
	}

	function testPadding ( parsed, entry ) {

		if ( !isNumeric(entry) ){
			throw new Error("noUiSlider: 'padding' option must be numeric.");
		}

		if ( entry === 0 ) {
			return;
		}

		parsed.padding = parsed.spectrum.getMargin(entry);

		if ( !parsed.padding ) {
			throw new Error("noUiSlider: 'padding' option is only supported on linear sliders.");
		}

		if ( parsed.padding < 0 ) {
			throw new Error("noUiSlider: 'padding' option must be a positive number.");
		}

		if ( parsed.padding >= 50 ) {
			throw new Error("noUiSlider: 'padding' option must be less than half the range.");
		}
	}

	function testDirection ( parsed, entry ) {

		// Set direction as a numerical value for easy parsing.
		// Invert connection for RTL sliders, so that the proper
		// handles get the connect/background classes.
		switch ( entry ) {
		  case 'ltr':
			parsed.dir = 0;
			break;
		  case 'rtl':
			parsed.dir = 1;
			break;
		  default:
			throw new Error("noUiSlider: 'direction' option was not recognized.");
		}
	}

	function testBehaviour ( parsed, entry ) {

		// Make sure the input is a string.
		if ( typeof entry !== 'string' ) {
			throw new Error("noUiSlider: 'behaviour' must be a string containing options.");
		}

		// Check if the string contains any keywords.
		// None are required.
		var tap = entry.indexOf('tap') >= 0;
		var drag = entry.indexOf('drag') >= 0;
		var fixed = entry.indexOf('fixed') >= 0;
		var snap = entry.indexOf('snap') >= 0;
		var hover = entry.indexOf('hover') >= 0;

		if ( fixed ) {

			if ( parsed.handles !== 2 ) {
				throw new Error("noUiSlider: 'fixed' behaviour must be used with 2 handles");
			}

			// Use margin to enforce fixed state
			testMargin(parsed, parsed.start[1] - parsed.start[0]);
		}

		parsed.events = {
			tap: tap || snap,
			drag: drag,
			fixed: fixed,
			snap: snap,
			hover: hover
		};
	}

	function testTooltips ( parsed, entry ) {

		if ( entry === false ) {
			return;
		}

		else if ( entry === true ) {

			parsed.tooltips = [];

			for ( var i = 0; i < parsed.handles; i++ ) {
				parsed.tooltips.push(true);
			}
		}

		else {

			parsed.tooltips = asArray(entry);

			if ( parsed.tooltips.length !== parsed.handles ) {
				throw new Error("noUiSlider: must pass a formatter for all handles.");
			}

			parsed.tooltips.forEach(function(formatter){
				if ( typeof formatter !== 'boolean' && (typeof formatter !== 'object' || typeof formatter.to !== 'function') ) {
					throw new Error("noUiSlider: 'tooltips' must be passed a formatter or 'false'.");
				}
			});
		}
	}

	function testFormat ( parsed, entry ) {

		parsed.format = entry;

		// Any object with a to and from method is supported.
		if ( typeof entry.to === 'function' && typeof entry.from === 'function' ) {
			return true;
		}

		throw new Error("noUiSlider: 'format' requires 'to' and 'from' methods.");
	}

	function testCssPrefix ( parsed, entry ) {

		if ( entry !== undefined && typeof entry !== 'string' && entry !== false ) {
			throw new Error("noUiSlider: 'cssPrefix' must be a string or `false`.");
		}

		parsed.cssPrefix = entry;
	}

	function testCssClasses ( parsed, entry ) {

		if ( entry !== undefined && typeof entry !== 'object' ) {
			throw new Error("noUiSlider: 'cssClasses' must be an object.");
		}

		if ( typeof parsed.cssPrefix === 'string' ) {
			parsed.cssClasses = {};

			for ( var key in entry ) {
				if ( !entry.hasOwnProperty(key) ) { continue; }

				parsed.cssClasses[key] = parsed.cssPrefix + entry[key];
			}
		} else {
			parsed.cssClasses = entry;
		}
	}

	function testUseRaf ( parsed, entry ) {
		if ( entry === true || entry === false ) {
			parsed.useRequestAnimationFrame = entry;
		} else {
			throw new Error("noUiSlider: 'useRequestAnimationFrame' option should be true (default) or false.");
		}
	}

	// Test all developer settings and parse to assumption-safe values.
	function testOptions ( options ) {

		// To prove a fix for #537, freeze options here.
		// If the object is modified, an error will be thrown.
		// Object.freeze(options);

		var parsed = {
			margin: 0,
			limit: 0,
			padding: 0,
			animate: true,
			animationDuration: 300,
			format: defaultFormatter
		}, tests;

		// Tests are executed in the order they are presented here.
		tests = {
			'step': { r: false, t: testStep },
			'start': { r: true, t: testStart },
			'connect': { r: true, t: testConnect },
			'direction': { r: true, t: testDirection },
			'snap': { r: false, t: testSnap },
			'animate': { r: false, t: testAnimate },
			'animationDuration': { r: false, t: testAnimationDuration },
			'range': { r: true, t: testRange },
			'orientation': { r: false, t: testOrientation },
			'margin': { r: false, t: testMargin },
			'limit': { r: false, t: testLimit },
			'padding': { r: false, t: testPadding },
			'behaviour': { r: true, t: testBehaviour },
			'format': { r: false, t: testFormat },
			'tooltips': { r: false, t: testTooltips },
			'cssPrefix': { r: false, t: testCssPrefix },
			'cssClasses': { r: false, t: testCssClasses },
			'useRequestAnimationFrame': { r: false, t: testUseRaf }
		};

		var defaults = {
			'connect': false,
			'direction': 'ltr',
			'behaviour': 'tap',
			'orientation': 'horizontal',
			'cssPrefix' : 'noUi-',
			'cssClasses': {
				target: 'target',
				base: 'base',
				origin: 'origin',
				handle: 'handle',
				horizontal: 'horizontal',
				vertical: 'vertical',
				background: 'background',
				connect: 'connect',
				ltr: 'ltr',
				rtl: 'rtl',
				draggable: 'draggable',
				drag: 'state-drag',
				tap: 'state-tap',
				active: 'active',
				tooltip: 'tooltip',
				pips: 'pips',
				pipsHorizontal: 'pips-horizontal',
				pipsVertical: 'pips-vertical',
				marker: 'marker',
				markerHorizontal: 'marker-horizontal',
				markerVertical: 'marker-vertical',
				markerNormal: 'marker-normal',
				markerLarge: 'marker-large',
				markerSub: 'marker-sub',
				value: 'value',
				valueHorizontal: 'value-horizontal',
				valueVertical: 'value-vertical',
				valueNormal: 'value-normal',
				valueLarge: 'value-large',
				valueSub: 'value-sub'
			},
			'useRequestAnimationFrame': true
		};

		// Run all options through a testing mechanism to ensure correct
		// input. It should be noted that options might get modified to
		// be handled properly. E.g. wrapping integers in arrays.
		Object.keys(tests).forEach(function( name ){

			// If the option isn't set, but it is required, throw an error.
			if ( options[name] === undefined && defaults[name] === undefined ) {

				if ( tests[name].r ) {
					throw new Error("noUiSlider: '" + name + "' is required.");
				}

				return true;
			}

			tests[name].t( parsed, options[name] === undefined ? defaults[name] : options[name] );
		});

		// Forward pips options
		parsed.pips = options.pips;

		var styles = [['left', 'top'], ['right', 'bottom']];

		// Pre-define the styles.
		parsed.style = styles[parsed.dir][parsed.ort];
		parsed.styleOposite = styles[parsed.dir?0:1][parsed.ort];

		return parsed;
	}
<|endoftext|>


<commit_before>const Product = function () {
  this.id
  this.name
  this.quantity
  this.price
  this.isPerItem
	this.priceUn
  this.total
}

Product.prototype.setName = function (name) {
  this.name = name
  return this
}
Product.prototype._stringToFloat = function (value) {
  return parseFloat(value)
}

Product.prototype.setQuantity = function (quantity) {
  this.quantity = this._stringToFloat(quantity)
  return this
}
Product.prototype.setPrice = function (price) {
  this.price = this._stringToFloat(price)
  return this
}
Product.prototype.calculateMethod = function (isPerItem) {
  this.isPerItem = isPerItem
  return this
}
Product.prototype.calculateTotal = function () {
  this._validateInformations()

  if (this.isPerItem) {
		this.total = this._parseDecimal(this.quantity*this.price)
		this.priceUn = this.price
  } else {
    this.total = this.price
    this.priceUn = this._parseDecimal(this.total / this.quantity)
  }

  return this
}
Product.prototype._parseDecimal = function (value) {
  return this._stringToFloat(value.toFixed(2))
}
Product.prototype._validateInformations = function () {
  let error = ''
  if (!this.name) {
    error = 'Name needs to be defined'
  } else if (!this.price) {
    error = 'Price needs to be defined'
  } else if (!this.quantity) {
    error = 'Quantity needs to be defined'
  } else if (!this.isPerItem) {
    if (typeof this.isPerItem !== 'boolean') {
      error = 'Calculate method must be a boolean.'
    }else if (this.isPerItem === undefined || this.isPerItem === null) {
      error = 'Calculate Method (isPerItem) needs to be defined'
    }
  } else if (isNaN(this.price)) {
    error = `Price must be a valide number (int or float)`
  } else if (isNaN(this.quantity)) {
    error = `Quantity must be a valide number (int or float).`
  }
  if (error) {
    throw new Error(error)
  }
  return true
}
Product.prototype.setId = function (id) {
  if (id) {
    this.id = parseInt(id)
  }else {
    this._generateId()
  }
  return this
}
Product.prototype._generateId = function () {
  this.id = new Date().getTime() + Math.floor(Math.random() * 100000000)
  return this
}
Product.prototype.getInnerHTML = function () {
  if (this._validateInformations()) {
    return `
        <label class="checkbox product-list__item" data-id="${this.id}">
                        <input type="checkbox">
                            ${this.quantity}x - ${this.name} - € ${this.total} ${this.quantity > 1
            ? `(€ ${this.priceUn} each)`
            : ''}
                        </input>
        </label>
    `
  }
}
<commit_msg>Product now have a toString method to copy content<commit_after>const Product = function () {
  this.id
  this.name
  this.quantity
  this.price
  this.isPerItem
	this.priceUn
  this.total
}

Product.prototype.setName = function (name) {
  this.name = name
  return this
}
Product.prototype._stringToFloat = function (value) {
  return parseFloat(value)
}

Product.prototype.setQuantity = function (quantity) {
  this.quantity = this._stringToFloat(quantity)
  return this
}
Product.prototype.setPrice = function (price) {
  this.price = this._stringToFloat(price)
  return this
}
Product.prototype.calculateMethod = function (isPerItem) {
  this.isPerItem = isPerItem
  return this
}
Product.prototype.calculateTotal = function () {
  this._validateInformations()

  if (this.isPerItem) {
		this.total = this._parseDecimal(this.quantity*this.price)
		this.priceUn = this.price
  } else {
    this.total = this.price
    this.priceUn = this._parseDecimal(this.total / this.quantity)
  }

  return this
}
Product.prototype._parseDecimal = function (value) {
  return this._stringToFloat(value.toFixed(2))
}
Product.prototype._validateInformations = function () {
  let error = ''
  if (!this.name) {
    error = 'Name needs to be defined'
  } else if (!this.price) {
    error = 'Price needs to be defined'
  } else if (!this.quantity) {
    error = 'Quantity needs to be defined'
  } else if (!this.isPerItem) {
    if (typeof this.isPerItem !== 'boolean') {
      error = 'Calculate method must be a boolean.'
    }else if (this.isPerItem === undefined || this.isPerItem === null) {
      error = 'Calculate Method (isPerItem) needs to be defined'
    }
  } else if (isNaN(this.price)) {
    error = `Price must be a valide number (int or float)`
  } else if (isNaN(this.quantity)) {
    error = `Quantity must be a valide number (int or float).`
  }
  if (error) {
    throw new Error(error)
  }
  return true
}
Product.prototype.setId = function (id) {
  if (id) {
    this.id = parseInt(id)
  }else {
    this._generateId()
  }
  return this
}
Product.prototype._generateId = function () {
  this.id = new Date().getTime() + Math.floor(Math.random() * 100000000)
  return this
}
Product.prototype.getInnerHTML = function () {
  if (this._validateInformations()) {
    return `
        <label class="checkbox product-list__item" data-id="${this.id}">
                        <input type="checkbox">
                            ${this.toString()}
                        </input>
        </label>
    `
  }
}
Product.prototype.toString = function(){
	return `${this.quantity}x - ${this.name} - € ${this.total} ${this.quantity > 1
            ? `(€ ${this.priceUn} each)`
            : ''}`
}
<|endoftext|>