<commit_before>'use strict';

(function(window, undefined) {
  window.senna = window.senna || {};

  /**
   * Appends a node with text or other nodes.
   * @param {!Node} parent The node to append nodes to.
   * @param {!Node|String} child The thing to append to the parent.
   */
  senna.append = function(parent, child) {
    if (senna.isString(child)) {
      child = senna.buildFragment(child);
    }
    return parent.appendChild(senna.parseScripts(child));
  };

  /**
   * Creates a new function that, when called, has its this keyword set to the
   * provided value, with a given sequence of arguments preceding any provided
   * when the new function is called.
   *
   * Usage:
var fn = bind(myFunction, myObj, 'arg1', 'arg2');
   * fn('arg3', 'arg4');

   *
   * @param {function} fn A function to partially apply.
   * @param {!Object} context Specifies the object which this should point to
   *     when the function is run.
   * @param {...*} var_args Additional arguments that are partially applied to
   *     the function.
   * @return {!Function} A partially-applied form of the function bind() was
   *     invoked as a method of.
   */
  senna.bind = function(fn, context) {
    if (!fn) {
      throw new Error();
    }

    if (Function.prototype.bind) {
      var bind = fn.call.apply(fn.bind, arguments);
      return function() {
        return bind.apply(null, arguments);
      };
    }

    if (arguments.length > 2) {
      var args = Array.prototype.slice.call(arguments, 2);
      return function() {
        var newArgs = Array.prototype.slice.call(arguments);
        Array.prototype.unshift.apply(newArgs, args);
        return fn.apply(context, newArgs);
      };
    } else {
      return function() {
        return fn.apply(context, arguments);
      };
    }
  };

  /**
   * Helper for buildFragment.
   * @param {!Document} doc The document.
   * @param {string} htmlString The HTML string to convert.
   * @return {!Node} The resulting document fragment.
   * @private
   */
  senna.buildFragment = function(htmlString) {
    var tempDiv = document.createElement('div');
    tempDiv.innerHTML = '
' + htmlString;
    tempDiv.removeChild(tempDiv.firstChild);

    var fragment = document.createDocumentFragment();
    while (tempDiv.firstChild) {
      fragment.appendChild(tempDiv.firstChild);
    }
    return fragment;
  };

  /**
   * Debounces function execution.
   * @param {Function} fn
   * @param {Number} delay
   * @return {Function}
   */
  senna.debounce = function(fn, delay, opt_context) {
    var id;
    return function() {
      if (!opt_context) {
        opt_context = this;
      }
      var args = arguments;
      clearTimeout(id);
      id = setTimeout(function() {
        fn.apply(opt_context, args);
      }, delay);
    };
  };

  /**
   * Returns an object based on its fully qualified external name.
   * @param {String} name The fully qualified name.
   * @param {Object=} opt_obj The object within which to look; default is
   *     window.
   * @return {?} The value (object or primitive) or, if not found, null.
   */
  senna.getObjectByName = function(name, opt_obj) {
    var parts = name.split('.');
    var cur = opt_obj || window;
    var part;
    while ((part = parts.shift())) {
      if (senna.isDefAndNotNull(cur[part])) {
        cur = cur[part];
      } else {
        return null;
      }
    }
    return cur;
  };

  /**
   * Evaluates script globally.
   * @param {String} data
   */
  senna.globalEval = function(data) {
    /* jshint evil: true */
    if (data && data.trim()) {
      var evaluator = window.execScript;
      if (!evaluator) {
        evaluator = function(data) {
          window['eval'].call(window, data);
        };
      }
      evaluator(data);
    }
  };

  /**
   * Inherits the prototype methods from one constructor into another.
   *
   * Usage:
   *

   * function ParentClass(a, b) { }
   * ParentClass.prototype.foo = function(a) { }
   *
   * function ChildClass(a, b, c) {
   *   tracking.base(this, a, b);
   * }
   * tracking.inherits(ChildClass, ParentClass);
   *
   * var child = new ChildClass('a', 'b', 'c');
   * child.foo();
   *

   *
   * @param {Function} childCtor Child class.
   * @param {Function} parentCtor Parent class.
   */
  senna.inherits = function(childCtor, parentCtor) {
    function TempCtor() {
    }
    TempCtor.prototype = parentCtor.prototype;
    childCtor.superClass_ = parentCtor.prototype;
    childCtor.prototype = new TempCtor();
    childCtor.prototype.constructor = childCtor;

    /**
     * Calls superclass constructor/method.
     *
     * This function is only available if you use tracking.inherits to express
     * inheritance relationships between classes.
     *
     * @param {!object} me Should always be "this".
     * @param {string} methodName The method name to call. Calling superclass
     *     constructor can be done with the special string 'constructor'.
     * @param {...*} var_args The arguments to pass to superclass
     *     method/constructor.
     * @return {*} The return value of the superclass method/constructor.
     */
    childCtor.base = function(me, methodName) {
      var args = Array.prototype.slice.call(arguments, 2);
      return parentCtor.prototype[methodName].apply(me, args);
    };
  };

  /**
   * Returns true if the specified value is not undefined.
   * @param {?} val Variable to test.
   * @return {boolean} Whether variable is defined.
   */
  senna.isDef = function(val) {
    return val !== undefined;
  };

  /**
   * Returns true if value is not undefined or null.
   * @param {*} val
   * @return {Boolean}
   */
  senna.isDefAndNotNull = function(val) {
    return senna.isDef(val) && !senna.isNull(val);
  };

  /**
   * Returns true if value is a dom element.
   * @param {*} val
   * @return {Boolean}
   */
  senna.isElement = function(val) {
    return typeof val === 'object' && val.nodeType === 1;
  };

  /**
   * Returns true if the specified value is a function.
   * @param {?} val Variable to test.
   * @return {boolean} Whether variable is a function.
   */
  senna.isFunction = function(val) {
    return typeof (val) === 'function';
  };

  /**
   * Returns true if value is null.
   * @param {*} val
   * @return {Boolean}
   */
  senna.isNull = function(val) {
    return val === null;
  };

  /**
   * Returns true if the specified value is an object. This includes arrays
   * and functions.
   * @param {?} val Variable to test.
   * @return {boolean} Whether variable is an object.
   */
  senna.isObject = function(val) {
    var type = typeof val;
    return type === 'object' && val !== null || type === 'function';
  };

  /**
   * Returns true if value is a string.
   * @param {*} val
   * @return {Boolean}
   */
  senna.isString = function(val) {
    return typeof val === 'string';
  };

  /**
   * Check if an element matches a given selector.
   * @param {Event} element
   * @param {String} selector
   * @return {Boolean}
   */
  senna.match = function(element, selector) {
    if (!element || element.nodeType !== 1) {
      return false;
    }

    var p = Element.prototype;
    var m = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || p.oMatchesSelector;
    if (m) {
      return m.call(element, selector);
    }

    var nodes = document.querySelectorAll(selector, element.parentNode);
    for (var i = 0; i < nodes.length; ++i) {
      if (nodes[i] === element) {
        return true;
      }
    }
    return false;
  };

  /**
   * Parses script nodes inside a fragment and sterilizes them setting their types to text/parsed.
   * @param {!Element} frag
   * @return {Element}
   */
  senna.parseScripts = function(frag) {
    var globalEval = function(o) {
      senna.globalEval(o.responseText || o.text || o.textContent || o.innerHTML || '');
    };
    var scripts = Array.prototype.slice.call(frag.querySelectorAll('script'));
    while (scripts.length) {
      var script = scripts.shift();

      // Some browsers evaluates scripts when appended to document. Sterilizes
      // evaluated scripts setting type to text/parsed.
      script.setAttribute('type', 'text/parsed');

      if (script.src) {
        var headers = {
          'Content-Type': 'text/javascript'
        };
        senna.request(script.src, 'GET', headers, null, true).then(globalEval);
      } else {
        senna.async.nextTick(senna.bind(globalEval, null, script));
      }
    }
    return frag;
  };

  /**
   * Removes element from the dom.
   * @param {Element} element
   */
  senna.remove = function(element) {
    if (element.parentNode) {
      element.parentNode.removeChild(element);
    }
  };

  /**
   * Requests the url using XMLHttpRequest.
   * @param {!String} url
   * @param {!String} httpMethod
   * @param {Object=} opt_httpHeaders
   * @param {Number=} opt_timeout
   * @param {Boolean=} opt_sync
   * @return {Promise} Promisified ajax request.
   */
  senna.request = function(url, httpMethod, opt_httpHeaders, opt_timeout, opt_sync) {
    var xhr = new XMLHttpRequest();

    var promise = new senna.Promise(function(resolve, reject) {
      xhr.onload = function() {
        if (xhr.status === 200) {
          resolve(xhr);
          return;
        }
        xhr.onerror();
      };
      xhr.onerror = function() {
        var error = new Error('Request error');
        error.xhr = xhr;
        reject(error);
      };
    }).thenCatch(function(reason) {
      xhr.abort();
      throw reason;
    }).thenAlways(function() {
      clearTimeout(timeout);
    });

    xhr.open(httpMethod, url, !opt_sync);
    if (opt_httpHeaders) {
      for (var i in opt_httpHeaders) {
        xhr.setRequestHeader(i, opt_httpHeaders[i]);
      }
    }
    xhr.send(null);

    if (senna.isDef(opt_timeout)) {
      var timeout = setTimeout(function() {
        promise.cancel('Request timeout');
      }, opt_timeout);
    }

    return promise;
  };

  /**
   * Browser features
   */
  senna.BrowserFeatures = {};
  senna.BrowserFeatures.chrome = navigator.userAgent.indexOf('Chrome') > -1;
  senna.BrowserFeatures.safari = navigator.userAgent.indexOf('Safari') > -1 && !senna.BrowserFeatures.chrome;

  document.addEventListener('DOMContentLoaded', function() {
    /**
     * Data attribute handler.
     * @type {senna.DataAttributeHandler}
     * @default new senna.DataAttributeHandler(document.body)
     */
    senna.dataAttributeHandler = new senna.DataAttributeHandler(document.body);
  });
}(window));
<commit_msg>Adds ability to handle xhr error status - Fixes #50<commit_after>'use strict';

(function(window, undefined) {
  window.senna = window.senna || {};

  /**
   * Appends a node with text or other nodes.
   * @param {!Node} parent The node to append nodes to.
   * @param {!Node|String} child The thing to append to the parent.
   */
  senna.append = function(parent, child) {
    if (senna.isString(child)) {
      child = senna.buildFragment(child);
    }
    return parent.appendChild(senna.parseScripts(child));
  };

  /**
   * Creates a new function that, when called, has its this keyword set to the
   * provided value, with a given sequence of arguments preceding any provided
   * when the new function is called.
   *
   * Usage:
var fn = bind(myFunction, myObj, 'arg1', 'arg2');
   * fn('arg3', 'arg4');

   *
   * @param {function} fn A function to partially apply.
   * @param {!Object} context Specifies the object which this should point to
   *     when the function is run.
   * @param {...*} var_args Additional arguments that are partially applied to
   *     the function.
   * @return {!Function} A partially-applied form of the function bind() was
   *     invoked as a method of.
   */
  senna.bind = function(fn, context) {
    if (!fn) {
      throw new Error();
    }

    if (Function.prototype.bind) {
      var bind = fn.call.apply(fn.bind, arguments);
      return function() {
        return bind.apply(null, arguments);
      };
    }

    if (arguments.length > 2) {
      var args = Array.prototype.slice.call(arguments, 2);
      return function() {
        var newArgs = Array.prototype.slice.call(arguments);
        Array.prototype.unshift.apply(newArgs, args);
        return fn.apply(context, newArgs);
      };
    } else {
      return function() {
        return fn.apply(context, arguments);
      };
    }
  };

  /**
   * Helper for buildFragment.
   * @param {!Document} doc The document.
   * @param {string} htmlString The HTML string to convert.
   * @return {!Node} The resulting document fragment.
   * @private
   */
  senna.buildFragment = function(htmlString) {
    var tempDiv = document.createElement('div');
    tempDiv.innerHTML = '
' + htmlString;
    tempDiv.removeChild(tempDiv.firstChild);

    var fragment = document.createDocumentFragment();
    while (tempDiv.firstChild) {
      fragment.appendChild(tempDiv.firstChild);
    }
    return fragment;
  };

  /**
   * Debounces function execution.
   * @param {Function} fn
   * @param {Number} delay
   * @return {Function}
   */
  senna.debounce = function(fn, delay, opt_context) {
    var id;
    return function() {
      if (!opt_context) {
        opt_context = this;
      }
      var args = arguments;
      clearTimeout(id);
      id = setTimeout(function() {
        fn.apply(opt_context, args);
      }, delay);
    };
  };

  /**
   * Returns an object based on its fully qualified external name.
   * @param {String} name The fully qualified name.
   * @param {Object=} opt_obj The object within which to look; default is
   *     window.
   * @return {?} The value (object or primitive) or, if not found, null.
   */
  senna.getObjectByName = function(name, opt_obj) {
    var parts = name.split('.');
    var cur = opt_obj || window;
    var part;
    while ((part = parts.shift())) {
      if (senna.isDefAndNotNull(cur[part])) {
        cur = cur[part];
      } else {
        return null;
      }
    }
    return cur;
  };

  /**
   * Evaluates script globally.
   * @param {String} data
   */
  senna.globalEval = function(data) {
    /* jshint evil: true */
    if (data && data.trim()) {
      var evaluator = window.execScript;
      if (!evaluator) {
        evaluator = function(data) {
          window['eval'].call(window, data);
        };
      }
      evaluator(data);
    }
  };

  /**
   * Inherits the prototype methods from one constructor into another.
   *
   * Usage:
   *

   * function ParentClass(a, b) { }
   * ParentClass.prototype.foo = function(a) { }
   *
   * function ChildClass(a, b, c) {
   *   tracking.base(this, a, b);
   * }
   * tracking.inherits(ChildClass, ParentClass);
   *
   * var child = new ChildClass('a', 'b', 'c');
   * child.foo();
   *

   *
   * @param {Function} childCtor Child class.
   * @param {Function} parentCtor Parent class.
   */
  senna.inherits = function(childCtor, parentCtor) {
    function TempCtor() {
    }
    TempCtor.prototype = parentCtor.prototype;
    childCtor.superClass_ = parentCtor.prototype;
    childCtor.prototype = new TempCtor();
    childCtor.prototype.constructor = childCtor;

    /**
     * Calls superclass constructor/method.
     *
     * This function is only available if you use tracking.inherits to express
     * inheritance relationships between classes.
     *
     * @param {!object} me Should always be "this".
     * @param {string} methodName The method name to call. Calling superclass
     *     constructor can be done with the special string 'constructor'.
     * @param {...*} var_args The arguments to pass to superclass
     *     method/constructor.
     * @return {*} The return value of the superclass method/constructor.
     */
    childCtor.base = function(me, methodName) {
      var args = Array.prototype.slice.call(arguments, 2);
      return parentCtor.prototype[methodName].apply(me, args);
    };
  };

  /**
   * Returns true if the specified value is not undefined.
   * @param {?} val Variable to test.
   * @return {boolean} Whether variable is defined.
   */
  senna.isDef = function(val) {
    return val !== undefined;
  };

  /**
   * Returns true if value is not undefined or null.
   * @param {*} val
   * @return {Boolean}
   */
  senna.isDefAndNotNull = function(val) {
    return senna.isDef(val) && !senna.isNull(val);
  };

  /**
   * Returns true if value is a dom element.
   * @param {*} val
   * @return {Boolean}
   */
  senna.isElement = function(val) {
    return typeof val === 'object' && val.nodeType === 1;
  };

  /**
   * Returns true if the specified value is a function.
   * @param {?} val Variable to test.
   * @return {boolean} Whether variable is a function.
   */
  senna.isFunction = function(val) {
    return typeof (val) === 'function';
  };

  /**
   * Returns true if value is null.
   * @param {*} val
   * @return {Boolean}
   */
  senna.isNull = function(val) {
    return val === null;
  };

  /**
   * Returns true if the specified value is an object. This includes arrays
   * and functions.
   * @param {?} val Variable to test.
   * @return {boolean} Whether variable is an object.
   */
  senna.isObject = function(val) {
    var type = typeof val;
    return type === 'object' && val !== null || type === 'function';
  };

  /**
   * Returns true if value is a string.
   * @param {*} val
   * @return {Boolean}
   */
  senna.isString = function(val) {
    return typeof val === 'string';
  };

  /**
   * Check if an element matches a given selector.
   * @param {Event} element
   * @param {String} selector
   * @return {Boolean}
   */
  senna.match = function(element, selector) {
    if (!element || element.nodeType !== 1) {
      return false;
    }

    var p = Element.prototype;
    var m = p.matches || p.webkitMatchesSelector || p.mozMatchesSelector || p.msMatchesSelector || p.oMatchesSelector;
    if (m) {
      return m.call(element, selector);
    }

    var nodes = document.querySelectorAll(selector, element.parentNode);
    for (var i = 0; i < nodes.length; ++i) {
      if (nodes[i] === element) {
        return true;
      }
    }
    return false;
  };

  /**
   * Parses script nodes inside a fragment and sterilizes them setting their types to text/parsed.
   * @param {!Element} frag
   * @return {Element}
   */
  senna.parseScripts = function(frag) {
    var globalEval = function(o) {
      senna.globalEval(o.responseText || o.text || o.textContent || o.innerHTML || '');
    };
    var scripts = Array.prototype.slice.call(frag.querySelectorAll('script'));
    while (scripts.length) {
      var script = scripts.shift();

      // Some browsers evaluates scripts when appended to document. Sterilizes
      // evaluated scripts setting type to text/parsed.
      script.setAttribute('type', 'text/parsed');

      if (script.src) {
        var headers = {
          'Content-Type': 'text/javascript'
        };
        senna.request(script.src, 'GET', headers, null, true).then(globalEval);
      } else {
        senna.async.nextTick(senna.bind(globalEval, null, script));
      }
    }
    return frag;
  };

  /**
   * Removes element from the dom.
   * @param {Element} element
   */
  senna.remove = function(element) {
    if (element.parentNode) {
      element.parentNode.removeChild(element);
    }
  };

  /**
   * Requests the url using XMLHttpRequest.
   * @param {!String} url
   * @param {!String} httpMethod
   * @param {Object=} opt_httpHeaders
   * @param {Number=} opt_timeout
   * @param {Boolean=} opt_sync
   * @return {Promise} Promisified ajax request.
   */
  senna.request = function(url, httpMethod, opt_httpHeaders, opt_timeout, opt_sync) {
    var xhr = new XMLHttpRequest();

    var promise = new senna.Promise(function(resolve, reject) {
      xhr.onload = function() {
        if (xhr.status === 200) {
          resolve(xhr);
          return;
        }
        xhr.onerror();
      };
      xhr.onerror = function() {
        var error = new Error('Request error');
        error.xhr = xhr;
        reject(error);
      };
    }).thenCatch(function(reason) {
      throw reason;
    }).thenAlways(function() {
      clearTimeout(timeout);
    });

    xhr.open(httpMethod, url, !opt_sync);
    if (opt_httpHeaders) {
      for (var i in opt_httpHeaders) {
        xhr.setRequestHeader(i, opt_httpHeaders[i]);
      }
    }
    xhr.send(null);

    if (senna.isDef(opt_timeout)) {
      var timeout = setTimeout(function() {
        promise.cancel('Request timeout');
      }, opt_timeout);
    }

    return promise;
  };

  /**
   * Browser features
   */
  senna.BrowserFeatures = {};
  senna.BrowserFeatures.chrome = navigator.userAgent.indexOf('Chrome') > -1;
  senna.BrowserFeatures.safari = navigator.userAgent.indexOf('Safari') > -1 && !senna.BrowserFeatures.chrome;

  document.addEventListener('DOMContentLoaded', function() {
    /**
     * Data attribute handler.
     * @type {senna.DataAttributeHandler}
     * @default new senna.DataAttributeHandler(document.body)
     */
    senna.dataAttributeHandler = new senna.DataAttributeHandler(document.body);
  });
}(window));
<|endoftext|>


<commit_before>goog.provide('lime.events.Drag');

goog.require('goog.events.EventTarget');

lime.events.Drag = function(event,opt_snapToCenter,opt_bounds,opt_targetObject){
    goog.base(this);

    this.target = opt_targetObject || event.targetObject;

    this.x = 0;
    this.y = 0;

    if (!opt_snapToCenter) {
        var centerpos = this.target.localToScreen(new goog.math.Coordinate(0,0));
        this.x = event.screenPosition.x-centerpos.x;
        this.y = event.screenPosition.y-centerpos.y;
    }

    event.swallow(['touchmove', 'mousemove'],goog.bind(this.moveHandler_,this));
    event.swallow(['touchend', 'touchcancel', 'mouseup'],goog.bind(this.releaseHandler_,this));

    this.setBounds(opt_bounds || null);

    this.dispatchEvent(new goog.events.Event(lime.events.Drag.Event.START));

}
goog.inherits(lime.events.Drag,goog.events.EventTarget);

lime.events.Drag.Event = {
    START   : 'start',
    END     : 'end',
    MOVE    : 'move',
    CHANGE  : 'change',
    DROP    : 'drop'
};

lime.events.Drag.prototype.disposeInternal = function() {
    goog.base(this,'disposeInternal');
    this.event_ = null;
    this.target = null;
};

lime.events.Drag.prototype.getBounds = function(){
    return this.bounds_;
}

lime.events.Drag.prototype.setBounds = function(bounds){
    this.bounds_ = bounds;
}

lime.events.Drag.prototype.moveHandler_ = function(e){
    var pos = e.screenPosition.clone();

    pos.x -= this.x;
    pos.y -= this.y;
    pos = this.target.getParent().screenToLocal(pos);

    var box = this.getBounds();

    if (goog.isDefAndNotNull(box)) {
        //todo: this can be optimized

        /*
        //thinking again testing with bounding box may be actually wrong
        var s = obj.size_, a = obj.anchorPoint_,p = this.position_;
        var rr = new goog.math.Rect(
                    p.x-s.width*a.x,
                    p.y-s.height*a.y ,
                    size.width, size.height
                );

        if(rr.left<box.left) rr.left=box.left;
        if(rr.top<box.top) rr.top=box.top;

        if(rr.left+s.width>box.right) bb.left=box.right-s.width;
        if(rr.top+s.height>box.bottom) bb.top=box.bottom-s.height;

        pos.x = rr.left+s.width*a.x;
        pos.y = rr.top+s.height*a.y;
        */

        //point version
        if (pos.x < box.left) pos.x = box.left;
        else if (pos.x > box.right) pos.x = box.right;

        if (pos.y < box.top) pos.y = box.top;
        else if (pos.y > box.bottom) pos.y = box.bottom;

    }

    this.target.setPosition(pos);

    this.dispatchEvent(new goog.events.Event(lime.events.Drag.Event.MOVE));
}

lime.events.Drag.prototype.releaseHandler_ = function(e){

    this.dispatchEvent(new goog.events.Event(lime.events.Drag.Event.END));

}

<commit_msg>Basic drop targets support<commit_after>goog.provide('lime.events.Drag');

goog.require('goog.events.EventTarget');
goog.require('lime.animation.MoveTo');

lime.events.Drag = function(event,opt_snapToCenter,opt_bounds,opt_targetObject){
    goog.base(this);

    this.target = opt_targetObject || event.targetObject;

    this.dropTargets_ = [];
    this.dropIndex_ = -1;

    this.x = 0;
    this.y = 0;

    if (!opt_snapToCenter) {
        var centerpos = this.target.localToScreen(new goog.math.Coordinate(0,0));
        this.x = event.screenPosition.x-centerpos.x;
        this.y = event.screenPosition.y-centerpos.y;
    }

    event.swallow(['touchmove', 'mousemove'],goog.bind(this.moveHandler_,this));
    event.swallow(['touchend', 'touchcancel', 'mouseup'],goog.bind(this.releaseHandler_,this));

    this.setBounds(opt_bounds || null);

    this.dispatchEvent(new goog.events.Event(lime.events.Drag.Event.START));

}
goog.inherits(lime.events.Drag,goog.events.EventTarget);

lime.events.Drag.Event = {
    START   : 'start',
    END     : 'end',
    MOVE    : 'move',
    CHANGE  : 'change',
    DROP    : 'drop',
    CANCEL  : 'cancel'
};

lime.events.Drag.prototype.disposeInternal = function() {
    goog.base(this,'disposeInternal');
    this.event_ = null;
    this.target = null;
    this.dropTargets_ = null;
};

lime.events.Drag.prototype.getBounds = function(){
    return this.bounds_;
}

lime.events.Drag.prototype.setBounds = function(bounds){
    this.bounds_ = bounds;
}

lime.events.Drag.prototype.moveHandler_ = function(e){
    var pos = e.screenPosition.clone();

    pos.x -= this.x;
    pos.y -= this.y;
    pos = this.target.getParent().screenToLocal(pos);

    var box = this.getBounds();

    if (goog.isDefAndNotNull(box)) {
        //todo: this can be optimized

        /*
        //thinking again testing with bounding box may be actually wrong
        var s = obj.size_, a = obj.anchorPoint_,p = this.position_;
        var rr = new goog.math.Rect(
                    p.x-s.width*a.x,
                    p.y-s.height*a.y ,
                    size.width, size.height
                );

        if(rr.left<box.left) rr.left=box.left;
        if(rr.top<box.top) rr.top=box.top;

        if(rr.left+s.width>box.right) bb.left=box.right-s.width;
        if(rr.top+s.height>box.bottom) bb.top=box.bottom-s.height;

        pos.x = rr.left+s.width*a.x;
        pos.y = rr.top+s.height*a.y;
        */

        //point version
        if (pos.x < box.left) pos.x = box.left;
        else if (pos.x > box.right) pos.x = box.right;

        if (pos.y < box.top) pos.y = box.top;
        else if (pos.y > box.bottom) pos.y = box.bottom;

    }

    this.target.setPosition(pos);

    this.dispatchEvent(new goog.events.Event(lime.events.Drag.Event.MOVE));

    var sel = -1;
    var currect = goog.math.Rect.createFromBox(this.target.getFrame());
    var results = [];
    for(var i=0;i<this.dropTargets_.length;i++){
        var loc = this.dropTargets_[i];
        var dropFrame = loc.getFrame();
        var tl = loc.localToNode(new goog.math.Coordinate(dropFrame.left,dropFrame.top),this.target);
        var br = loc.localToNode(new goog.math.Coordinate(dropFrame.right,dropFrame.bottom),this.target);
        var droprect = goog.math.Rect.createFromBox(new goog.math.Box(tl.y,br.x,br.y,tl.x));
        var intersection;

        if(intersection = goog.math.Rect.intersection(currect,droprect)){
            results.push([intersection.width*intersection.height/(droprect.width*droprect.height),i]);
        }
    }

    if(results.length){

        results = results.sort(function(a,b){b[0]-a[0]});
        sel = results[0][1];
   }

   if(sel!=this.dropIndex_){
        if(this.dropIndex_!=-1){
            if(goog.isFunction(this.dropTargets_[this.dropIndex_].hideDropHightLight)){
                this.dropTargets_[this.dropIndex_].hideDropHightLight();
            }
        }
        this.dropIndex_ = sel;
        if(this.dropIndex_!=-1){
            if(goog.isFunction(this.dropTargets_[this.dropIndex_].hideDropHightLight)){
                this.dropTargets_[this.dropIndex_].hideDropHightLight();
            }
        }

        var ev = new goog.events.Event(lime.events.Drag.Event.CHANGE);
        ev.activeDropTarget = this.dropIndex_ != -1 ? this.dropTargets_[this.dropIndex_] : null;
        this.dispatchEvent(ev);

    }

}

lime.events.Drag.prototype.releaseHandler_ = function(e){

    if(this.dropTargets_.length){

        if(this.dropIndex_!=-1){
            var ev = new goog.events.Event(lime.events.Drag.Event.DROP);
            ev.activeDropTarget = this.dropTargets_[this.dropIndex_];
            this.dispatchEvent(ev);
            if(!ev.propagationStopped_){
                var pos = ev.activeDropTarget.getParent().localToNode(ev.activeDropTarget.getPosition(),this.target.getParent());
                this.target.runAction(new lime.animation.MoveTo(pos.x,pos.y).setDuration(.5).enableOptimizations());
            }
        }
        else {
            this.dispatchEvent(new goog.events.Event(lime.events.Drag.Event.CANCEL));
        }

    }

    this.dispatchEvent(new goog.events.Event(lime.events.Drag.Event.END));

    lime.scheduleManager.callAfter(this.dispose,this,100);

}

lime.events.Drag.prototype.addDropTarget = function(drop){
    this.dropTargets_.push(drop);
}

<|endoftext|>


<commit_before>// update the cookie if it exists, if it doesn't, create a new one, lasting 2 years
Cookie.exists('uid') ? Cookie.set('uid', Cookie.get('uid'), 2*365*24*60) : Cookie.set('uid', Helper.guid(), 2*365*24*60);
// save any utms through as session cookies
Cookie.setUtms();

// process the queue and future incoming commands
pixelFunc.process = function(method, value, optional) {
  if (method === 'init') {
    Config.id = value;
  } else if(method === 'param') {
    Config.params[value] = () => optional
  } else if(method === 'event') {
    if(value === 'pageload' && !Config.pageLoadOnce) {
      Config.pageLoadOnce = true;
      new Pixel(value, pixelFunc.t, optional);
    } else if(value !== 'pageload' && value !== 'pageclose') {
      new Pixel(value, Helper.now(), optional);
    }
  }
}

// run the queued calls from the snippet to be processed
for (var i = 0, l = pixelFunc.queue.length; i < l; i++) {
  pixelFunc.process.apply(pixelFunc, pixelFunc.queue[i]);
}

window.addEventListener('unload', function() {
  if (!Config.pageCloseOnce) {
    Config.pageCloseOnce = true;
    new Pixel('pageclose', Helper.now(), function() {
      // if a link was clicked in the last 5 seconds that goes to an external host, pass it through as event data
      if (Helper.isPresent(Config.externalHost) && (Helper.now() - Config.externalHost.time) < 5*1000) {
        return Config.externalHost.link;
      }
    });
  }
});

window.onload = function() {
  var aTags = document.getElementsByTagName('a');
  for (var i = 0, l = aTags.length; i < l; i++) {
    aTags[i].addEventListener('click', function(_e) {
      if (Url.externalHost(this)) {
        Config.externalHost = { link: this.href, time: Helper.now() };
      }
    }.bind(aTags[i]));
  }

  var dataAttributes = document.querySelectorAll('[data-OPIX_FUNC-event]')
  for (var i = 0, l = dataAttributes.length; i < l; i++) {
    dataAttributes[i].addEventListener('click', function(_e) {
      var event = this.getAttribute('data-OPIX_FUNC-event');
      if (event) {
        new Pixel(event, Helper.now(), this.getAttribute('data-OPIX_FUNC-data'));
      }
    }.bind(dataAttributes[i]));
  }
}
<commit_msg>More accurate page close event handling (#115)<commit_after>// update the cookie if it exists, if it doesn't, create a new one, lasting 2 years
Cookie.exists('uid') ? Cookie.set('uid', Cookie.get('uid'), 2*365*24*60) : Cookie.set('uid', Helper.guid(), 2*365*24*60);
// save any utms through as session cookies
Cookie.setUtms();

// process the queue and future incoming commands
pixelFunc.process = function(method, value, optional) {
  if (method === 'init') {
    Config.id = value;
  } else if(method === 'param') {
    Config.params[value] = () => optional
  } else if(method === 'event') {
    if(value === 'pageload' && !Config.pageLoadOnce) {
      Config.pageLoadOnce = true;
      new Pixel(value, pixelFunc.t, optional);
    } else if(value !== 'pageload' && value !== 'pageclose') {
      new Pixel(value, Helper.now(), optional);
    }
  }
}

// run the queued calls from the snippet to be processed
for (var i = 0, l = pixelFunc.queue.length; i < l; i++) {
  pixelFunc.process.apply(pixelFunc, pixelFunc.queue[i]);
}

// https://github.com/GoogleChromeLabs/page-lifecycle/blob/master/src/Lifecycle.mjs
// Safari does not reliably fire the `pagehide` or `visibilitychange`
var isNotSafari = !(typeof safari === 'object' && safari.pushNotification);
var isPageHideSupported = 'onpageshow' in self;

// IE9-10 do not support the pagehide event, so we fall back to unload
// pagehide event is more reliable but less broad than unload event for mobile and modern browsers
var pageCloseEvent =
  isPageHideSupported && isNotSafari
    ? 'pagehide'
    : 'unload';

window.addEventListener(pageCloseEvent, function() {
  if (!Config.pageCloseOnce) {
    Config.pageCloseOnce = true;
    new Pixel('pageclose', Helper.now(), function() {
      // if a link was clicked in the last 5 seconds that goes to an external host, pass it through as event data
      if (Helper.isPresent(Config.externalHost) && (Helper.now() - Config.externalHost.time) < 5*1000) {
        return Config.externalHost.link;
      }
    });
  }
});

window.onload = function() {
  var aTags = document.getElementsByTagName('a');
  for (var i = 0, l = aTags.length; i < l; i++) {
    aTags[i].addEventListener('click', function(_e) {
      if (Url.externalHost(this)) {
        Config.externalHost = { link: this.href, time: Helper.now() };
      }
    }.bind(aTags[i]));
  }

  var dataAttributes = document.querySelectorAll('[data-OPIX_FUNC-event]')
  for (var i = 0, l = dataAttributes.length; i < l; i++) {
    dataAttributes[i].addEventListener('click', function(_e) {
      var event = this.getAttribute('data-OPIX_FUNC-event');
      if (event) {
        new Pixel(event, Helper.now(), this.getAttribute('data-OPIX_FUNC-data'));
      }
    }.bind(dataAttributes[i]));
  }
}
<|endoftext|>


<commit_before>
import $logger from 'beaver-logger/client';

import { config } from './config';
import { initLogger, checkForCommonErrors } from './lib';
import { enableCheckoutIframe } from './components';
import { setupBridge } from './compat';

function domainToEnv(domain) {
    for (let env of Object.keys(config.paypalUrls)) {
        if (config.paypalUrls[env] === domain) {
            return env;
        }
    }
}

function setDomainEnv(domain) {
    let currentDomainEnv = domainToEnv(domain);

    if (currentDomainEnv && currentDomainEnv !== 'test') {
        config.env = currentDomainEnv;
    }
}

setDomainEnv(`${window.location.protocol}//${window.location.host}`);

initLogger();

export function setup(options = {}) {

    checkForCommonErrors();

    if (options.env) {
        if (!config.paypalUrls[options.env]) {
            throw new Error(`Invalid env: ${options.env}`);
        }

        delete config.env;
        config.env = options.env;
    }

    if (options.stage) {
        delete config.stage;
        config.stage = options.stage;
        if (!options.env) {
            delete config.env;
            config.env = 'stage';
        }
    }

    if (options.apiStage) {
        delete config.apiStage;
        config.apiStage = options.apiStage;
    }

    if (options.paypalUrl) {
        delete config.paypalUrl;
        config.paypalUrl = options.paypalUrl;
        setDomainEnv(config.paypalUrl);
    }

    if (options.state) {
        delete config.state;
        config.state = options.state;
    }

    if (options.ppobjects) {
        config.ppobjects = true;
    }

    if (options.lightbox) {
        enableCheckoutIframe();
    }

    if (options.bridge) {
        setupBridge(config.env, config.bridgeUrl);
    }

    $logger.info(`setup_${config.env}`);
}

function getCurrentScript() {

    let scripts = Array.prototype.slice.call(document.getElementsByTagName('script'));

    for (let script of scripts) {
        if (script.src && script.src.replace(/^https?:/, '').split('?')[0] === config.scriptUrl || script.hasAttribute('data-paypal-checkout')) {
            return script;
        }
    }
}

let currentScript = getCurrentScript();

if (currentScript) {

    setup({
        env:       currentScript.getAttribute('data-env'),
        stage:     currentScript.getAttribute('data-stage'),
        apiStage:  currentScript.getAttribute('data-api-stage'),
        paypalUrl: currentScript.getAttribute('data-paypal-url'),
        state:     currentScript.getAttribute('data-state'),
        lightbox:  currentScript.hasAttribute('data-enable-lightbox'),
        bridge:    currentScript.hasAttribute('data-enable-bridge'),
        ppobjects: true
    });

} else {
    $logger.debug(`no_current_script`);
}
<commit_msg>Make setup callable once only<commit_after>
import $logger from 'beaver-logger/client';

import { config } from './config';
import { initLogger, checkForCommonErrors, once } from './lib';
import { enableCheckoutIframe } from './components';
import { setupBridge } from './compat';

function domainToEnv(domain) {
    for (let env of Object.keys(config.paypalUrls)) {
        if (config.paypalUrls[env] === domain) {
            return env;
        }
    }
}

function setDomainEnv(domain) {
    let currentDomainEnv = domainToEnv(domain);

    if (currentDomainEnv && currentDomainEnv !== 'test') {
        config.env = currentDomainEnv;
    }
}

setDomainEnv(`${window.location.protocol}//${window.location.host}`);

initLogger();

export let setup = once(function setup(options = {}) {

    checkForCommonErrors();

    if (options.env) {
        if (!config.paypalUrls[options.env]) {
            throw new Error(`Invalid env: ${options.env}`);
        }

        delete config.env;
        config.env = options.env;
    }

    if (options.stage) {
        delete config.stage;
        config.stage = options.stage;
        if (!options.env) {
            delete config.env;
            config.env = 'stage';
        }
    }

    if (options.apiStage) {
        delete config.apiStage;
        config.apiStage = options.apiStage;
    }

    if (options.paypalUrl) {
        delete config.paypalUrl;
        config.paypalUrl = options.paypalUrl;
        setDomainEnv(config.paypalUrl);
    }

    if (options.state) {
        delete config.state;
        config.state = options.state;
    }

    if (options.ppobjects) {
        config.ppobjects = true;
    }

    if (options.lightbox) {
        enableCheckoutIframe();
    }

    if (options.bridge) {
        setupBridge(config.env, config.bridgeUrl);
    }

    $logger.info(`setup_${config.env}`);
});

function getCurrentScript() {

    let scripts = Array.prototype.slice.call(document.getElementsByTagName('script'));

    for (let script of scripts) {
        if (script.src && script.src.replace(/^https?:/, '').split('?')[0] === config.scriptUrl || script.hasAttribute('data-paypal-checkout')) {
            return script;
        }
    }
}

let currentScript = getCurrentScript();

if (currentScript) {

    setup({
        env:       currentScript.getAttribute('data-env'),
        stage:     currentScript.getAttribute('data-stage'),
        apiStage:  currentScript.getAttribute('data-api-stage'),
        paypalUrl: currentScript.getAttribute('data-paypal-url'),
        state:     currentScript.getAttribute('data-state'),
        lightbox:  currentScript.hasAttribute('data-enable-lightbox'),
        bridge:    currentScript.hasAttribute('data-enable-bridge'),
        ppobjects: true
    });

} else {
    $logger.debug(`no_current_script`);
}
<|endoftext|>


<commit_before>// Base object for different progress bar shapes

var Path = require('./path');
var utils = require('./utils');

var DESTROYED_ERROR = 'Object is destroyed';

var Shape = function Shape(container, opts) {
    // Throw a better error if progress bars are not initialized with `new`
    // keyword
    if (!(this instanceof Shape)) {
        throw new Error('Constructor was called without new keyword');
    }

    // Prevent calling constructor without parameters so inheritance
    // works correctly. To understand, this is how Shape is inherited:
    //
    //   Line.prototype = new Shape();
    //
    // We just want to set the prototype for Line.
    if (arguments.length === 0) return;

    // Default parameters for progress bar creation
    this._opts = utils.extend({
        color: '#555',
        strokeWidth: 1.0,
        trailColor: null,
        trailWidth: null,
        fill: null,
        text: {
            autoStyle: true,
            color: null,
            value: '',
            className: 'progressbar-text'
        }
    }, opts, true);  // Use recursive extend

    var svgView = this._createSvgView(this._opts);

    var element;
    if (utils.isString(container)) {
        element = document.querySelector(container);
    } else {
        element = container;
    }

    if (!element) {
        throw new Error('Container does not exist: ' + container);
    }

    this._container = element;
    this._container.appendChild(svgView.svg);

    this.text = null;
    if (this._opts.text.value) {
        this.text = this._createTextElement(this._opts, this._container);
        this._container.appendChild(this.text);
    }

    // Expose public attributes before Path initialization
    this.svg = svgView.svg;
    this.path = svgView.path;
    this.trail = svgView.trail;
    // this.text is also a public attribute

    var newOpts = utils.extend({
        attachment: this
    }, this._opts);
    this._progressPath = new Path(svgView.path, newOpts);
};

Shape.prototype.animate = function animate(progress, opts, cb) {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);
    this._progressPath.animate(progress, opts, cb);
};

Shape.prototype.stop = function stop() {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);
    this._progressPath.stop();
};

Shape.prototype.destroy = function destroy() {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);

    this.stop();
    this.svg.parentNode.removeChild(this.svg);
    this.svg = null;
    this.path = null;
    this.trail = null;
    this._progressPath = null;

    if (this.text !== null) {
        this.text.parentNode.removeChild(this.text);
        this.text = null;
    }
};

Shape.prototype.set = function set(progress) {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);
    this._progressPath.set(progress);
};

Shape.prototype.value = function value() {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);
    return this._progressPath.value();
};

Shape.prototype.setText = function setText(text) {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);

    if (this.text === null) {
        // Create new text node
        this.text = this._createTextElement(this._opts, this._container);
        this._container.appendChild(this.text);
    } else {
        // Remove previous text node
        this.text.removeChild(this.text.firstChild);
    }

    this.text.appendChild(document.createTextNode(text));
};

Shape.prototype._createSvgView = function _createSvgView(opts) {
    var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    this._initializeSvg(svg, opts);

    var trailPath = null;
    // Each option listed in the if condition are 'triggers' for creating
    // the trail path
    if (opts.trailColor || opts.trailWidth) {
        trailPath = this._createTrail(opts);
        svg.appendChild(trailPath);
    }

    var path = this._createPath(opts);
    svg.appendChild(path);

    return {
        svg: svg,
        path: path,
        trail: trailPath
    };
};

Shape.prototype._initializeSvg = function _initializeSvg(svg, opts) {
    svg.setAttribute('viewBox', '0 0 100 100');
};

Shape.prototype._createPath = function _createPath(opts) {
    var pathString = this._pathString(opts);
    return this._createPathElement(pathString, opts);
};

Shape.prototype._createTrail = function _createTrail(opts) {
    // Create path string with original passed options
    var pathString = this._trailString(opts);

    // Prevent modifying original
    var newOpts = utils.extend({}, opts);

    // Defaults for parameters which modify trail path
    if (!newOpts.trailColor) newOpts.trailColor = '#eee';
    if (!newOpts.trailWidth) newOpts.trailWidth = newOpts.strokeWidth;

    newOpts.color = newOpts.trailColor;
    newOpts.strokeWidth = newOpts.trailWidth;

    // When trail path is set, fill must be set for it instead of the
    // actual path to prevent trail stroke from clipping
    newOpts.fill = null;

    return this._createPathElement(pathString, newOpts);
};

Shape.prototype._createPathElement = function _createPathElement(pathString, opts) {
    var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    path.setAttribute('d', pathString);
    path.setAttribute('stroke', opts.color);
    path.setAttribute('stroke-width', opts.strokeWidth);

    if (opts.fill) {
        path.setAttribute('fill', opts.fill);
    } else {
        path.setAttribute('fill-opacity', '0');
    }

    return path;
};

Shape.prototype._createTextElement = function _createTextElement(opts, container) {
    var element = document.createElement('p');
    element.appendChild(document.createTextNode(opts.text.value));

    if (opts.text.autoStyle) {
        // Center text
        container.style.position = 'relative';
        element.style.position = 'absolute';
        element.style.top = '50%';
        element.style.left = '50%';
        element.style.padding = 0;
        element.style.margin = 0;
        utils.setStyle(element, 'transform', 'translate(-50%, -50%');

        if (opts.text.color) {
            element.style.color = opts.text.color;
        } else {
            element.style.color = opts.color;
        }
    }
    element.className = opts.text.className;

    return element;
};

Shape.prototype._pathString = function _pathString(opts) {
    throw new Error('Override this function for each progress bar');
};

Shape.prototype._trailString = function _trailString(opts) {
    throw new Error('Override this function for each progress bar');
};

module.exports = Shape;
<commit_msg>Fix syntax error in CSS translate to fix text centering issue. Fixes #41<commit_after>// Base object for different progress bar shapes

var Path = require('./path');
var utils = require('./utils');

var DESTROYED_ERROR = 'Object is destroyed';

var Shape = function Shape(container, opts) {
    // Throw a better error if progress bars are not initialized with `new`
    // keyword
    if (!(this instanceof Shape)) {
        throw new Error('Constructor was called without new keyword');
    }

    // Prevent calling constructor without parameters so inheritance
    // works correctly. To understand, this is how Shape is inherited:
    //
    //   Line.prototype = new Shape();
    //
    // We just want to set the prototype for Line.
    if (arguments.length === 0) return;

    // Default parameters for progress bar creation
    this._opts = utils.extend({
        color: '#555',
        strokeWidth: 1.0,
        trailColor: null,
        trailWidth: null,
        fill: null,
        text: {
            autoStyle: true,
            color: null,
            value: '',
            className: 'progressbar-text'
        }
    }, opts, true);  // Use recursive extend

    var svgView = this._createSvgView(this._opts);

    var element;
    if (utils.isString(container)) {
        element = document.querySelector(container);
    } else {
        element = container;
    }

    if (!element) {
        throw new Error('Container does not exist: ' + container);
    }

    this._container = element;
    this._container.appendChild(svgView.svg);

    this.text = null;
    if (this._opts.text.value) {
        this.text = this._createTextElement(this._opts, this._container);
        this._container.appendChild(this.text);
    }

    // Expose public attributes before Path initialization
    this.svg = svgView.svg;
    this.path = svgView.path;
    this.trail = svgView.trail;
    // this.text is also a public attribute

    var newOpts = utils.extend({
        attachment: this
    }, this._opts);
    this._progressPath = new Path(svgView.path, newOpts);
};

Shape.prototype.animate = function animate(progress, opts, cb) {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);
    this._progressPath.animate(progress, opts, cb);
};

Shape.prototype.stop = function stop() {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);
    this._progressPath.stop();
};

Shape.prototype.destroy = function destroy() {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);

    this.stop();
    this.svg.parentNode.removeChild(this.svg);
    this.svg = null;
    this.path = null;
    this.trail = null;
    this._progressPath = null;

    if (this.text !== null) {
        this.text.parentNode.removeChild(this.text);
        this.text = null;
    }
};

Shape.prototype.set = function set(progress) {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);
    this._progressPath.set(progress);
};

Shape.prototype.value = function value() {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);
    return this._progressPath.value();
};

Shape.prototype.setText = function setText(text) {
    if (this._progressPath === null) throw new Error(DESTROYED_ERROR);

    if (this.text === null) {
        // Create new text node
        this.text = this._createTextElement(this._opts, this._container);
        this._container.appendChild(this.text);
    } else {
        // Remove previous text node
        this.text.removeChild(this.text.firstChild);
    }

    this.text.appendChild(document.createTextNode(text));
};

Shape.prototype._createSvgView = function _createSvgView(opts) {
    var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    this._initializeSvg(svg, opts);

    var trailPath = null;
    // Each option listed in the if condition are 'triggers' for creating
    // the trail path
    if (opts.trailColor || opts.trailWidth) {
        trailPath = this._createTrail(opts);
        svg.appendChild(trailPath);
    }

    var path = this._createPath(opts);
    svg.appendChild(path);

    return {
        svg: svg,
        path: path,
        trail: trailPath
    };
};

Shape.prototype._initializeSvg = function _initializeSvg(svg, opts) {
    svg.setAttribute('viewBox', '0 0 100 100');
};

Shape.prototype._createPath = function _createPath(opts) {
    var pathString = this._pathString(opts);
    return this._createPathElement(pathString, opts);
};

Shape.prototype._createTrail = function _createTrail(opts) {
    // Create path string with original passed options
    var pathString = this._trailString(opts);

    // Prevent modifying original
    var newOpts = utils.extend({}, opts);

    // Defaults for parameters which modify trail path
    if (!newOpts.trailColor) newOpts.trailColor = '#eee';
    if (!newOpts.trailWidth) newOpts.trailWidth = newOpts.strokeWidth;

    newOpts.color = newOpts.trailColor;
    newOpts.strokeWidth = newOpts.trailWidth;

    // When trail path is set, fill must be set for it instead of the
    // actual path to prevent trail stroke from clipping
    newOpts.fill = null;

    return this._createPathElement(pathString, newOpts);
};

Shape.prototype._createPathElement = function _createPathElement(pathString, opts) {
    var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    path.setAttribute('d', pathString);
    path.setAttribute('stroke', opts.color);
    path.setAttribute('stroke-width', opts.strokeWidth);

    if (opts.fill) {
        path.setAttribute('fill', opts.fill);
    } else {
        path.setAttribute('fill-opacity', '0');
    }

    return path;
};

Shape.prototype._createTextElement = function _createTextElement(opts, container) {
    var element = document.createElement('p');
    element.appendChild(document.createTextNode(opts.text.value));

    if (opts.text.autoStyle) {
        // Center text
        container.style.position = 'relative';
        element.style.position = 'absolute';
        element.style.top = '50%';
        element.style.left = '50%';
        element.style.padding = 0;
        element.style.margin = 0;
        utils.setStyle(element, 'transform', 'translate(-50%, -50%)');

        if (opts.text.color) {
            element.style.color = opts.text.color;
        } else {
            element.style.color = opts.color;
        }
    }
    element.className = opts.text.className;

    return element;
};

Shape.prototype._pathString = function _pathString(opts) {
    throw new Error('Override this function for each progress bar');
};

Shape.prototype._trailString = function _trailString(opts) {
    throw new Error('Override this function for each progress bar');
};

module.exports = Shape;
<|endoftext|>


<commit_before>(function() {
  const CTRL_ATTR = 'data-controller';
  const MODEL_ATTR = 'data-model';

  let self = {}

  window.sixth = self;

  let utils = {
    isUndefined: (value) => typeof value === 'undefined',
    isDefined: (value) => typeof value !== 'undefined'
  }
  /**
   * Work in progress
   */
  class Scope {
    constructor(){}

    getModel() {
      return Object.keys(this)
        .reduce((mappedData, key) => {
          mappedData[key] = [];

          return mappedData
        }, {});
    }
  };

  /**
   * Controller class that bind model and view
   */
  class Controller {
    constructor(name, callback) {
      this.ctrlName = name;
      this.isBinded = false;

      this.scope = new Proxy(new Scope(),{
        set: (model, property, value) => {
          let oldValue = model[property];

          if(oldValue === value) return true;

          model[property] = value;

          this.isBinded && this.render(property, value)

          return true;
        }
      });

      this.callback = callback;
      this.ctrlElement = document.querySelector(`[${CTRL_ATTR}=${name}]`);
      this.bindModel();
    }

    /**
     * Sort each element with data-model attribut to it model in scope
     * @returns {*}
     */
    bindModel(){
      let domElements = this.ctrlElement.querySelectorAll(`[${MODEL_ATTR}]`);

      this.callback.call(this.scope);
      this.modelView = this.scope.getModel();

      for(let key in domElements) {
        let element = domElements[key];

        if(!element.tagName) return;

        let name = element.getAttribute(MODEL_ATTR);

        if(!this.modelView.hasOwnProperty(name)) return;

        this.modelView[name].push(element);

        if (utils.isDefined(element.value)) {
          let event = this.getEvent(this.scope, element.type, name);

          element.addEventListener(event.name, event.fn, false);
        }

        this.isBinded = true;
        this.render(name, this.scope[name]);
      }
    };

    getEvent(scope, type, name) {
      let setValue = function(event) {
        this.isTouched = true;
        scope[name] = event.target.value;
      }

      let eventsTypes = {
        'default': () => ({
          name: 'keyup',
          fn: setValue
        }),
        'checkbox': () => ({
          name: 'change',
          fn: function(event) {
            this.isTouched = true;
            scope[name] = event.target.checked;
          }
        }),
        'radio': () => ({
          name: 'change',
          fn: setValue
        }),
        'select-one': () => ({
          name: 'change',
          fn: setValue
        })
      }

      return eventsTypes.hasOwnProperty(type)
        ? eventsTypes[type]()
        : eventsTypes.default();

    };

    //TODO: Need to add support for change and click, and also for select tag,
    // and check the checkbox, it doesn't work properly

    render(name, value) {
      let elementsType = {
        checkbox: (element, value) => {
          element.setAttribute('checked', !!value);
        },
        radio: (element, value) => {
          if (element.value === value && !element.checked) {
            element.setAttribute('checked', true);
          }
        },
        default: (element, value) => {
          element.value = value;
        }
      };

      this.modelView[name].forEach((element) => {

        try {
          if (utils.isDefined(element.value)) {

            if(element.isTouched) return element.isTouched = false;

            elementsType[element.type]
              ? elementsType[element.type](element, value)
              : elementsType.default(element, value);

          } else {
            element.innerHTML = value;
          }

        } catch (error) {
          console.log(error)
        }

      });
    }
  };

  self.controller = function(name, callback) {
    let ctrl = new Controller(name, callback);

    console.log('ctrl', ctrl)
  }

})();<commit_msg>changes in the  way it render<commit_after>(function() {
  const CTRL_ATTR = 'data-controller';
  const MODEL_ATTR = 'data-model';

  let self = {}

  window.sixth = self;

  let utils = {
    isUndefined: (value) => typeof value === 'undefined',
    isDefined: (value) => typeof value !== 'undefined'
  }
  /**
   * Work in progress
   */
  class Scope {
    constructor(){}

    getModel() {
      return Object.keys(this)
        .reduce((mappedData, key) => {
          mappedData[key] = [];

          return mappedData
        }, {});
    }
  };

  /**
   * Controller class that bind model and view
   */
  class Controller {
    constructor(name, callback) {
      this.ctrlName = name;
      this.isBinded = false;
      this.callback = callback;
      this.ctrlElement = document.querySelector(`[${CTRL_ATTR}=${name}]`);
      this.bindElements();
    }

    bindModel(scope) {
      console.log('scope', scope)
      this.scope = new Proxy(scope,{
        set: (model, property, value) => {
          let oldValue = model[property];
          console.log('render')
          if(oldValue === value) return true;

          model[property] = value;

          this.render(property, value)

          return true;
        }
      });
    }
    /**
     * Sort each element with data-model attribut to it model in scope
     * @returns {*}
     */
    bindElements(){
      let domElements = this.ctrlElement.querySelectorAll(`[${MODEL_ATTR}]`)
        , scope = new Scope();

      this.callback.call(scope);
      this.modelView = scope.getModel();

      this.bindModel(scope);

      for(let key in domElements) {
        let element = domElements[key];

        if(!element.tagName) return;

        let name = element.getAttribute(MODEL_ATTR);

        if(!this.modelView.hasOwnProperty(name)) return;

        this.modelView[name].push(element);

        if (utils.isDefined(element.value)) {
          let event = this.getEvent(this.scope, element.type, name);

          element.addEventListener(event.name, event.fn, false);
        }

        this.render(name, this.scope[name]);
      }
    };

    getEvent(scope, type, name) {
      let setValue = function(event) {
        this.isTouched = true;
        scope[name] = event.target.value;
      };

      let eventsTypes = {
        'default': () => ({
          name: 'keyup',
          fn: setValue
        }),
        'checkbox': () => ({
          name: 'change',
          fn: function(event) {
            this.isTouched = true;
            scope[name] = event.target.checked;
          }
        }),
        'radio': () => ({
          name: 'change',
          fn: setValue
        }),
        'select-one': () => ({
          name: 'change',
          fn: setValue
        })
      }

      return eventsTypes.hasOwnProperty(type)
        ? eventsTypes[type]()
        : eventsTypes.default();

    };

    //TODO: Need to add support for change and click, and also for select tag,
    // and check the checkbox, it doesn't work properly

    render(name, value) {
      let elementsType = {
        checkbox: (element, value) => {
          console.log('value', !!value)
          element.setAttribute('checked', value);
        },
        radio: (element, value) => {
          if (element.value === value && !element.checked) {
            element.setAttribute('checked', true);
          }
        },
        default: (element, value) => {
          element.value = value;
        }
      };

      this.modelView[name].forEach((element) => {

        try {
          if (utils.isDefined(element.value)) {

            if(element.isTouched) return element.isTouched = false;

            elementsType[element.type]
              ? elementsType[element.type](element, value)
              : elementsType.default(element, value);

          } else {
            element.innerHTML = value;
          }

        } catch (error) {
          console.log(error)
        }

      });
    }
  };

  self.controller = function(name, callback) {
    let ctrl = new Controller(name, callback);

    console.log('ctrl', ctrl)
  }

})();<|endoftext|>


<commit_before>class Space {
  constructor(iterable) {
    if (!iterable) {
      throw new Error();
    }
    this.table = new Map(iterable);
  }

  toString() {
    let object = Object.create(null);
    for (let [key, value] of this.table) {
      object[key] = value;
    }
    return JSON.stringify(object);
  }

  isValid() {
    return false;
  }

  clone() {
    throw new Error("clone() is not implemented");
  }

  get(key) {
    return this.table.get(key);
  }

  set(key, value) {
    return this.table.set(key, value);
  }

  getOrSet(key, value = null) {
    if (value == null) {
      return this.get(key);
    }
    this.set(key, value);
    return this;
  }

  values() {
    return this.table.values();
  }
}

export class Rgb extends Space {
  static KEY_R = "r";
  static KEY_G = "g";
  static KEY_B = "b";

  constructor(r, g, b) {
    super([[Rgb.KEY_R, r], [Rgb.KEY_G, g], [Rgb.KEY_B, b]]);
  }

  toString() {
    return `rgb(${this.r()}, ${this.g()}, ${this.b()})`;
  }

  isValid() {
    let values = this.values();
    for (let value of values) {
      if (value < 0x00 || value > 0xFF) {
        return false;
      }
    }
    return true;
  }

  clone() {
    return new Rgb(this.r(), this.g(), this.b());
  }

  r(value = null) {
    return this.getOrSet(Rgb.KEY_R, value);
  }

  g(value = null) {
    return this.getOrSet(Rgb.KEY_G, value);
  }

  b(value = null) {
    return this.getOrSet(Rgb.KEY_B, value);
  }

  hsl() {
    let r = this.r() / 0xFF;
    let g = this.g() / 0xFF;
    let b = this.b() / 0xFF;

    let max   = Math.max(r, g, b);
    let min   = Math.min(r, g, b);
    let delta = max - min;
    if (delta === 0) {
      return new Hsl(0, 0, max);
    }

    let h = 0;
    if (max === r) {
      h = 60 * ((g - b) / delta % 360);
    } else if (max === g) {
      h = 60 * ((b - r) / delta + 2);
    } else if (max === b) {
      h = 60 * ((r - g) / delta + 4);
    }

    let l = (max + min) / 2;

    let s = delta / (1 - Math.abs(2 * l - 1))

    return new Hsl(h, s, l);
  }
}

export class Hsl extends Space {
  static KEY_H = "h";
  static KEY_S = "s";
  static KEY_L = "l";

  constructor(h, s, l) {
    super([[Hsl.KEY_H, h], [Hsl.KEY_S, s], [Hsl.KEY_L, l]]);
  }

  toString() {
    return `hsl(${this.h()}, ${this.s()}%, ${this.l()}%)`;
  }

  clone() {
    return new Hsl(this.h(), this.s(), this.l());
  }

  isValid() {
    let h = this.h();
    if (!Number.isFinite(h) || h < 0 || h > 360) {
      return false;
    }

    let s = this.s();
    if (!Number.isFinite(s) || s < 0 || s > 100) {
      return false;
    }

    let l = this.l();
    if (!Number.isFinite(l) || l < 0 || l > 100) {
      return false;
    }
    return true;
  }

  h(value = null) {
    return this.getOrSet(Hsl.KEY_H, value);
  }

  s(value = null) {
    return this.getOrSet(Hsl.KEY_S, value);
  }

  l(value = null) {
    return this.getOrSet(Hsl.KEY_L, value);
  }
}
<commit_msg>Added a conversion method that converts color space from hsl to rgb<commit_after>class Space {
  constructor(iterable) {
    if (!iterable) {
      throw new Error();
    }
    this.table = new Map(iterable);
  }

  toString() {
    let object = Object.create(null);
    for (let [key, value] of this.table) {
      object[key] = value;
    }
    return JSON.stringify(object);
  }

  isValid() {
    return false;
  }

  clone() {
    throw new Error("clone() is not implemented");
  }

  get(key) {
    return this.table.get(key);
  }

  set(key, value) {
    return this.table.set(key, value);
  }

  getOrSet(key, value = null) {
    if (value == null) {
      return this.get(key);
    }
    this.set(key, value);
    return this;
  }

  values() {
    return this.table.values();
  }
}

export class Rgb extends Space {
  static KEY_R = "r";
  static KEY_G = "g";
  static KEY_B = "b";

  constructor(r, g, b) {
    super([[Rgb.KEY_R, r], [Rgb.KEY_G, g], [Rgb.KEY_B, b]]);
  }

  toString() {
    return `rgb(${this.r()}, ${this.g()}, ${this.b()})`;
  }

  isValid() {
    let values = this.values();
    for (let value of values) {
      if (value < 0x00 || value > 0xFF) {
        return false;
      }
    }
    return true;
  }

  clone() {
    return new Rgb(this.r(), this.g(), this.b());
  }

  r(value = null) {
    return this.getOrSet(Rgb.KEY_R, value);
  }

  g(value = null) {
    return this.getOrSet(Rgb.KEY_G, value);
  }

  b(value = null) {
    return this.getOrSet(Rgb.KEY_B, value);
  }

  hsl() {
    let r = this.r() / 0xFF;
    let g = this.g() / 0xFF;
    let b = this.b() / 0xFF;

    let max   = Math.max(r, g, b);
    let min   = Math.min(r, g, b);
    let delta = max - min;
    if (delta === 0) {
      return new Hsl(0, 0, max);
    }

    let h = 0;
    if (max === r) {
      h = 60 * ((g - b) / delta % 360);
    } else if (max === g) {
      h = 60 * ((b - r) / delta + 2);
    } else if (max === b) {
      h = 60 * ((r - g) / delta + 4);
    }

    let l = (max + min) / 2;

    let s = delta / (1 - Math.abs(2 * l - 1))

    return new Hsl(h, s, l);
  }
}

export class Hsl extends Space {
  static KEY_H = "h";
  static KEY_S = "s";
  static KEY_L = "l";

  constructor(h, s, l) {
    super([[Hsl.KEY_H, h], [Hsl.KEY_S, s], [Hsl.KEY_L, l]]);
  }

  toString() {
    return `hsl(${this.h()}, ${this.s()}%, ${this.l()}%)`;
  }

  clone() {
    return new Hsl(this.h(), this.s(), this.l());
  }

  isValid() {
    let h = this.h();
    if (!Number.isFinite(h) || h < 0 || h > 360) {
      return false;
    }

    let s = this.s();
    if (!Number.isFinite(s) || s < 0 || s > 100) {
      return false;
    }

    let l = this.l();
    if (!Number.isFinite(l) || l < 0 || l > 100) {
      return false;
    }
    return true;
  }

  h(value = null) {
    return this.getOrSet(Hsl.KEY_H, value);
  }

  s(value = null) {
    return this.getOrSet(Hsl.KEY_S, value);
  }

  l(value = null) {
    return this.getOrSet(Hsl.KEY_L, value);
  }

  rgb() {
    let h = this.h();
    let s = this.s();
    let l = this.l();
    if (s === 0) {
      let value = Math.round(l * 0xFF);
      return new Rgb(value, value, value);
    }

    let m2 = 0;
    if (l < 0.5) {
      m2 = l * (s + 1);
    } else {
      m2 = l + s - l * s;
    }

    let m1 = 2 * l - m2;
    let r = Math.round(255 * Hsl.hueToRgb(m1, m2, h / 360 + 1 / 3));
    let g = Math.round(255 * Hsl.hueToRgb(m1, m2, h / 360));
    let b = Math.round(255 * Hsl.hueToRgb(m1, m2, h / 360 - 1 / 3));
    return new Rgb(r, g, b)
  }

  static hueToRgb(m1, m2, h) {
    if (h < 0) {
      h += 1;
    } else if (h > 1) {
      h -= 1;
    }

    if (h * 6 < 1) {
      return m1 + (m2 - m1) * h * 6;
    } else if (h * 2 < 1) {
      return m2;
    } else if (h * 3 < 2) {
      return m1 + (m2 - m1) * (2 / 3 - h) * 6;
    }
    return m1;
  }
}
<|endoftext|>


<commit_before>// @flow

import events from './events/event';
import eventProps from './events/event-props';

import {
  isElement,
  hasKeys,
  matchAndAddition,
  mergeArrayObjects
} from './utils/helpers.utils';

import { position } from './utils/position.utils';

/**
 * Fire path callback function if its defined otherwise take the path
 * object/array and return it as an increment
 *
 * @param {Function} path
 * @param {Event} event
**/
const handlePathObj = (
  path: Function | Object,
  event: MouseEvent | TouchEvent | KeyboardEvent,
  EventObject: Array<string>,
  newIndex: number
): Object => {
  if (typeof path === 'function') {
    return path(event);
  } else if (typeof path === 'object' && !Array.isArray(path) && path) {
    return EventObject.reduce(matchAndAddition(path, event), {});
  } else if (typeof path === 'object' && Array.isArray(path) && path) {
    return EventObject.reduce(matchAndAddition(path[newIndex], event), {});
  }
  return {};
};

/**
 * Recursive function to be called as many times as we defined the steps count
 *
 * @param {Array} instances
 * @param {Integer} index
 * @param {Object} options
**/
const caller = (
  instances: Function,
  index: number,
  options: Object,
): Event | Function => {
  // at the moment we are only calling the first event,
  // but lets start prepare the api for managin an array of events
  return instances(options)
  .then(({event, eventName}) => {
    const shouldExit = (typeof options.tick === 'function') ?
      options.tick(event) :
      false;

    const newIndex = index + 1;
    // if we havent reached the end of our cycle return a new caller
    // otherwise just exit the recursive function
    const eventObj = eventProps[eventName];
    return (newIndex >= options.steps || shouldExit) ? event :
    caller(
      instances,
      newIndex,
      Object.assign({}, options, handlePathObj(options.path, event, eventObj, newIndex))
    );
  });
};

/**
 * Load Instance, works as fire but waiths for the spray method to call it.
 *
 * @param {String} eventName
 * @param {String} triggerName
 * @param {Node} element
 * @param {Object} options
**/
export const load = (
  eventName: string = 'MouseEvent',
  triggerName: string = 'click',
  element: HTMLElement | Document = document,
  ...rest: Array<Object>
): Function => {
  return (opt: Object = {}) => {
    return new Promise((resolve) => {
      setTimeout(() => {
        const options = rest.reduce(mergeArrayObjects, {});
        // If we pass an element but without specifying its positoin we need
        // to calculate clientX and clientY relative to passed element
        if (isElement(element) && !hasKeys(options, 'clientX', 'clientY')) {
          Object.assign(options, position(element));
        }

        const combinedOpts = Object.assign({}, options, opt);
        const event = events(eventName)(triggerName, element, combinedOpts);
        element.dispatchEvent(event);
        resolve({
          event,
          eventName
        });
      }, opt.speed || 0);
    });
  };
};

/**
 * Spray method.
 *
 * @param {Function, Array} instance
 * @param {Object} options
**/
export const spray = (instance: Function, options: Object = {
  speed: 100,
  steps: 10,
  path: null,
  tick: null,
}): Event => {
  return caller(instance, 0, options);
};
<commit_msg>add current index as argument to tick and path methods in spray<commit_after>// @flow

import events from './events/event';
import eventProps from './events/event-props';

import {
  isElement,
  hasKeys,
  matchAndAddition,
  mergeArrayObjects
} from './utils/helpers.utils';

import { position } from './utils/position.utils';

/**
 * Fire path callback function if its defined otherwise take the path
 * object/array and return it as an increment
 *
 * @param {Function} path
 * @param {Event} event
**/
const handlePathObj = (
  path: Function | Object,
  event: MouseEvent | TouchEvent | KeyboardEvent,
  EventObject: Array<string>,
  newIndex: number
): Object => {
  if (typeof path === 'function') {
    return path(event, newIndex);
  } else if (typeof path === 'object' && !Array.isArray(path) && path) {
    return EventObject.reduce(matchAndAddition(path, event), {});
  } else if (typeof path === 'object' && Array.isArray(path) && path) {
    return EventObject.reduce(matchAndAddition(path[newIndex], event), {});
  }
  return {};
};

/**
 * Recursive function to be called as many times as we defined the steps count
 *
 * @param {Array} instances
 * @param {Integer} index
 * @param {Object} options
**/
const caller = (
  instances: Function,
  index: number,
  options: Object,
): Event | Function => {
  // at the moment we are only calling the first event,
  // but lets start prepare the api for managin an array of events
  return instances(options)
  .then(({event, eventName}) => {
    const shouldExit = (typeof options.tick === 'function') ?
      options.tick(event, index) :
      false;

    const newIndex = index + 1;
    // if we havent reached the end of our cycle return a new caller
    // otherwise just exit the recursive function
    const eventObj = eventProps[eventName];
    return (newIndex >= options.steps || shouldExit) ? event :
    caller(
      instances,
      newIndex,
      Object.assign({}, options, handlePathObj(options.path, event, eventObj, newIndex))
    );
  });
};

/**
 * Load Instance, works as fire but waiths for the spray method to call it.
 *
 * @param {String} eventName
 * @param {String} triggerName
 * @param {Node} element
 * @param {Object} options
**/
export const load = (
  eventName: string = 'MouseEvent',
  triggerName: string = 'click',
  element: HTMLElement | Document = document,
  ...rest: Array<Object>
): Function => {
  return (opt: Object = {}) => {
    return new Promise((resolve) => {
      setTimeout(() => {
        const options = rest.reduce(mergeArrayObjects, {});
        // If we pass an element but without specifying its positoin we need
        // to calculate clientX and clientY relative to passed element
        if (isElement(element) && !hasKeys(options, 'clientX', 'clientY')) {
          Object.assign(options, position(element));
        }

        const combinedOpts = Object.assign({}, options, opt);
        const event = events(eventName)(triggerName, element, combinedOpts);
        element.dispatchEvent(event);
        resolve({
          event,
          eventName
        });
      }, opt.speed || 0);
    });
  };
};

/**
 * Spray method.
 *
 * @param {Function, Array} instance
 * @param {Object} options
**/
export const spray = (instance: Function, options: Object = {
  speed: 100,
  steps: 10,
  path: null,
  tick: null,
}): Event => {
  return caller(instance, 0, options);
};
<|endoftext|>


<commit_before>/**
 * Stack
 * notation key
 * a                    = function 'a'
 * [a]                  = an instance of Stack with the function 'a'
 * <action> => <result> = a transformation of the Stack/Stack sequence
 * <action> // <result> = a return value
 * <action> || <result> = the effect of the <action>
 * [a,b,c]              = an array of functions 'a', 'b', 'c'
 * [identity]            = an instance of Stack with 'identity' function
 * [a[b]]               = an instance of Stack with function 'a' and a next [b]
 * [a[b[c]]]            = an instance of Stack with the head [a] and tail [c]
 * {x}                  = some value x
 * [{x},{y}]            = an array of values {x} and {y}
 * a(x)                 = function 'a' invoked with argument {x}
 * a(x, y)              = function 'a' invoked with arguments {x} and {y}
 * ?                    = an object
 * &&                   = logical and
 */
(function(global, undef) {
    function merge(a, b) {
        Array.prototype.push.apply(a, b);
        return a;
    }
    function makeArray(val) {
        return Array.isArray(val) ? val : val ? [val] : [];
    }
    function identity() {
        return arguments.length > 1 ? arguments : arguments[0];
    }
    function trampoline(fn) {
        return function () {
            var bounce = fn.apply(this, arguments);
            while (typeof bounce === "function") {
                bounce = bounce();
            }
            return bounce;
        };
    }
    function recur(matcher, transformer) {
        return trampoline(function recurring() {
            var self = this;
            var args = arguments;
            return function () {
                return matcher.apply(self, args) && self ||
                    self.next && recurring.apply(self.next, transformer ? transformer.apply(this, args) : args);
            };
        });
    }
    function iterate(action, accumulator, limit) {
        return trampoline(function iterating() {
            var self = this;
            var args = arguments;
            return function () {
                var val = action.apply(self, args);
                if (limit && limit.call(self, val)) {
                    return val;
                }
                return self.next ? iterating.apply(self.next, accumulator ? accumulator.apply(self, merge([val], args)) : args) : val;
            };
        });
    }
    /**
     * Stack
     * Stack() => [identity] // [identity]
     * Stack(a) => [a] // [a]
     * Stack([a,b,c]) => [c[b[a]]] // [c[b[a]]]
     * Stack(a, [b]) => [a[b]] // [a[b]]
     * @param fn {Function|Array}
     * @param [next {Stack}]
     * @returns {Stack}
     * @constructor
     */
    function Stack(fn, next) {
        var arr;
        if (Array.isArray(fn)) {
            arr = fn.slice(0);
            return arr.reduce(function (stack, f) {
                return stack.push(f);
            }, new Stack(arr.shift()));
        }
        if (!(this instanceof Stack)) {
            return new Stack(fn, next);
        }
        this.fn = fn || identity;
        this.next = next || undef;
    }

    /**
     * mung
     * @param prop
     * @param rename
     * @static
     * @returns Stack
     */
    Stack.mung = function (prop, rename) {
        this.prototype[rename] = this.prototype[prop];
        return this;
    };
    /**
     * push
     * [a].push(b) => [b[a]].push(c) => [c[b[a]]] // [c[b[a]]]
     * @param fn {Function}
     * @returns {Stack}
     */
    Stack.prototype.push = function(fn) {
        return new Stack(fn, this);
    };
    /**
     * insert
     * [a].insert(b) => [a[b]] // [b].insert(c) => [a[b[c]]] // [c]
     * @param fn
     * @returns {Stack}
     */
    Stack.prototype.insert = function (fn) {
        return this.next = new Stack(fn, this.next);
    };
    /**
     * index
     * [a[b[c]]].index(1) // [b]
     * @param idx
     * @returns {Stack|undefined}
     */
    Stack.prototype.index = recur(function (i) {
        return i===0;
    }, function (i) {
        i--;
        return arguments;
    });

    /**
     * priorNext
     * [a[b[c[d]]]].priorNext([d]) // [b]
     * @param [stack]
     * @returns {Stack|undefined}
     */
    Stack.prototype.priorNext = recur(function (stack) {
        return this.next && this.next.next === stack;
    });
    /**
     * priorFn
     * [a[b[c]]].priorFn(b) // [a]
     * @param fn
     * @returns {Stack|undefined}
     */
    Stack.prototype.priorFn = recur(function (fn) {
        return this.next && this.next.fn === fn;
    });
    /**
     * isNext
     * [a[b]].isNext([b]) // true
     * @param stack
     * @returns {boolean}
     */
    Stack.prototype.isNext = function (stack) {
        return this.next === stack;
    };
    /**
     * isFn
     * [a].isFn(a) // true
     * @param fn
     * @returns {boolean}
     */
    Stack.prototype.isFn = function (fn) {
        return this.fn === fn;
    };
    /**
     * searchNext
     * [a[b[c]]].searchNext([c]) // [b[c]]
     * @param [stack]
     * @returns {Stack|undefined}
     */
    Stack.prototype.searchNext = recur(Stack.prototype.isNext);
    /**
     * searchFn
     * [a[b[c]]].searchFn(b) // [b]
     * @param fn
     * @returns {Stack|undefined}
     */
    Stack.prototype.searchFn = recur(Stack.prototype.isFn);
    /**
     * distribute
     * [a[b[c]]].distribute({x}) || a(x), b(x), c(x)
     * [a[b[c]]].distribute({x}, ?) || ?.a(x), ?.b(x), ?.c(x)
     * @param arg
     * @param receiver
     * @returns {undefined}
     */
    Stack.prototype.distribute = iterate(function (arg, receiver) {
        this.fn.call(receiver || self, arg);
    });
    /**
     * distributeAll
     * [a[b[c]]].distribute([{x},{y},{z}]) || a(x,y,z), b(x,y,z), c(x,y,z)
     * [a[b[c]]].distribute([{x},{y},{z}], ?) || ?.a(x,y,z), ?.b(x,y,z), ?.c(x,y,z)
     * @param args
     * @param receiver
     * @returns {undefined}
     */
    Stack.prototype.distributeAll = iterate(function (args, receiver) {
        this.fn.apply(receiver || self, args);
    });
    /**
     * call
     * [a[b[c]]].call({x}) // c(b(a(x)))
     * [a[b[c]]].call({x}, ?) // ?.c(?.b(?.a(x)))
     * @param arg
     * @param receiver
     * @returns {*}
     */
    Stack.prototype.call = iterate(function (arg, receiver) {
        return this.fn.call(receiver || this, arg);
    }, function (val, arg, receiver) {
        return [val, receiver];
    });
    /**
     * apply
     * [a[b[c]]].apply([{x},{y},{z}]) // c(b(a(x,y,z)))
     * [a[b[c]]].apply([{x},{y},{z}], ?) // ?.c(?.b(?.a(x,y,z)))
     * @param args
     * @param receiver
     * @returns {*}
     */
    Stack.prototype.apply = iterate(function (args, receiver) {
        return this.fn.apply(receiver || this, args);
    }, function (val, args, receiver) {
        return [makeArray(val), receiver];
    });
    /**
     * clone
     * [a[b[c]]].clone() // [a[b[c]]]
     * [a[b[c]]].clone(d) // [d[b[c]]]
     * [a[b[c]]].clone(null, [d]) // [a[d]]
     * [a[b[c]]].clone(d, [e]) // [d[e]]
     * @param fn
     * @param next
     * @returns {Stack}
     */
    Stack.prototype.clone = function (fn, next) {
        return new Stack(fn || this.fn, next || this.next);
    };
    /**
     * tail
     * [a[b[c]]].tail() // [c]
     * @returns {Stack|undefined}
     */
    Stack.prototype.tail = function () {
        return this.searchNext();
    };
    /**
     * unshift
     * [a[b]].unshift(c) => [a[b[c]]] // [c]
     * @param fn
     * @returns {Stack}
     */
    Stack.prototype.unshift = function (fn) {
        return this.tail().insert(fn);
    };
    /**
     * before
     * [a[b[c]]].before(b, d) => [a[d[b[c]]]] // [d[b[c]]]
     * @param a
     * @param b
     * @returns {Stack}
     */
    Stack.prototype.beforeFn = function (a, b) {
        return (this.searchFn(a || undef) || this).insert(b);
    };
    /**
     * after
     * [a[b[c]]].after(b, d) => [a[b[d[c]]]] // [b[d[c]]]
     * @param a
     * @param b
     * @returns {Stack}
     */
    Stack.prototype.before = function (a, b) {
        return (this.searchFn(a || undef) || this).insert(b);
    };
    /**
     * shift
     * [a[b[c]]].shift() => [a[b]] // [c]
     * @returns {Stack}
     */
    Stack.prototype.shift = function () {
        var p = this.priorNext();
        var removed = p.next;
        p.next = undef;
        return removed;
    };
    /**
     * [a[b[c]]].pop() => [a], [b[c]] // [a]
     * @returns {Stack}
     */
    Stack.prototype.pop = function () {
        this.next = undef;
        return this;
    };
    /**
     * some
     * [a[b[c]]].some() || !c() && !b() && !c() // true|false
     * [a[b[c]]].some({x}) || !c(x) && !b(x) && !c(x) // true|false
     * @param arg
     * @param receiver
     * @returns {boolean}
     */
    Stack.prototype.some = iterate(function (arg, receiver) {
        return this.fn.call(receiver || self, arg);
    }, null, function (val) {
        return val;
    });
    /**
     * every
     * [a[b[c]]].every() || c() && b() && c() // true|false
     * [a[b[c]]].every({x}) || c(x) && b(x) && c(x) // true|false
     * @param arg
     * @param receiver
     * @returns {boolean}
     */
    Stack.prototype.every = iterate(function (arg, receiver) {
        return this.fn.call(receiver || this, arg);
    }, null, function (val) {
        return !val;
    });
    /**
     * [a].push(b) = [a].after(b) = [a].composedWith(b) => [b[a]] // [b[a]]
     * [a].insert(b) = [a].before(b) = [a].then(b) => [a[b]] // [b]
     * [a[b]].isNext([b]) = [a[b]].composes([b]) // true
     * [a].isFn(a) = [a].with(a) = [a].uses(a) // true
     * [a[b]].searchNext([b]) =
     */
    Stack.mung("push", "of")
        .mung("insert", "to")
        .mung("insert", "compose");

//        .mung("isNext", "follows")
//        .mung("isFn", "with")
//        .mung("isFn", "uses")
//        .mung("searchNext", "of")
//        .mung("searchFn", "using")
//        .mung("priorNext", "previousActsOn")
//        .mung("priorFn", "composedWith");

    global.Stack = Stack;
}(this));
<commit_msg>Update stack.js<commit_after>/**
 * Stack
 * notation key
 * a                    = function 'a'
 * [a]                  = an instance of Stack with the function 'a'
 * <action> => <result> = a transformation of the Stack/Stack sequence
 * <action> // <result> = a return value
 * <action> || <result> = the effect of the <action>
 * [a,b,c]              = an array of functions 'a', 'b', 'c'
 * [identity]            = an instance of Stack with 'identity' function
 * [a[b]]               = an instance of Stack with function 'a' and a next [b]
 * [a[b[c]]]            = an instance of Stack with the head [a] and tail [c]
 * {x}                  = some value x
 * [{x},{y}]            = an array of values {x} and {y}
 * a(x)                 = function 'a' invoked with argument {x}
 * a(x, y)              = function 'a' invoked with arguments {x} and {y}
 * ?                    = an object
 * &&                   = logical and
 */
(function(global, undef) {
    function merge(a, b) {
        Array.prototype.push.apply(a, b);
        return a;
    }
    function makeArray(val) {
        return Array.isArray(val) ? val : val ? [val] : [];
    }
    function identity() {
        return arguments.length > 1 ? arguments : arguments[0];
    }
    function trampoline(fn) {
        return function () {
            var bounce = fn.apply(this, arguments);
            while (typeof bounce === "function") {
                bounce = bounce();
            }
            return bounce;
        };
    }
    function recur(matcher, transformer) {
        return trampoline(function recurring() {
            var self = this;
            var args = arguments;
            return function () {
                return matcher.apply(self, args) && self ||
                    self.next && recurring.apply(self.next, transformer ? transformer.apply(this, args) : args);
            };
        });
    }
    function iterate(action, accumulator, limit) {
        return trampoline(function iterating() {
            var self = this;
            var args = arguments;
            return function () {
                var val = action.apply(self, args);
                if (limit && limit.call(self, val)) {
                    return val;
                }
                return self.next ? iterating.apply(self.next, accumulator ? accumulator.apply(self, merge([val], args)) : args) : val;
            };
        });
    }
    /**
     * Stack
     * Stack() => [identity] // [identity]
     * Stack(a) => [a] // [a]
     * Stack([a,b,c]) => [c[b[a]]] // [c[b[a]]]
     * Stack(a, [b]) => [a[b]] // [a[b]]
     * @param fn {Function|Array}
     * @param [next {Stack}]
     * @returns {Stack}
     * @constructor
     */
    function Stack(fn, next) {
        var arr;
        if (Array.isArray(fn)) {
            arr = fn.slice(0);
            return arr.reduce(function (stack, f) {
                return stack.push(f);
            }, new Stack(arr.shift()));
        }
        if (!(this instanceof Stack)) {
            return new Stack(fn, next);
        }
        this.fn = fn || identity;
        this.next = next || undef;
    }

    /**
     * mung
     * @param prop
     * @param rename
     * @static
     * @returns Stack
     */
    Stack.mung = function (prop, rename) {
        this.prototype[rename] = this.prototype[prop];
        return this;
    };
    /**
     * push
     * [a].push(b) => [b[a]].push(c) => [c[b[a]]] // [c[b[a]]]
     * @param fn {Function}
     * @returns {Stack}
     */
    Stack.prototype.push = function(fn) {
        return new Stack(fn, this);
    };
    /**
     * insert
     * [a].insert(b) => [a[b]] // [b].insert(c) => [a[b[c]]] // [c]
     * @param fn
     * @returns {Stack}
     */
    Stack.prototype.insert = function (fn) {
        return this.next = new Stack(fn, this.next);
    };
    /**
     * index
     * [a[b[c]]].index(1) // [b]
     * @param idx
     * @returns {Stack|undefined}
     */
    Stack.prototype.index = recur(function (i) {
        return i===0;
    }, function (i) {
        i--;
        return arguments;
    });

    /**
     * priorNext
     * [a[b[c[d]]]].priorNext([d]) // [b]
     * @param [stack]
     * @returns {Stack|undefined}
     */
    Stack.prototype.priorNext = recur(function (stack) {
        return this.next && this.next.next === stack;
    });
    /**
     * priorFn
     * [a[b[c]]].priorFn(b) // [a]
     * @param fn
     * @returns {Stack|undefined}
     */
    Stack.prototype.priorFn = recur(function (fn) {
        return this.next && this.next.fn === fn;
    });
    /**
     * isNext
     * [a[b]].isNext([b]) // true
     * @param stack
     * @returns {boolean}
     */
    Stack.prototype.isNext = function (stack) {
        return this.next === stack;
    };
    /**
     * isFn
     * [a].isFn(a) // true
     * @param fn
     * @returns {boolean}
     */
    Stack.prototype.isFn = function (fn) {
        return this.fn === fn;
    };
    /**
     * searchNext
     * [a[b[c]]].searchNext([c]) // [b[c]]
     * @param [stack]
     * @returns {Stack|undefined}
     */
    Stack.prototype.searchNext = recur(Stack.prototype.isNext);
    /**
     * searchFn
     * [a[b[c]]].searchFn(b) // [b]
     * @param fn
     * @returns {Stack|undefined}
     */
    Stack.prototype.searchFn = recur(Stack.prototype.isFn);
    /**
     * distribute
     * [a[b[c]]].distribute({x}) || a(x), b(x), c(x)
     * [a[b[c]]].distribute({x}, ?) || ?.a(x), ?.b(x), ?.c(x)
     * @param arg
     * @param receiver
     * @returns {undefined}
     */
    Stack.prototype.distribute = iterate(function (arg, receiver) {
        this.fn.call(receiver || self, arg);
    });
    /**
     * distributeAll
     * [a[b[c]]].distribute([{x},{y},{z}]) || a(x,y,z), b(x,y,z), c(x,y,z)
     * [a[b[c]]].distribute([{x},{y},{z}], ?) || ?.a(x,y,z), ?.b(x,y,z), ?.c(x,y,z)
     * @param args
     * @param receiver
     * @returns {undefined}
     */
    Stack.prototype.distributeAll = iterate(function (args, receiver) {
        this.fn.apply(receiver || self, args);
    });
    /**
     * call
     * [a[b[c]]].call({x}) // c(b(a(x)))
     * [a[b[c]]].call({x}, ?) // ?.c(?.b(?.a(x)))
     * @param arg
     * @param receiver
     * @returns {*}
     */
    Stack.prototype.call = iterate(function (arg, receiver) {
        return this.fn.call(receiver || this, arg);
    }, function (val, arg, receiver) {
        return [val, receiver];
    });
    /**
     * apply
     * [a[b[c]]].apply([{x},{y},{z}]) // c(b(a(x,y,z)))
     * [a[b[c]]].apply([{x},{y},{z}], ?) // ?.c(?.b(?.a(x,y,z)))
     * @param args
     * @param receiver
     * @returns {*}
     */
    Stack.prototype.apply = iterate(function (args, receiver) {
        return this.fn.apply(receiver || this, args);
    }, function (val, args, receiver) {
        return [makeArray(val), receiver];
    });
    /**
     * clone
     * [a[b[c]]].clone() // [a[b[c]]]
     * [a[b[c]]].clone(d) // [d[b[c]]]
     * [a[b[c]]].clone(null, [d]) // [a[d]]
     * [a[b[c]]].clone(d, [e]) // [d[e]]
     * @param fn
     * @param next
     * @returns {Stack}
     */
    Stack.prototype.clone = function (fn, next) {
        return new Stack(fn || this.fn, next || this.next);
    };
    /**
     * tail
     * [a[b[c]]].tail() // [c]
     * @returns {Stack|undefined}
     */
    Stack.prototype.tail = function () {
        return this.searchNext();
    };
    /**
     * unshift
     * [a[b]].unshift(c) => [a[b[c]]] // [c]
     * @param fn
     * @returns {Stack}
     */
    Stack.prototype.unshift = function (fn) {
        return this.tail().insert(fn);
    };
    /**
     * before
     * [a[b[c]]].before(b, d) => [a[d[b[c]]]] // [d[b[c]]]
     * @param a
     * @param b
     * @returns {Stack}
     */
    Stack.prototype.beforeFn = function (a, b) {
        return (this.searchFn(a || undef) || this).insert(b);
    };
    /**
     * after
     * [a[b[c]]].after(b, d) => [a[b[d[c]]]] // [b[d[c]]]
     * @param a
     * @param b
     * @returns {Stack}
     */
    Stack.prototype.before = function (a, b) {
        return (this.searchFn(a || undef) || this).insert(b);
    };
    /**
     * shift
     * [a[b[c]]].shift() => [a[b]] // [c]
     * @returns {Stack}
     */
    Stack.prototype.shift = function () {
        var p = this.priorNext();
        var removed = p.next;
        p.next = undef;
        return removed;
    };
    /**
     * [a[b[c]]].pop() => [a], [b[c]] // [a]
     * @returns {Stack}
     */
    Stack.prototype.pop = function () {
        this.next = undef;
        return this;
    };
    /**
     * some
     * [a[b[c]]].some() || !c() && !b() && !c() // true|false
     * [a[b[c]]].some({x}) || !c(x) && !b(x) && !c(x) // true|false
     * @param arg
     * @param receiver
     * @returns {boolean}
     */
    Stack.prototype.some = iterate(function (arg, receiver) {
        return this.fn.call(receiver || self, arg);
    }, null, function (val) {
        return val;
    });
    /**
     * every
     * [a[b[c]]].every() || c() && b() && c() // true|false
     * [a[b[c]]].every({x}) || c(x) && b(x) && c(x) // true|false
     * @param arg
     * @param receiver
     * @returns {boolean}
     */
    Stack.prototype.every = iterate(function (arg, receiver) {
        return this.fn.call(receiver || this, arg);
    }, null, function (val) {
        return val === false;
    });
    /**
     * [a].push(b) = [a].after(b) = [a].composedWith(b) => [b[a]] // [b[a]]
     * [a].insert(b) = [a].before(b) = [a].then(b) => [a[b]] // [b]
     * [a[b]].isNext([b]) = [a[b]].composes([b]) // true
     * [a].isFn(a) = [a].with(a) = [a].uses(a) // true
     * [a[b]].searchNext([b]) =
     */
    Stack.mung("push", "of")
        .mung("insert", "to")
        .mung("insert", "compose");

//        .mung("isNext", "follows")
//        .mung("isFn", "with")
//        .mung("isFn", "uses")
//        .mung("searchNext", "of")
//        .mung("searchFn", "using")
//        .mung("priorNext", "previousActsOn")
//        .mung("priorFn", "composedWith");

    global.Stack = Stack;
}(this));
<|endoftext|>


<commit_before>import { applyMiddleware, compose, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
import createHistory from 'history/createBrowserHistory';

import rootSaga from './root-saga';
import './shared/ducks/error-message';
import './map/ducks/click-location/map-click-location';
import * as auth from './shared/services/auth/auth';
import { authenticateUser } from './reducers/user';
import { fetchCatalogFilters } from './catalog/ducks/data-selection/data-selection-catalog';
import rootReducer from './reducers/root';
import stateUrlConverter from './shared/services/routing/state-url-converter';
import { isDevelopment } from './shared/environment';
import freeze from './shared/services/freeze/freeze';
import contextMiddleware from './shared/services/context/context-middleware';
import stateToUrlMiddleware from './shared/services/state-to-url/state-to-url-middleware';
import locationHandlerCreator from './location-handler';

window.reducer = rootReducer;

const urlDefaultState = stateUrlConverter.getDefaultState();
const defaultState = isDevelopment() ? freeze(urlDefaultState) : urlDefaultState;

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const sagaMiddleware = createSagaMiddleware();
const enhancer = composeEnhancers(
  applyMiddleware(contextMiddleware, stateToUrlMiddleware, sagaMiddleware)
);

window.reduxStore = createStore(rootReducer, defaultState, enhancer);

sagaMiddleware.run(rootSaga);

try {
  auth.initAuth();
} catch (error) {
  window.Raven.captureMessage(error);
}

const returnPath = auth.getReturnPath();
if (returnPath) {
  // Timeout needed because the change is otherwise not being handled in
  // Firefox browsers. This is possibly due to AngularJS changing the
  // `location.hash` at the same time.
  window.setTimeout(() => {
    location.hash = returnPath;
  });
}

const accessToken = auth.getAccessToken();
if (accessToken) {
  window.reduxStore.dispatch(authenticateUser(auth.getAccessToken(), auth.getName(),
    auth.getScopes()));
}

window.reduxStore.dispatch(fetchCatalogFilters());

const history = createHistory();
const locationHandler = locationHandlerCreator(window.reduxStore);
// eslint-disable-next-line no-unused-vars
const unlisten = history.listen(locationHandler);
// Handle first page load URL
locationHandler(window.location);
<commit_msg>DP-6052 fix navigate to homepage when login<commit_after>import { applyMiddleware, compose, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
import createHistory from 'history/createBrowserHistory';

import rootSaga from './root-saga';
import './shared/ducks/error-message';
import './map/ducks/click-location/map-click-location';
import * as auth from './shared/services/auth/auth';
import { authenticateUser } from './reducers/user';
import { fetchCatalogFilters } from './catalog/ducks/data-selection/data-selection-catalog';
import rootReducer from './reducers/root';
import stateUrlConverter from './shared/services/routing/state-url-converter';
import { isDevelopment } from './shared/environment';
import freeze from './shared/services/freeze/freeze';
import contextMiddleware from './shared/services/context/context-middleware';
import stateToUrlMiddleware from './shared/services/state-to-url/state-to-url-middleware';
import locationHandlerCreator from './location-handler';

window.reducer = rootReducer;

const urlDefaultState = stateUrlConverter.getDefaultState();
const defaultState = isDevelopment() ? freeze(urlDefaultState) : urlDefaultState;

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const sagaMiddleware = createSagaMiddleware();
const enhancer = composeEnhancers(
  applyMiddleware(contextMiddleware, stateToUrlMiddleware, sagaMiddleware)
);

window.reduxStore = createStore(rootReducer, defaultState, enhancer);

sagaMiddleware.run(rootSaga);

try {
  auth.initAuth();
} catch (error) {
  window.Raven.captureMessage(error);
}

const returnPath = auth.getReturnPath();
if (returnPath) {
  location.hash = returnPath;
}

const accessToken = auth.getAccessToken();
if (accessToken) {
  window.reduxStore.dispatch(authenticateUser(auth.getAccessToken(), auth.getName(),
    auth.getScopes()));
}

window.reduxStore.dispatch(fetchCatalogFilters());

const history = createHistory();
const locationHandler = locationHandlerCreator(window.reduxStore);
// eslint-disable-next-line no-unused-vars
const unlisten = history.listen(locationHandler);
// Handle first page load URL
locationHandler(window.location);
<|endoftext|>