<commit_before>/*global collectionOptionNames, inheritVars */

var loadStart = 'load:start',
    loadEnd = 'load:end',
    rootObject;

Thorax.setRootObject = function(obj) {
  rootObject = obj;
};

Thorax.loadHandler = function(start, end, context) {
  var loadCounter = _.uniqueId();
  return function(message, background, object) {
    var self = context || this;
    self._loadInfo = self._loadInfo || [];
    var loadInfo = self._loadInfo[loadCounter];

    function startLoadTimeout() {
      clearTimeout(loadInfo.timeout);

      loadInfo.loadingTimeout = loadInfo.loadingTimeout ?
        Math.max(loadInfo.loadingTimeout - (new Date().getTime() - loadInfo.startTime), 0) :
        loadingTimeout * 1000;

      loadInfo.startTime = new Date().getTime();
      loadInfo.timeout = setTimeout(function() {
          try {
            loadInfo.run = true;
            start.call(self, loadInfo.message, loadInfo.background, loadInfo);
          } catch (e) {
            Thorax.onException('loadStart', e);
          }
        },
        loadInfo.loadingTimeout);
    }

    var loadingTimeout = self._loadingTimeoutDuration !== undefined ?
      self._loadingTimeoutDuration : Thorax.View.prototype._loadingTimeoutDuration;
    if (!loadInfo) {

      loadInfo = self._loadInfo[loadCounter] = _.extend({
        events: [],
        timeout: 0,
        message: message,
        background: !!background
      }, Backbone.Events);
      startLoadTimeout();
    } else {
      clearTimeout(loadInfo.endTimeout);

      loadInfo.message = message;
      if (!background && loadInfo.background) {
        loadInfo.background = false;
        startLoadTimeout();
      }
    }

    loadInfo.events.push(object);
    object.on(loadEnd, function endCallback() {
      object.off(loadEnd, endCallback);

      var loadingEndTimeout = self._loadingTimeoutEndDuration;
      if (loadingEndTimeout === void 0) {
        // If we are running on a non-view object pull the default timeout
        loadingEndTimeout = Thorax.View.prototype._loadingTimeoutEndDuration;
      }

      var events = loadInfo.events,
          index = events.indexOf(object);
      if (index >= 0) {
        events.splice(index, 1);
      }
      if (!events.length) {
        loadInfo.endTimeout = setTimeout(function() {
          try {
            if (!events.length) {
              var run = loadInfo.run;

              if (run) {
                // Emit the end behavior, but only if there is a paired start
                end.call(self, loadInfo.background, loadInfo);
                loadInfo.trigger(loadEnd, loadInfo);
              }

              // If stopping make sure we don't run a start
              clearTimeout(loadInfo.timeout);
              loadInfo = self._loadInfo[loadCounter] = undefined;
            }
          } catch (e) {
            Thorax.onException('loadEnd', e);
          }
        }, loadingEndTimeout * 1000);
      }
    });
  };
};

/**
 * Helper method for propagating load:start events to other objects.
 *
 * Forwards load:start events that occur on `source` to `dest`.
 */
Thorax.forwardLoadEvents = function(source, dest, once) {
  function load(message, backgound, object) {
    if (once) {
      source.off(loadStart, load);
    }
    dest.trigger(loadStart, message, backgound, object);
  }
  source.on(loadStart, load);
  return {
    off: function() {
      source.off(loadStart, load);
    }
  };
};

//
// Data load event generation
//

/**
 * Mixing for generating load:start and load:end events.
 */
Thorax.mixinLoadable = function(target, useParent) {
  _.extend(target, {
    //loading config
    _loadingClassName: 'loading',
    _loadingTimeoutDuration: 0.33,
    _loadingTimeoutEndDuration: 0.10,

    // Propagates loading view parameters to the AJAX layer
    onLoadStart: function(message, background, object) {
      var that = useParent ? this.parent : this;
      if (!that.nonBlockingLoad && !background && rootObject && rootObject !== this) {
        rootObject.trigger(loadStart, message, background, object);
      }
      $(that.el).addClass(that._loadingClassName);
      //used by loading helpers
      if (that._loadingCallbacks) {
        _.each(that._loadingCallbacks, function(callback) {
          callback();
        });
      }
    },
    onLoadEnd: function(/* background, object */) {
      var that = useParent ? this.parent : this;
      $(that.el).removeClass(that._loadingClassName);
      //used by loading helpers
      if (that._loadingCallbacks) {
        _.each(that._loadingCallbacks, function(callback) {
          callback();
        });
      }
    }
  });
};

Thorax.mixinLoadableEvents = function(target, useParent) {
  _.extend(target, {
    loadStart: function(message, background) {
      var that = useParent ? this.parent : this;
      that.trigger(loadStart, message, background, that);
    },
    loadEnd: function() {
      var that = useParent ? this.parent : this;
      that.trigger(loadEnd, that);
    }
  });
};

Thorax.mixinLoadable(Thorax.View.prototype);
Thorax.mixinLoadableEvents(Thorax.View.prototype);

Thorax.sync = function(method, dataObj, options) {
  var self = this,
      complete = options.complete;

  options.complete = function() {
    self._request = undefined;
    self._aborted = false;

    complete && complete.apply(this, arguments);
  };
  this._request = Backbone.sync.apply(this, arguments);

  return this._request;
};

function bindToRoute(callback, failback) {
  var fragment = Backbone.history.getFragment(),
      routeChanged = false;

  function routeHandler() {
    if (fragment === Backbone.history.getFragment()) {
      return;
    }
    routeChanged = true;
    res.cancel();
    failback && failback();
  }

  Backbone.history.on('route', routeHandler);

  function finalizer() {
    Backbone.history.off('route', routeHandler);
    var args = Array.prototype.slice.call(arguments, 1);
    if (!routeChanged) {
      callback.apply(this, args);
    }
  }

  var res = _.bind(finalizer, this);
  res.cancel = function() {
    Backbone.history.off('route', routeHandler);
  };

  return res;
}

function loadData(callback, failback, options) {
  if (this.isPopulated()) {
    return callback(this);
  }

  if (arguments.length === 2 && typeof failback !== 'function' && _.isObject(failback)) {
    options = failback;
    failback = false;
  }

  var self = this,
      routeChanged = false,
      successCallback = bindToRoute(_.bind(callback, self), function() {
        routeChanged = true;
        if (self._request) {
          self._aborted = true;
          self._request.abort();
        }
        failback && failback.call(self, false);
      });

  this.fetch(_.defaults({
    success: successCallback,
    error: failback && function() {
      if (!routeChanged) {
        failback.apply(self, [true].concat(_.toArray(arguments)));
      }
    },
    complete: function() {
      successCallback.cancel();
    }
  }, options));
}

function fetchQueue(options, $super) {
  if (options.resetQueue) {
    // WARN: Should ensure that loaders are protected from out of band data
    //    when using this option
    this.fetchQueue = undefined;
  }

  if (!this.fetchQueue) {
    // Kick off the request
    this.fetchQueue = [options];
    options = _.defaults({
      success: flushQueue(this, this.fetchQueue, 'success'),
      error: flushQueue(this, this.fetchQueue, 'error'),
      complete: flushQueue(this, this.fetchQueue, 'complete')
    }, options);
    $super.call(this, options);
  } else {
    // Currently fetching. Queue and process once complete
    this.fetchQueue.push(options);
  }
}

function flushQueue(self, fetchQueue, handler) {
  return function() {
    var args = arguments;

    // Flush the queue. Executes any callback handlers that
    // may have been passed in the fetch options.
    _.each(fetchQueue, function(options) {
      if (options[handler]) {
        options[handler].apply(this, args);
      }
    }, this);

    // Reset the queue if we are still the active request
    if (self.fetchQueue === fetchQueue) {
      self.fetchQueue = undefined;
    }
  };
}

var klasses = [];
Thorax.Model && klasses.push(Thorax.Model);
Thorax.Collection && klasses.push(Thorax.Collection);

_.each(klasses, function(DataClass) {
  var $fetch = DataClass.prototype.fetch;
  Thorax.mixinLoadableEvents(DataClass.prototype, false);
  _.extend(DataClass.prototype, {
    sync: Thorax.sync,

    fetch: function(options) {
      options = options || {};

      var self = this,
          complete = options.complete;

      options.complete = function() {
        complete && complete.apply(this, arguments);
        self.loadEnd();
      };
      self.loadStart(undefined, options.background);
      return fetchQueue.call(this, options || {}, $fetch);
    },

    load: function(callback, failback, options) {
      if (arguments.length === 2 && typeof failback !== 'function') {
        options = failback;
        failback = false;
      }

      options = options || {};
      if (!options.background && !this.isPopulated() && rootObject) {
        // Make sure that the global scope sees the proper load events here
        // if we are loading in standalone mode
        Thorax.forwardLoadEvents(this, rootObject, true);
      }

      loadData.call(this, callback, failback, options);
    }
  });
});

Thorax.Util.bindToRoute = bindToRoute;

if (Thorax.Router) {
  Thorax.Router.bindToRoute = Thorax.Router.prototype.bindToRoute = bindToRoute;
}

// Propagates loading view parameters to the AJAX layer
Thorax.View.prototype._modifyDataObjectOptions = function(dataObject, options) {
  options.ignoreErrors = this.ignoreFetchError;
  options.background = this.nonBlockingLoad;
  return options;
};

inheritVars.collection.loading = function() {
  var loadingView = this.loadingView,
      loadingTemplate = this.loadingTemplate,
      loadingPlacement = this.loadingPlacement;
  //add "loading-view" and "loading-template" options to collection helper
  if (loadingView || loadingTemplate) {
    var callback = Thorax.loadHandler(_.bind(function() {
      var item;
      if (this.collection.length === 0) {
        this.$el.empty();
      }
      if (loadingView) {
        var instance = Thorax.Util.getViewInstance(loadingView, {
          collection: this.collection
        });
        this._addChild(instance);
        if (loadingTemplate) {
          instance.render(loadingTemplate);
        } else {
          instance.render();
        }
        item = instance;
      } else {
        item = this.renderTemplate(loadingTemplate, {
          collection: this.collection
        });
      }
      var index = loadingPlacement
        ? loadingPlacement.call(this)
        : this.collection.length
      ;
      this.appendItem(item, index);
      this.$el.children().eq(index).attr('data-loading-element', this.collection.cid);
    }, this), _.bind(function() {
      this.$el.find('[data-loading-element="' + this.collection.cid + '"]').remove();
    }, this),
    this.collection);

    this.listenTo(this.collection, 'load:start', callback);
  }
};

if (typeof collectionOptionNames !== 'undefined') {
  collectionOptionNames['loading-template'] = 'loadingTemplate';
  collectionOptionNames['loading-view'] = 'loadingView';
  collectionOptionNames['loading-placement'] = 'loadingPlacement';
}

Thorax.View.on({
  'load:start': Thorax.loadHandler(
      function(message, background, object) {
        this.onLoadStart(message, background, object);
      },
      function(background, object) {
        this.onLoadEnd(object);
      }),

  collection: {
    'load:start': function(message, background, object) {
      this.trigger(loadStart, message, background, object);
    }
  },
  model: {
    'load:start': function(message, background, object) {
      this.trigger(loadStart, message, background, object);
    }
  }
});
<commit_msg>Simplify loadHandler<commit_after>/*global collectionOptionNames, inheritVars */

var loadStart = 'load:start',
    loadEnd = 'load:end',
    rootObject;

Thorax.setRootObject = function(obj) {
  rootObject = obj;
};

Thorax.loadHandler = function(start, end, context) {
  var loadCounter = _.uniqueId();
  return function(message, background, object) {
    var self = context || this;
    self._loadInfo = self._loadInfo || [];
    var loadInfo = self._loadInfo[loadCounter];

    function startLoadTimeout() {

      // If the timeout has been set already but has not triggered yet do nothing
      // Otherwise set a new timeout (either initial or for going from background to
      // non-background loading)
      if (loadInfo.timeout && !loadInfo.run) {
        return;
      }

      var loadingTimeout = self._loadingTimeoutDuration !== undefined ?
        self._loadingTimeoutDuration : Thorax.View.prototype._loadingTimeoutDuration;
      loadInfo.timeout = setTimeout(function() {
          try {
            loadInfo.run = true;
            start.call(self, loadInfo.message, loadInfo.background, loadInfo);
          } catch (e) {
            Thorax.onException('loadStart', e);
          }
        }, loadingTimeout * 1000);
    }

    if (!loadInfo) {
      loadInfo = self._loadInfo[loadCounter] = _.extend({
        events: [],
        timeout: 0,
        message: message,
        background: !!background
      }, Backbone.Events);
      startLoadTimeout();
    } else {
      clearTimeout(loadInfo.endTimeout);

      loadInfo.message = message;
      if (!background && loadInfo.background) {
        loadInfo.background = false;
        startLoadTimeout();
      }
    }

    loadInfo.events.push(object);
    object.on(loadEnd, function endCallback() {
      object.off(loadEnd, endCallback);

      var loadingEndTimeout = self._loadingTimeoutEndDuration;
      if (loadingEndTimeout === void 0) {
        // If we are running on a non-view object pull the default timeout
        loadingEndTimeout = Thorax.View.prototype._loadingTimeoutEndDuration;
      }

      var events = loadInfo.events,
          index = events.indexOf(object);
      if (index >= 0) {
        events.splice(index, 1);
      }
      if (!events.length) {
        loadInfo.endTimeout = setTimeout(function() {
          try {
            if (!events.length) {
              var run = loadInfo.run;

              if (run) {
                // Emit the end behavior, but only if there is a paired start
                end.call(self, loadInfo.background, loadInfo);
                loadInfo.trigger(loadEnd, loadInfo);
              }

              // If stopping make sure we don't run a start
              clearTimeout(loadInfo.timeout);
              loadInfo = self._loadInfo[loadCounter] = undefined;
            }
          } catch (e) {
            Thorax.onException('loadEnd', e);
          }
        }, loadingEndTimeout * 1000);
      }
    });
  };
};

/**
 * Helper method for propagating load:start events to other objects.
 *
 * Forwards load:start events that occur on `source` to `dest`.
 */
Thorax.forwardLoadEvents = function(source, dest, once) {
  function load(message, backgound, object) {
    if (once) {
      source.off(loadStart, load);
    }
    dest.trigger(loadStart, message, backgound, object);
  }
  source.on(loadStart, load);
  return {
    off: function() {
      source.off(loadStart, load);
    }
  };
};

//
// Data load event generation
//

/**
 * Mixing for generating load:start and load:end events.
 */
Thorax.mixinLoadable = function(target, useParent) {
  _.extend(target, {
    //loading config
    _loadingClassName: 'loading',
    _loadingTimeoutDuration: 0.33,
    _loadingTimeoutEndDuration: 0.10,

    // Propagates loading view parameters to the AJAX layer
    onLoadStart: function(message, background, object) {
      var that = useParent ? this.parent : this;
      if (!that.nonBlockingLoad && !background && rootObject && rootObject !== this) {
        rootObject.trigger(loadStart, message, background, object);
      }
      $(that.el).addClass(that._loadingClassName);
      //used by loading helpers
      if (that._loadingCallbacks) {
        _.each(that._loadingCallbacks, function(callback) {
          callback();
        });
      }
    },
    onLoadEnd: function(/* background, object */) {
      var that = useParent ? this.parent : this;
      $(that.el).removeClass(that._loadingClassName);
      //used by loading helpers
      if (that._loadingCallbacks) {
        _.each(that._loadingCallbacks, function(callback) {
          callback();
        });
      }
    }
  });
};

Thorax.mixinLoadableEvents = function(target, useParent) {
  _.extend(target, {
    loadStart: function(message, background) {
      var that = useParent ? this.parent : this;
      that.trigger(loadStart, message, background, that);
    },
    loadEnd: function() {
      var that = useParent ? this.parent : this;
      that.trigger(loadEnd, that);
    }
  });
};

Thorax.mixinLoadable(Thorax.View.prototype);
Thorax.mixinLoadableEvents(Thorax.View.prototype);

Thorax.sync = function(method, dataObj, options) {
  var self = this,
      complete = options.complete;

  options.complete = function() {
    self._request = undefined;
    self._aborted = false;

    complete && complete.apply(this, arguments);
  };
  this._request = Backbone.sync.apply(this, arguments);

  return this._request;
};

function bindToRoute(callback, failback) {
  var fragment = Backbone.history.getFragment(),
      routeChanged = false;

  function routeHandler() {
    if (fragment === Backbone.history.getFragment()) {
      return;
    }
    routeChanged = true;
    res.cancel();
    failback && failback();
  }

  Backbone.history.on('route', routeHandler);

  function finalizer() {
    Backbone.history.off('route', routeHandler);
    var args = Array.prototype.slice.call(arguments, 1);
    if (!routeChanged) {
      callback.apply(this, args);
    }
  }

  var res = _.bind(finalizer, this);
  res.cancel = function() {
    Backbone.history.off('route', routeHandler);
  };

  return res;
}

function loadData(callback, failback, options) {
  if (this.isPopulated()) {
    return callback(this);
  }

  if (arguments.length === 2 && typeof failback !== 'function' && _.isObject(failback)) {
    options = failback;
    failback = false;
  }

  var self = this,
      routeChanged = false,
      successCallback = bindToRoute(_.bind(callback, self), function() {
        routeChanged = true;
        if (self._request) {
          self._aborted = true;
          self._request.abort();
        }
        failback && failback.call(self, false);
      });

  this.fetch(_.defaults({
    success: successCallback,
    error: failback && function() {
      if (!routeChanged) {
        failback.apply(self, [true].concat(_.toArray(arguments)));
      }
    },
    complete: function() {
      successCallback.cancel();
    }
  }, options));
}

function fetchQueue(options, $super) {
  if (options.resetQueue) {
    // WARN: Should ensure that loaders are protected from out of band data
    //    when using this option
    this.fetchQueue = undefined;
  }

  if (!this.fetchQueue) {
    // Kick off the request
    this.fetchQueue = [options];
    options = _.defaults({
      success: flushQueue(this, this.fetchQueue, 'success'),
      error: flushQueue(this, this.fetchQueue, 'error'),
      complete: flushQueue(this, this.fetchQueue, 'complete')
    }, options);
    $super.call(this, options);
  } else {
    // Currently fetching. Queue and process once complete
    this.fetchQueue.push(options);
  }
}

function flushQueue(self, fetchQueue, handler) {
  return function() {
    var args = arguments;

    // Flush the queue. Executes any callback handlers that
    // may have been passed in the fetch options.
    _.each(fetchQueue, function(options) {
      if (options[handler]) {
        options[handler].apply(this, args);
      }
    }, this);

    // Reset the queue if we are still the active request
    if (self.fetchQueue === fetchQueue) {
      self.fetchQueue = undefined;
    }
  };
}

var klasses = [];
Thorax.Model && klasses.push(Thorax.Model);
Thorax.Collection && klasses.push(Thorax.Collection);

_.each(klasses, function(DataClass) {
  var $fetch = DataClass.prototype.fetch;
  Thorax.mixinLoadableEvents(DataClass.prototype, false);
  _.extend(DataClass.prototype, {
    sync: Thorax.sync,

    fetch: function(options) {
      options = options || {};

      var self = this,
          complete = options.complete;

      options.complete = function() {
        complete && complete.apply(this, arguments);
        self.loadEnd();
      };
      self.loadStart(undefined, options.background);
      return fetchQueue.call(this, options || {}, $fetch);
    },

    load: function(callback, failback, options) {
      if (arguments.length === 2 && typeof failback !== 'function') {
        options = failback;
        failback = false;
      }

      options = options || {};
      if (!options.background && !this.isPopulated() && rootObject) {
        // Make sure that the global scope sees the proper load events here
        // if we are loading in standalone mode
        Thorax.forwardLoadEvents(this, rootObject, true);
      }

      loadData.call(this, callback, failback, options);
    }
  });
});

Thorax.Util.bindToRoute = bindToRoute;

if (Thorax.Router) {
  Thorax.Router.bindToRoute = Thorax.Router.prototype.bindToRoute = bindToRoute;
}

// Propagates loading view parameters to the AJAX layer
Thorax.View.prototype._modifyDataObjectOptions = function(dataObject, options) {
  options.ignoreErrors = this.ignoreFetchError;
  options.background = this.nonBlockingLoad;
  return options;
};

inheritVars.collection.loading = function() {
  var loadingView = this.loadingView,
      loadingTemplate = this.loadingTemplate,
      loadingPlacement = this.loadingPlacement;
  //add "loading-view" and "loading-template" options to collection helper
  if (loadingView || loadingTemplate) {
    var callback = Thorax.loadHandler(_.bind(function() {
      var item;
      if (this.collection.length === 0) {
        this.$el.empty();
      }
      if (loadingView) {
        var instance = Thorax.Util.getViewInstance(loadingView, {
          collection: this.collection
        });
        this._addChild(instance);
        if (loadingTemplate) {
          instance.render(loadingTemplate);
        } else {
          instance.render();
        }
        item = instance;
      } else {
        item = this.renderTemplate(loadingTemplate, {
          collection: this.collection
        });
      }
      var index = loadingPlacement
        ? loadingPlacement.call(this)
        : this.collection.length
      ;
      this.appendItem(item, index);
      this.$el.children().eq(index).attr('data-loading-element', this.collection.cid);
    }, this), _.bind(function() {
      this.$el.find('[data-loading-element="' + this.collection.cid + '"]').remove();
    }, this),
    this.collection);

    this.listenTo(this.collection, 'load:start', callback);
  }
};

if (typeof collectionOptionNames !== 'undefined') {
  collectionOptionNames['loading-template'] = 'loadingTemplate';
  collectionOptionNames['loading-view'] = 'loadingView';
  collectionOptionNames['loading-placement'] = 'loadingPlacement';
}

Thorax.View.on({
  'load:start': Thorax.loadHandler(
      function(message, background, object) {
        this.onLoadStart(message, background, object);
      },
      function(background, object) {
        this.onLoadEnd(object);
      }),

  collection: {
    'load:start': function(message, background, object) {
      this.trigger(loadStart, message, background, object);
    }
  },
  model: {
    'load:start': function(message, background, object) {
      this.trigger(loadStart, message, background, object);
    }
  }
});
<|endoftext|>


<commit_before>// Global variables
var G = Optiscroll.G = {
  isTouch: 'ontouchstart' in window,
  cssTransition: cssTest('transition'),
  cssTransform: cssTest('transform'),
  nativeScrollbarSize: getScrollbarWidth(),

  instances: [],
  checkTimer: null,
  pauseCheck: false
};

G.cssTransformDashed = (G.cssTransform === 'transform') ? G.cssTransform : '-'+G.cssTransform.replace('T','-t').toLowerCase();

var animationTimeout = (function () {
  return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback){ window.setTimeout(callback, 1000/60); };
})();

// Get scrollbars width, thanks Google Closure Library
function getScrollbarWidth () {
  var htmlEl = document.documentElement,
      outerEl, innerEl, width = 0;

  outerEl = document.createElement('div');
  outerEl.style.cssText = 'overflow:auto;width:50px;height:50px;' + 'position:absolute;left:-100px';

  innerEl = document.createElement('div');
  innerEl.style.cssText = 'width:100px;height:100px';

  outerEl.appendChild(innerEl);
  htmlEl.appendChild(outerEl);
  width = outerEl.offsetWidth - outerEl.clientWidth;
  htmlEl.removeChild(outerEl);

  return width;
}

// Detect css3 support, thanks Modernizr
function cssTest (prop) {
  var ucProp  = prop.charAt(0).toUpperCase() + prop.slice(1),
      el = document.createElement( 'test' ),
      props   = (prop + ' ' + ['Webkit','Moz','O','ms'].join(ucProp + ' ') + ucProp).split(' ');

  for ( var i in props ) {
    if ( el.style[ props[i] ] !== undefined ) { return props[i]; }
  }
  return false;
}

function toggleClass (el, value, bool) {
  var classes = el.className.split(/\s+/),
      index = classes.indexOf(value);

  if(bool) {
    ~index || classes.push(value);
  } else {
    ~index && classes.splice(index, 1);
  }

  el.className = classes.join(" ");
}

function _extend (dest, src, merge) {
  for(var key in src) {
    if(!src.hasOwnProperty(key) || dest[key] !== undefined && merge) {
      continue;
    }
    dest[key] = src[key];
  }
  return dest;
}

function _invoke (collection, fn, args) {
  var i, j;
  if(collection.length) {
    for(i = 0, j = collection.length; i < j; i++) {
      collection[i][fn].apply(collection[i], args);
    }
  } else {
    for (i in collection) {
      collection[i][fn].apply(collection[i], args);
    }
  }
}

function _throttle(fn, threshhold) {
  var last, deferTimer;
  return function () {
    var context = this,
        now = Date.now(),
        args = arguments;
    if (last && now < last + threshhold) {
      // hold on to it
      clearTimeout(deferTimer);
      deferTimer = setTimeout(function () {
        last = now;
        fn.apply(context, args);
      }, threshhold);
    } else {
      last = now;
      fn.apply(context, args);
    }
  };
}

<commit_msg>Scrollbars size on FF 12 WinXP was 0<commit_after>// Global variables
var G = Optiscroll.G = {
  isTouch: 'ontouchstart' in window,
  cssTransition: cssTest('transition'),
  cssTransform: cssTest('transform'),
  nativeScrollbarSize: getScrollbarWidth(),

  instances: [],
  checkTimer: null,
  pauseCheck: false
};

G.cssTransformDashed = (G.cssTransform === 'transform') ? G.cssTransform : '-'+G.cssTransform.replace('T','-t').toLowerCase();

var animationTimeout = (function () {
  return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.msRequestAnimationFrame ||
    function(callback){ window.setTimeout(callback, 1000/60); };
})();

// Get scrollbars width, thanks Google Closure Library
function getScrollbarWidth () {
  var htmlEl = document.documentElement,
      outerEl, innerEl, width = 0;

  outerEl = document.createElement('div');
  outerEl.style.cssText = 'overflow:scroll;width:50px;height:50px;' + 'position:absolute;left:-100px';

  innerEl = document.createElement('div');
  innerEl.style.cssText = 'width:100px;height:100px';

  outerEl.appendChild(innerEl);
  htmlEl.appendChild(outerEl);
  width = outerEl.offsetWidth - outerEl.clientWidth;
  htmlEl.removeChild(outerEl);

  return width;
}

// Detect css3 support, thanks Modernizr
function cssTest (prop) {
  var ucProp  = prop.charAt(0).toUpperCase() + prop.slice(1),
      el = document.createElement( 'test' ),
      props   = (prop + ' ' + ['Webkit','Moz','O','ms'].join(ucProp + ' ') + ucProp).split(' ');

  for ( var i in props ) {
    if ( el.style[ props[i] ] !== undefined ) { return props[i]; }
  }
  return false;
}

function toggleClass (el, value, bool) {
  var classes = el.className.split(/\s+/),
      index = classes.indexOf(value);

  if(bool) {
    ~index || classes.push(value);
  } else {
    ~index && classes.splice(index, 1);
  }

  el.className = classes.join(" ");
}

function _extend (dest, src, merge) {
  for(var key in src) {
    if(!src.hasOwnProperty(key) || dest[key] !== undefined && merge) {
      continue;
    }
    dest[key] = src[key];
  }
  return dest;
}

function _invoke (collection, fn, args) {
  var i, j;
  if(collection.length) {
    for(i = 0, j = collection.length; i < j; i++) {
      collection[i][fn].apply(collection[i], args);
    }
  } else {
    for (i in collection) {
      collection[i][fn].apply(collection[i], args);
    }
  }
}

function _throttle(fn, threshhold) {
  var last, deferTimer;
  return function () {
    var context = this,
        now = Date.now(),
        args = arguments;
    if (last && now < last + threshhold) {
      // hold on to it
      clearTimeout(deferTimer);
      deferTimer = setTimeout(function () {
        last = now;
        fn.apply(context, args);
      }, threshhold);
    } else {
      last = now;
      fn.apply(context, args);
    }
  };
}

<|endoftext|>


<commit_before>(function($) {

  $.fn.majesty = function() {

    var findMatches = function(searchValue, elements) {
      // Hack for now. Probably use regex later
      filtered = elements.filter(function() {
        values = $(this).data('depends-value').split(',');
        for(var i=0; i < values.length; i++) {
          if($.trim(values[i]) == searchValue) {
            return true;
          }
        }
      });
      return filtered;
    };

    return this.each(function() {

      self = $(this);
      dependents = self.find('[data-depends-on]');
      dependents.hide();

      self.on('change', 'select', function(e) {
        target = $(e.currentTarget);
        name = target.attr('name');
        val = target.val();
        potential = dependents.filter('[data-depends-on=' + name + ']');
        matched = findMatches(val, potential);
        potential.hide();
        matched.show();
      });
    });
  };
})(jQuery);
<commit_msg>Minor refactor<commit_after>(function($) {

  $.fn.majesty = function() {

    var findDependents = function(rootElement) {
      return rootElement.find('[data-depends-on]');
    };

    var findMatches = function(searchValue, elements) {
      // Hack for now. Probably use regex later
      filtered = elements.filter(function() {
        values = $(this).data('depends-value').split(',');
        for(var i=0; i < values.length; i++) {
          if($.trim(values[i]) == searchValue) {
            return true;
          }
        }
      });
      return filtered;
    };

    return this.each(function() {

      self = $(this);
      dependents = findDependents(self);
      dependents.hide();

      self.on('change', 'select', function(e) {
        target = $(e.currentTarget);
        name = target.attr('name');
        val = target.val();
        potential = dependents.filter('[data-depends-on=' + name + ']');
        matched = findMatches(val, potential);
        potential.hide();
        matched.show();
      });
    });
  };
})(jQuery);
<|endoftext|>


<commit_before>import angular from 'angular';
import $ from 'jquery';
import moment from 'moment';
import _ from 'lodash';
import kbn from 'app/core/utils/kbn';
import './bower_components/d3/d3.min.js';
import './bower_components/epoch/dist/js/epoch.min.js';

angular.module('grafana.directives').directive('grafanaHeatmapEpoch', function($rootScope, timeSrv) {
  return {
    restrict: 'A',
    template: '<div> </div>',
    link: function(scope, elem) {
      var ctrl = scope.ctrl;
      var dashboard = ctrl.dashboard;
      var panel = ctrl.panel;
      var data;
      var sortedSeries;
      var legendSideLastValue = null;
      var rootScope = scope.$root;
      var epoch = null;
      var firstDraw = true;
      var delta = true;
      var labelToModelIndexMap = {};
      var currentDatasource = '';
      var currentTimeRange = [0, 0];
      var currentSize = { width: null, height: null };

      // Receive render events
      ctrl.events.on('render', function(renderData) {
        data = renderData || data;
        if (!data) {
          ctrl.refresh();
          return;
        }
        render_panel();
      });

      function getLegendHeight(panelHeight) {
        if (!panel.legend.show || panel.legend.rightSide) {
          return 2;
        }

        if (panel.legend.alignAsTable) {
          var legendSeries = _.filter(data, function(series) {
            return series.hideFromLegend(panel.legend) === false;
          });
          var total = 23 + (22 * legendSeries.length);
          return Math.min(total, Math.floor(panelHeight/2));
        } else {
          return 26;
        }
      }

      function setElementHeight() {
        try {
          var height = ctrl.height - getLegendHeight(ctrl.height);
          elem.css('height', height + 'px');

          return true;
        } catch(e) { // IE throws errors sometimes
          console.log(e);
          return false;
        }
      }

      function shouldAbortRender() {
        if (!data || _.isEmpty(data)) {
          return true;
        }

        if (!setElementHeight()) { return true; }

        if (elem.width() === 0) {
          return true;
        }
      }

      function processOffsetHook(plot, gridMargin) {
        var left = panel.yaxes[0];
        var right = panel.yaxes[1];
        if (left.show && left.label) { gridMargin.left = 20; }
        if (right.show && right.label) { gridMargin.right = 20; }
      }

      function getEpoch() {
        if (epoch) {
          return epoch;
        }

        epoch = elem.epoch(panel.heatmapOptions);
        scope.$watch('ctrl.panel.heatmapOptions.windowSize', function(newVal, oldVal) {
          epoch.option('windowSize', newVal);
          epoch.option('historySize', newVal * 3);
          epoch.redraw();
        });
        scope.$watch('ctrl.panel.heatmapOptions.buckets', function(newVal, oldVal) {
          epoch.option('buckets', newVal);
        });
        scope.$watch('ctrl.panel.heatmapOptions.bucketRange[0]', function(newVal, oldVal) {
          epoch.option('bucketRange', panel.heatmapOptions.bucketRange);
        });
        scope.$watch('ctrl.panel.heatmapOptions.bucketRange[1]', function(newVal, oldVal) {
          epoch.option('bucketRange', panel.heatmapOptions.bucketRange);
        });
        scope.$watch('ctrl.panel.heatmapOptions.startTime', function(newVal, oldVal) {
          epoch.option('startTime', newVal);
          epoch.redraw();
        });

        return epoch;
      }

      function getHeatmapData(datapoints, delta) {
        var windowInterval = Math.floor((ctrl.range.to - ctrl.range.from) / panel.heatmapOptions.windowSize);
        var groupedData = _.chain(datapoints)
        .reject(function(dp) {
          return dp[0] === null;
        })
        .groupBy(function(dp) {
          return Math.floor((dp[1] - ctrl.range.from) / windowInterval) + 1;
        }).value();

        var data = [];
        var n;
        var keys = _.keys(groupedData);
        var min = delta ? _.min(keys) : 1;
        var max = delta ? _.max(keys) : panel.heatmapOptions.windowSize + 1;
        for (n = min; n <= max; n++) {
          var values = groupedData[n] || [];

          data.push({
            time: Math.floor((n * windowInterval + ctrl.range.from) / 1000),
            histogram: _.countBy(values, function(value) {
              return value[0];
            })
          });
        }

        if (data.length > panel.heatmapOptions.windowSize) {
          data[panel.heatmapOptions.windowSize].histogram = {};
        }

        return data;
      }

      function callPlot(incrementRenderCounter, data) {
        try {
          epoch.setData(data);

          _.each(data, function(d) {
            epoch.showLayer(d.label);
            if (ctrl.hiddenSeries[d.alias]) {
              epoch.hideLayer(d.label);
            }
          });

          if (ctrl.range.from !== currentTimeRange[0] || ctrl.range.to !== currentTimeRange[1]) {
            var ticks = Math.ceil(panel.heatmapOptions.windowSize / panel.heatmapOptions.ticks.time);
            var min = _.isUndefined(ctrl.range.from) ? null : ctrl.range.from.valueOf();
            var max = _.isUndefined(ctrl.range.to) ? null : ctrl.range.to.valueOf();
            epoch.option('tickFormats.bottom', function (d) {
              var timeFormat = time_format(ticks, min, max);
              return moment.unix(d).format(timeFormat);
            });
            epoch.ticksChanged();
          }
          currentTimeRange = [ctrl.range.from, ctrl.range.to];

          epoch.redraw();
        } catch (e) {
          console.log('epoch error', e);
        }

        if (incrementRenderCounter) {
          ctrl.renderingCompleted();
        }
      }

      // Function for rendering panel
      function render_panel() {
        if (shouldAbortRender()) {
          return;
        }

        // reset startTime if datasource is changed
        if (panel.datasource !== currentDatasource) {
          panel.heatmapOptions.startTime = Math.floor(ctrl.range.from.valueOf() / 1000);
          firstDraw = true;
        }
        currentDatasource = panel.datasource;

        var epoch = getEpoch();

        // check panel size change
        var width = elem.parent().width();
        var height = elem.parent().height();
        if (width !== currentSize.width) {
          epoch.option('width', width);
          var ticksTime = Math.floor(panel.heatmapOptions.windowSize * 30 * 2 / width);
          epoch.option('ticks.time', ticksTime);
          epoch.ticksChanged();
        }
        if (height !== currentSize.height) {
          epoch.option('height', height);
        }
        currentSize.width = width;
        currentSize.height = height;

        if (firstDraw) {
          delta = true;
          var seriesData = _.map(data, function (series) {
            delta = delta && series.unit; // use unit as delta temporaly, if all series is delta, enable realtime chart
            var epochLabel = ctrl.getEpochLabel(series.label);

            return {
              alias: series.label,
              label: epochLabel,
              values: getHeatmapData(series.datapoints, false)
            };
          });

          if (shouldDelayDraw(panel)) {
            // temp fix for legends on the side, need to render twice to get dimensions right
            callPlot(false, seriesData);
            setTimeout(function() { callPlot(true, seriesData); }, 50);
            legendSideLastValue = panel.legend.rightSide;
          } else {
            callPlot(true, seriesData);
          }

          // create model index for realtime graph
          if (delta) {
            firstDraw = false;

            labelToModelIndexMap = {};
            _.each(data, function (series, i) {
              labelToModelIndexMap[series.label] = i;
            });
          }
        } else if (delta) { // realtime graph
          var indexedData = [];
          var dataLength = 0;
          _.each(data, function (series) {
            if (_.isUndefined(labelToModelIndexMap[series.label])) {
              return;
            }

            var values = getHeatmapData(series.datapoints, true);
            indexedData[labelToModelIndexMap[series.label]] = values;

            if (dataLength < values.length) {
              dataLength = values.length;
            }
          });

          if (!_.isEmpty(indexedData)) {
            var now = new Date() / 1000;
            for (var n = 0; n < dataLength; n++) {
              var pushData = indexedData.map(function (d) {
                return d[n] || {
                  time: now,
                  histogram: {
                  }
                };
              });
              epoch.push(pushData);
            }
          }
          ctrl.renderingCompleted();
        }
      }

      function time_format(ticks, min, max) {
        if (min && max && ticks) {
          var range = max - min;
          var secPerTick = (range/ticks) / 1000;
          var oneDay = 86400000;
          var oneYear = 31536000000;

          if (secPerTick <= 45) {
            return 'HH:mm:ss';
          }
          if (secPerTick <= 7200 || range <= oneDay) {
            return 'HH:mm';
          }
          if (secPerTick <= 80000) {
            return 'M/D HH:mm';
          }
          if (secPerTick <= 2419200 || range <= oneYear) {
            return 'M/D';
          }
          return 'YYYY-M';
        }

        return 'HH:mm';
      }

      function shouldDelayDraw(panel) {
        if (panel.legend.rightSide) {
          return true;
        }
        if (legendSideLastValue !== null && panel.legend.rightSide !== legendSideLastValue) {
          return true;
        }
      }

      elem.bind('plotselected', function (event, ranges) {
        scope.$apply(function() {
          timeSrv.setTime({
            from  : moment.utc(ranges.xaxis.from),
            to    : moment.utc(ranges.xaxis.to),
          });
        });
      });
    }
  };
});
<commit_msg>queue redraw request<commit_after>import angular from 'angular';
import $ from 'jquery';
import moment from 'moment';
import _ from 'lodash';
import kbn from 'app/core/utils/kbn';
import './bower_components/d3/d3.min.js';
import './bower_components/epoch/dist/js/epoch.min.js';

angular.module('grafana.directives').directive('grafanaHeatmapEpoch', function($rootScope, timeSrv) {
  return {
    restrict: 'A',
    template: '<div> </div>',
    link: function(scope, elem) {
      var ctrl = scope.ctrl;
      var dashboard = ctrl.dashboard;
      var panel = ctrl.panel;
      var data;
      var sortedSeries;
      var legendSideLastValue = null;
      var rootScope = scope.$root;
      var epoch = null;
      var firstDraw = true;
      var delta = true;
      var labelToModelIndexMap = {};
      var currentDatasource = '';
      var currentTimeRange = [0, 0];
      var currentSize = { width: null, height: null };

      // Receive render events
      ctrl.events.on('render', function(renderData) {
        data = renderData || data;
        if (!data) {
          ctrl.refresh();
          return;
        }
        render_panel();
      });

      function getLegendHeight(panelHeight) {
        if (!panel.legend.show || panel.legend.rightSide) {
          return 2;
        }

        if (panel.legend.alignAsTable) {
          var legendSeries = _.filter(data, function(series) {
            return series.hideFromLegend(panel.legend) === false;
          });
          var total = 23 + (22 * legendSeries.length);
          return Math.min(total, Math.floor(panelHeight/2));
        } else {
          return 26;
        }
      }

      function setElementHeight() {
        try {
          var height = ctrl.height - getLegendHeight(ctrl.height);
          elem.css('height', height + 'px');

          return true;
        } catch(e) { // IE throws errors sometimes
          console.log(e);
          return false;
        }
      }

      function shouldAbortRender() {
        if (!data || _.isEmpty(data)) {
          return true;
        }

        if (!setElementHeight()) { return true; }

        if (elem.width() === 0) {
          return true;
        }
      }

      function processOffsetHook(plot, gridMargin) {
        var left = panel.yaxes[0];
        var right = panel.yaxes[1];
        if (left.show && left.label) { gridMargin.left = 20; }
        if (right.show && right.label) { gridMargin.right = 20; }
      }

      function getEpoch() {
        if (epoch) {
          return epoch;
        }

        epoch = elem.epoch(panel.heatmapOptions);
        scope.$watch('ctrl.panel.heatmapOptions.windowSize', function(newVal, oldVal) {
          epoch.option('windowSize', newVal);
          epoch.option('historySize', newVal * 3);
          redraw();
        });
        scope.$watch('ctrl.panel.heatmapOptions.buckets', function(newVal, oldVal) {
          epoch.option('buckets', newVal);
        });
        scope.$watch('ctrl.panel.heatmapOptions.bucketRange[0]', function(newVal, oldVal) {
          epoch.option('bucketRange', panel.heatmapOptions.bucketRange);
        });
        scope.$watch('ctrl.panel.heatmapOptions.bucketRange[1]', function(newVal, oldVal) {
          epoch.option('bucketRange', panel.heatmapOptions.bucketRange);
        });
        scope.$watch('ctrl.panel.heatmapOptions.startTime', function(newVal, oldVal) {
          epoch.option('startTime', newVal);
          redraw();
        });

        return epoch;
      }

      function getHeatmapData(datapoints, delta) {
        var windowInterval = Math.floor((ctrl.range.to - ctrl.range.from) / panel.heatmapOptions.windowSize);
        var groupedData = _.chain(datapoints)
        .reject(function(dp) {
          return dp[0] === null;
        })
        .groupBy(function(dp) {
          return Math.floor((dp[1] - ctrl.range.from) / windowInterval) + 1;
        }).value();

        var data = [];
        var n;
        var keys = _.keys(groupedData);
        var min = delta ? _.min(keys) : 1;
        var max = delta ? _.max(keys) : panel.heatmapOptions.windowSize + 1;
        for (n = min; n <= max; n++) {
          var values = groupedData[n] || [];

          data.push({
            time: Math.floor((n * windowInterval + ctrl.range.from) / 1000),
            histogram: _.countBy(values, function(value) {
              return value[0];
            })
          });
        }

        if (data.length > panel.heatmapOptions.windowSize) {
          data[panel.heatmapOptions.windowSize].histogram = {};
        }

        return data;
      }

      var inRedraw = false;
      function redraw() {
        if (inRedraw) {
          return;
        }

        inRedraw = true;
        var epoch = getEpoch();
        setTimeout(function() {
          epoch.redraw();
          inRedraw = false;
        }, 0);
      }

      function callPlot(incrementRenderCounter, data) {
        try {
          epoch.setData(data);

          _.each(data, function(d) {
            epoch.showLayer(d.label);
            if (ctrl.hiddenSeries[d.alias]) {
              epoch.hideLayer(d.label);
            }
          });

          if (ctrl.range.from !== currentTimeRange[0] || ctrl.range.to !== currentTimeRange[1]) {
            var ticks = Math.ceil(panel.heatmapOptions.windowSize / panel.heatmapOptions.ticks.time);
            var min = _.isUndefined(ctrl.range.from) ? null : ctrl.range.from.valueOf();
            var max = _.isUndefined(ctrl.range.to) ? null : ctrl.range.to.valueOf();
            epoch.option('tickFormats.bottom', function (d) {
              var timeFormat = time_format(ticks, min, max);
              return moment.unix(d).format(timeFormat);
            });
            epoch.ticksChanged();
          }
          currentTimeRange = [ctrl.range.from, ctrl.range.to];

          redraw();
        } catch (e) {
          console.log('epoch error', e);
        }

        if (incrementRenderCounter) {
          ctrl.renderingCompleted();
        }
      }

      // Function for rendering panel
      function render_panel() {
        if (shouldAbortRender()) {
          return;
        }

        // reset startTime if datasource is changed
        if (panel.datasource !== currentDatasource) {
          panel.heatmapOptions.startTime = Math.floor(ctrl.range.from.valueOf() / 1000);
          firstDraw = true;
        }
        currentDatasource = panel.datasource;

        var epoch = getEpoch();

        // check panel size change
        var width = elem.parent().width();
        var height = elem.parent().height();
        if (width !== currentSize.width) {
          epoch.option('width', width);
          var ticksTime = Math.floor(panel.heatmapOptions.windowSize * 30 * 2 / width);
          epoch.option('ticks.time', ticksTime);
          epoch.ticksChanged();
        }
        if (height !== currentSize.height) {
          epoch.option('height', height);
        }
        currentSize.width = width;
        currentSize.height = height;

        if (firstDraw) {
          delta = true;
          var seriesData = _.map(data, function (series) {
            delta = delta && series.unit; // use unit as delta temporaly, if all series is delta, enable realtime chart
            var epochLabel = ctrl.getEpochLabel(series.label);

            return {
              alias: series.label,
              label: epochLabel,
              values: getHeatmapData(series.datapoints, false)
            };
          });

          if (shouldDelayDraw(panel)) {
            // temp fix for legends on the side, need to render twice to get dimensions right
            callPlot(false, seriesData);
            setTimeout(function() { callPlot(true, seriesData); }, 50);
            legendSideLastValue = panel.legend.rightSide;
          } else {
            callPlot(true, seriesData);
          }

          // create model index for realtime graph
          if (delta) {
            firstDraw = false;

            labelToModelIndexMap = {};
            _.each(data, function (series, i) {
              labelToModelIndexMap[series.label] = i;
            });
          }
        } else if (delta) { // realtime graph
          var indexedData = [];
          var dataLength = 0;
          _.each(data, function (series) {
            if (_.isUndefined(labelToModelIndexMap[series.label])) {
              return;
            }

            var values = getHeatmapData(series.datapoints, true);
            indexedData[labelToModelIndexMap[series.label]] = values;

            if (dataLength < values.length) {
              dataLength = values.length;
            }
          });

          if (!_.isEmpty(indexedData)) {
            var now = new Date() / 1000;
            for (var n = 0; n < dataLength; n++) {
              var pushData = indexedData.map(function (d) {
                return d[n] || {
                  time: now,
                  histogram: {
                  }
                };
              });
              epoch.push(pushData);
            }
          }
          ctrl.renderingCompleted();
        }
      }

      function time_format(ticks, min, max) {
        if (min && max && ticks) {
          var range = max - min;
          var secPerTick = (range/ticks) / 1000;
          var oneDay = 86400000;
          var oneYear = 31536000000;

          if (secPerTick <= 45) {
            return 'HH:mm:ss';
          }
          if (secPerTick <= 7200 || range <= oneDay) {
            return 'HH:mm';
          }
          if (secPerTick <= 80000) {
            return 'M/D HH:mm';
          }
          if (secPerTick <= 2419200 || range <= oneYear) {
            return 'M/D';
          }
          return 'YYYY-M';
        }

        return 'HH:mm';
      }

      function shouldDelayDraw(panel) {
        if (panel.legend.rightSide) {
          return true;
        }
        if (legendSideLastValue !== null && panel.legend.rightSide !== legendSideLastValue) {
          return true;
        }
      }

      elem.bind('plotselected', function (event, ranges) {
        scope.$apply(function() {
          timeSrv.setTime({
            from  : moment.utc(ranges.xaxis.from),
            to    : moment.utc(ranges.xaxis.to),
          });
        });
      });
    }
  };
});
<|endoftext|>


<commit_before>import { isObject } from './util'

/**
 * Reduce the code which written in Vue.js for getting the state.
 * @param {String} [namespace] - Module's namespace
 * @param {Object|Array} states # Object's item can be a function which accept state and getters for param, you can do something for state and getters in it.
 * @param {Object}
 */
export const mapState = normalizeNamespace((namespace, states) => {
  const res = {}
  if (__DEV__ && !isValidMap(states)) {
    console.error('[vuex] mapState: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(states).forEach(({ key, val }) => {
    res[key] = function mappedState () {
      let state = this.$store.state
      let getters = this.$store.getters
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapState', namespace)
        if (!module) {
          return
        }
        state = module.context.state
        getters = module.context.getters
      }
      return typeof val === 'function'
        ? val.call(this, state, getters)
        : state[val]
    }
    // mark vuex getter for devtools
    res[key].vuex = true
  })
  return res
})

/**
 * Reduce the code which written in Vue.js for committing the mutation
 * @param {String} [namespace] - Module's namespace
 * @param {Object|Array} mutations # Object's item can be a function which accept `commit` function as the first param, it can accept anthor params. You can commit mutation and do any other things in this function. specially, You need to pass anthor params from the mapped function.
 * @return {Object}
 */
export const mapMutations = normalizeNamespace((namespace, mutations) => {
  const res = {}
  if (__DEV__ && !isValidMap(mutations)) {
    console.error('[vuex] mapMutations: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(mutations).forEach(({ key, val }) => {
    res[key] = function mappedMutation (...args) {
      // Get the commit method from store
      let commit = this.$store.commit
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapMutations', namespace)
        if (!module) {
          return
        }
        commit = module.context.commit
      }
      return typeof val === 'function'
        ? val.apply(this, [commit].concat(args))
        : commit.apply(this.$store, [val].concat(args))
    }
  })
  return res
})

/**
 * Reduce the code which written in Vue.js for getting the getters
 * @param {String} [namespace] - Module's namespace
 * @param {Object|Array} getters
 * @return {Object}
 */
export const mapGetters = normalizeNamespace((namespace, getters) => {
  const res = {}
  if (__DEV__ && !isValidMap(getters)) {
    console.error('[vuex] mapGetters: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(getters).forEach(({ key, val }) => {
    // The namespace has been mutated by normalizeNamespace
    val = namespace + val
    res[key] = function mappedGetter () {
      if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) {
        return
      }
      if (__DEV__ && !(val in this.$store.getters)) {
        console.error(`[vuex] unknown getter: ${val}`)
        return
      }
      return this.$store.getters[val]
    }
    // mark vuex getter for devtools
    res[key].vuex = true
  })
  return res
})

/**
 * Reduce the code which written in Vue.js for dispatch the action
 * @param {String} [namespace] - Module's namespace
 * @param {Object|Array} actions # Object's item can be a function which accept `dispatch` function as the first param, it can accept anthor params. You can dispatch action and do any other things in this function. specially, You need to pass anthor params from the mapped function.
 * @return {Object}
 */
export const mapActions = normalizeNamespace((namespace, actions) => {
  const res = {}
  if (__DEV__ && !isValidMap(actions)) {
    console.error('[vuex] mapActions: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(actions).forEach(({ key, val }) => {
    res[key] = function mappedAction (...args) {
      // get dispatch function from store
      let dispatch = this.$store.dispatch
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapActions', namespace)
        if (!module) {
          return
        }
        dispatch = module.context.dispatch
      }
      return typeof val === 'function'
        ? val.apply(this, [dispatch].concat(args))
        : dispatch.apply(this.$store, [val].concat(args))
    }
  })
  return res
})

/**
 * Rebinding namespace param for mapXXX function in special scoped, and return them by simple object
 * @param {String} namespace
 * @return {Object}
 */
export const createNamespacedHelpers = (namespace) => ({
  mapState: mapState.bind(null, namespace),
  mapGetters: mapGetters.bind(null, namespace),
  mapMutations: mapMutations.bind(null, namespace),
  mapActions: mapActions.bind(null, namespace)
})

/**
 * Normalize the map
 * normalizeMap([1, 2, 3]) => [ { key: 1, val: 1 }, { key: 2, val: 2 }, { key: 3, val: 3 } ]
 * normalizeMap({a: 1, b: 2, c: 3}) => [ { key: 'a', val: 1 }, { key: 'b', val: 2 }, { key: 'c', val: 3 } ]
 * @param {Array|Object} map
 * @return {Object}
 */
function normalizeMap (map) {
  if (!isValidMap(map)) {
    return []
  }
  return Array.isArray(map)
    ? map.map(key => ({ key, val: key }))
    : Object.keys(map).map(key => ({ key, val: map[key] }))
}

/**
 * Validate whether given map is valid or not
 * @param {*} map
 * @return {Boolean}
 */
function isValidMap (map) {
  return Array.isArray(map) || isObject(map)
}

/**
 * Return a function expect two param contains namespace and map. it will normalize the namespace and then the param's function will handle the new namespace and the map.
 * @param {Function} fn
 * @return {Function}
 */
function normalizeNamespace (fn) {
  return (namespace, map) => {
    if (typeof namespace !== 'string') {
      map = namespace
      namespace = ''
    } else if (namespace.charAt(namespace.length - 1) !== '/') {
      namespace += '/'
    }
    return fn(namespace, map)
  }
}

/**
 * Search a special module from store by namespace. if module not exist, print error message.
 * @param {Object} store
 * @param {String} helper
 * @param {String} namespace
 * @return {Object}
 */
function getModuleByNamespace (store, helper, namespace) {
  const module = store._modulesNamespaceMap[namespace]
  if (__DEV__ && !module) {
    console.error(`[vuex] module namespace not found in ${helper}(): ${namespace}`)
  }
  return module
}
<commit_msg>chore: fix a little typo in the comment<commit_after>import { isObject } from './util'

/**
 * Reduce the code which written in Vue.js for getting the state.
 * @param {String} [namespace] - Module's namespace
 * @param {Object|Array} states # Object's item can be a function which accept state and getters for param, you can do something for state and getters in it.
 * @param {Object}
 */
export const mapState = normalizeNamespace((namespace, states) => {
  const res = {}
  if (__DEV__ && !isValidMap(states)) {
    console.error('[vuex] mapState: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(states).forEach(({ key, val }) => {
    res[key] = function mappedState () {
      let state = this.$store.state
      let getters = this.$store.getters
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapState', namespace)
        if (!module) {
          return
        }
        state = module.context.state
        getters = module.context.getters
      }
      return typeof val === 'function'
        ? val.call(this, state, getters)
        : state[val]
    }
    // mark vuex getter for devtools
    res[key].vuex = true
  })
  return res
})

/**
 * Reduce the code which written in Vue.js for committing the mutation
 * @param {String} [namespace] - Module's namespace
 * @param {Object|Array} mutations # Object's item can be a function which accept `commit` function as the first param, it can accept another params. You can commit mutation and do any other things in this function. specially, You need to pass anthor params from the mapped function.
 * @return {Object}
 */
export const mapMutations = normalizeNamespace((namespace, mutations) => {
  const res = {}
  if (__DEV__ && !isValidMap(mutations)) {
    console.error('[vuex] mapMutations: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(mutations).forEach(({ key, val }) => {
    res[key] = function mappedMutation (...args) {
      // Get the commit method from store
      let commit = this.$store.commit
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapMutations', namespace)
        if (!module) {
          return
        }
        commit = module.context.commit
      }
      return typeof val === 'function'
        ? val.apply(this, [commit].concat(args))
        : commit.apply(this.$store, [val].concat(args))
    }
  })
  return res
})

/**
 * Reduce the code which written in Vue.js for getting the getters
 * @param {String} [namespace] - Module's namespace
 * @param {Object|Array} getters
 * @return {Object}
 */
export const mapGetters = normalizeNamespace((namespace, getters) => {
  const res = {}
  if (__DEV__ && !isValidMap(getters)) {
    console.error('[vuex] mapGetters: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(getters).forEach(({ key, val }) => {
    // The namespace has been mutated by normalizeNamespace
    val = namespace + val
    res[key] = function mappedGetter () {
      if (namespace && !getModuleByNamespace(this.$store, 'mapGetters', namespace)) {
        return
      }
      if (__DEV__ && !(val in this.$store.getters)) {
        console.error(`[vuex] unknown getter: ${val}`)
        return
      }
      return this.$store.getters[val]
    }
    // mark vuex getter for devtools
    res[key].vuex = true
  })
  return res
})

/**
 * Reduce the code which written in Vue.js for dispatch the action
 * @param {String} [namespace] - Module's namespace
 * @param {Object|Array} actions # Object's item can be a function which accept `dispatch` function as the first param, it can accept anthor params. You can dispatch action and do any other things in this function. specially, You need to pass anthor params from the mapped function.
 * @return {Object}
 */
export const mapActions = normalizeNamespace((namespace, actions) => {
  const res = {}
  if (__DEV__ && !isValidMap(actions)) {
    console.error('[vuex] mapActions: mapper parameter must be either an Array or an Object')
  }
  normalizeMap(actions).forEach(({ key, val }) => {
    res[key] = function mappedAction (...args) {
      // get dispatch function from store
      let dispatch = this.$store.dispatch
      if (namespace) {
        const module = getModuleByNamespace(this.$store, 'mapActions', namespace)
        if (!module) {
          return
        }
        dispatch = module.context.dispatch
      }
      return typeof val === 'function'
        ? val.apply(this, [dispatch].concat(args))
        : dispatch.apply(this.$store, [val].concat(args))
    }
  })
  return res
})

/**
 * Rebinding namespace param for mapXXX function in special scoped, and return them by simple object
 * @param {String} namespace
 * @return {Object}
 */
export const createNamespacedHelpers = (namespace) => ({
  mapState: mapState.bind(null, namespace),
  mapGetters: mapGetters.bind(null, namespace),
  mapMutations: mapMutations.bind(null, namespace),
  mapActions: mapActions.bind(null, namespace)
})

/**
 * Normalize the map
 * normalizeMap([1, 2, 3]) => [ { key: 1, val: 1 }, { key: 2, val: 2 }, { key: 3, val: 3 } ]
 * normalizeMap({a: 1, b: 2, c: 3}) => [ { key: 'a', val: 1 }, { key: 'b', val: 2 }, { key: 'c', val: 3 } ]
 * @param {Array|Object} map
 * @return {Object}
 */
function normalizeMap (map) {
  if (!isValidMap(map)) {
    return []
  }
  return Array.isArray(map)
    ? map.map(key => ({ key, val: key }))
    : Object.keys(map).map(key => ({ key, val: map[key] }))
}

/**
 * Validate whether given map is valid or not
 * @param {*} map
 * @return {Boolean}
 */
function isValidMap (map) {
  return Array.isArray(map) || isObject(map)
}

/**
 * Return a function expect two param contains namespace and map. it will normalize the namespace and then the param's function will handle the new namespace and the map.
 * @param {Function} fn
 * @return {Function}
 */
function normalizeNamespace (fn) {
  return (namespace, map) => {
    if (typeof namespace !== 'string') {
      map = namespace
      namespace = ''
    } else if (namespace.charAt(namespace.length - 1) !== '/') {
      namespace += '/'
    }
    return fn(namespace, map)
  }
}

/**
 * Search a special module from store by namespace. if module not exist, print error message.
 * @param {Object} store
 * @param {String} helper
 * @param {String} namespace
 * @return {Object}
 */
function getModuleByNamespace (store, helper, namespace) {
  const module = store._modulesNamespaceMap[namespace]
  if (__DEV__ && !module) {
    console.error(`[vuex] module namespace not found in ${helper}(): ${namespace}`)
  }
  return module
}
<|endoftext|>


<commit_before>'use babel'

import FS from 'fs'
import Path from 'path'
import Minimatch from 'minimatch'
import Glob from 'glob'

const DEFAULT_CONFIG = {
  plugins: [],
  rules: []
}

/** Finding Helpers */

export function findFile(root, fileName) {
  try {
    FS.accessSync(root, FS.R_OK)
  } catch (_) {
    throw new Error(`Can not read directory ${root}`)
  }
  const chunks = root.split(Path.sep)
  while (chunks.length) {
    const filePath = Path.join(chunks.join(Path.sep), fileName)
    if (filePath === fileName) {
      break
    }
    try {
      FS.accessSync(filePath, FS.R_OK)
      return filePath
    } catch (_) {}
    chunks.pop()
  }
  return null
}

export function findRoot(path, root) {
  if (root !== null) {
    return root
  } else if (path.indexOf('*') !== -1) {
    throw new Error('Options.root must be specified with glob')
  }
  let stat
  try {
    stat = FS.statSync(path)
  } catch (_) {
    throw new Error(`Error reading ${path}`)
  }
  if (stat.isDirectory()) {
    return path
  } else if (stat.isFile()) {
    const configFile = findFile(path, '.ucompilerrc')
    if (configFile === null) {
      return Path.dirname(path)
    } else {
      return Path.dirname(configFile)
    }
  } else throw new Error(`${path} is neither a file nor a directory`)
}

export function scanFiles(path, {root, ignored}) {
  if (path.indexOf('*') === -1) {
    // Non-Glob
    const absPath = Path.isAbsolute(path) ? path : Path.join(path, root)
    const stat = FS.statSync(absPath)
    if (stat.isFile()) {
      return [absPath]
    } else if (stat.isDirectory()) {
      let files = []
      FS.readdirSync(absPath).forEach(function(file) {
        const absFilePath = Path.join(absPath, file)
        const relativeFilePath = Path.relative(root, absFilePath)
        if (ignored.some(function(ignored) {
            return Minimatch(relativeFilePath, ignored)
          })) {
          return
        }
        let stat
        try {
          stat = FS.lstatSync(absFilePath)
        } catch (_) {
          throw new Error(`Error reading ${absFilePath}`)
        }
        if (!stat.isSymbolicLink()) {
          if (stat.isFile()) {
            files.push(relativeFilePath)
          } else if (stat.isDirectory()) {
            files = files.concat(scanFiles(absFilePath, {root, ignored}))
          }
        }
      })
      return files
    } else return []
  } else {
    // Glob
    return Glob.sync(path, {cwd: root, ignore: ignored})
  }
}

/** Config Helper */

export function getConfig(root) {
  const configFile = findFile(root, '.ucompilerrc')
  if (configFile !== null) {
    let config
    try {
      config = JSON.parse(FS.readFileSync(configFile, {encoding: 'utf8'}))
    } catch (e) {
      throw new Error(`Malformed configuration file located at ${configFile}`)
    }
    return Object.assign({}, DEFAULT_CONFIG, config)
  } else return DEFAULT_CONFIG
}

/** Saving Helper */

export function saveFile({contents, file, config}) {
  //console.log(contents)
}
<commit_msg>:bug: Fix a minor bug<commit_after>'use babel'

import FS from 'fs'
import Path from 'path'
import Minimatch from 'minimatch'
import Glob from 'glob'

const DEFAULT_CONFIG = {
  plugins: [],
  rules: []
}

/** Finding Helpers */

export function findFile(root, fileName) {
  try {
    FS.accessSync(root, FS.R_OK)
  } catch (_) {
    throw new Error(`Can not read directory ${root}`)
  }
  const chunks = root.split(Path.sep)
  while (chunks.length) {
    const filePath = Path.join(chunks.join(Path.sep), fileName)
    if (filePath === fileName) {
      break
    }
    try {
      FS.accessSync(filePath, FS.R_OK)
      return filePath
    } catch (_) {}
    chunks.pop()
  }
  return null
}

export function findRoot(path, root) {
  if (root !== null) {
    return root
  } else if (path.indexOf('*') !== -1) {
    throw new Error('Options.root must be specified with glob')
  }
  let stat
  try {
    stat = FS.statSync(path)
  } catch (_) {
    throw new Error(`Error reading ${path}`)
  }
  if (stat.isDirectory()) {
    return path
  } else if (stat.isFile()) {
    const fileDir = Path.dirname(path)
    const configFile = findFile(fileDir, '.ucompilerrc')
    if (configFile === null) {
      return fileDir
    } else {
      return Path.dirname(configFile)
    }
  } else throw new Error(`${path} is neither a file nor a directory`)
}

export function scanFiles(path, {root, ignored}) {
  if (path.indexOf('*') === -1) {
    // Non-Glob
    const absPath = Path.isAbsolute(path) ? path : Path.join(path, root)
    const stat = FS.statSync(absPath)
    if (stat.isFile()) {
      return [absPath]
    } else if (stat.isDirectory()) {
      let files = []
      FS.readdirSync(absPath).forEach(function(file) {
        const absFilePath = Path.join(absPath, file)
        const relativeFilePath = Path.relative(root, absFilePath)
        if (ignored.some(function(ignored) {
            return Minimatch(relativeFilePath, ignored)
          })) {
          return
        }
        let stat
        try {
          stat = FS.lstatSync(absFilePath)
        } catch (_) {
          throw new Error(`Error reading ${absFilePath}`)
        }
        if (!stat.isSymbolicLink()) {
          if (stat.isFile()) {
            files.push(relativeFilePath)
          } else if (stat.isDirectory()) {
            files = files.concat(scanFiles(absFilePath, {root, ignored}))
          }
        }
      })
      return files
    } else return []
  } else {
    // Glob
    return Glob.sync(path, {cwd: root, ignore: ignored})
  }
}

/** Config Helper */

export function getConfig(root) {
  const configFile = findFile(root, '.ucompilerrc')
  if (configFile !== null) {
    let config
    try {
      config = JSON.parse(FS.readFileSync(configFile, {encoding: 'utf8'}))
    } catch (e) {
      throw new Error(`Malformed configuration file located at ${configFile}`)
    }
    return Object.assign({}, DEFAULT_CONFIG, config)
  } else return DEFAULT_CONFIG
}

/** Saving Helper */

export function saveFile({contents, file, config}) {
  console.log(contents)
}
<|endoftext|>


<commit_before>'use strict';

import path from 'path';
import shorturl from 'shorturl';
import fs from 'fs';

/**
 * joins current dir and given filePath together
 *
 * @param filePath
 * @returns {string}
 */
export let buildLocalPath = (filePath, dir) => path.join(dir, filePath);

/**
 *
 * @param filePath
 */
export let getJSON = (filePath, dir) => fs.readFileSync(buildLocalPath(filePath, dir), 'utf8');

/**
 *
 * @param input
 */
export let parseJSON = input => JSON.parse(input);

/**
 * loads json config
 *
 * @param filePath
 * @returns {object}
 */
export let getConfig = (filePath, dir) => parseJSON(getJSON(filePath, dir));

/**
 * check if object has a specific property set (not undefined/null/false/empty string)
 *
 * @param prop
 * @returns {function(): boolean}
 */
export let hasPropSet = prop => {
    return obj => !!obj && (!!obj[prop] || obj[prop] === 0 || obj[prop] === '');
};

/**
 * check if an object has all properties set given by an array (not undefined/null/false/empty string)
 *
 * @param props
 * @returns {function(): boolean}
 */
export let hasAllPropsSet = props => {

    return obj => {

        return props.reduce((hasAll, prop) => {

            if (!hasAll) {
                return false;
            }
            else {
                return hasPropSet(prop)(obj);
            }
        }, true);
    };
};

export let anyHasPropSet = prop => {

    return arr => {

        return arr.reduce((anyHas, obj) => {

            if (anyHas) {
                return true;
            }
            else {
                return hasPropSet(prop)(obj);
            }
        }, false);
    };
};

/**
 * checks if object has property with a specific value
 *
 * @param prop
 * @param value
 * @returns {Function}
 */
export let hasPropValue = (prop, value) => {

    return el => el[prop] === value;
};

/**
 * checks if object has a specific value on property 'name'
 *
 * @param name
 * @returns {Function}
 */
export let hasNameValue = name => hasPropValue('name', name);

/**
 * filter array for specific objects with specific name property
 *
 * @param arr
 * @param name
 * @returns {Array}
 */
export let getByName = (arr, name) => arr.filter(hasNameValue(name));

/**
 * get's first object with specific name property
 *
 * @param arr
 * @param name
 * @returns {object}
 */
export let getFirstByName = (arr, name) => getByName(arr, name)[0];

/**
 * get comma separated string of name properties values from an array of objects
 *
 * @param arr
 * @returns {string}
 */
export let getNameList = arr => {
    return arr.reduce((list, category) => {

        if (list.length) {
            return `${list}, ${category.name}`
        }

        return category.name;
    }, '');
};

/**
 * get random entry from array
 *
 * @param arr
 * @returns {*}
 */
export let getRandomEntry = arr => arr[Math.floor(Math.random() * arr.length)];

/**
 * shorten url
 *
 * @param url
 * @returns {Promise}
 */
export let shortenUrl = url => {

    return new Promise(function (resolve, reject) {

        shorturl(url, result => {

            if (!result) {
                reject('shortenUrl: service not available');
            }
            else {
                resolve(result);
            }
        });
    });
};

/**
 * deep copy of an object
 *
 * @param obj
 */
export let copyObject = obj => JSON.parse(JSON.stringify(obj));

/**
 * deep copy of an array
 *
 * @param obj
 */
export let copyArray = arr => copyObject(arr);

/**
 * returns a new array sorted by a property value
 *
 * @param arr
 * @param prop
 * @returns {Array}
 */
export let sortByProp = (arr, prop) => {

    let copy = copyArray(arr);

    return copy.sort(function (a, b) {
        if (a[prop] > b[prop]) {
            return 1;
        }
        else if (a[prop] < b[prop]) {
            return -1;
        }

        return 0;
    });
};

/**
 * returns a new array sorted by a property value that is in a deeper level
 *
 *
 * @param arr
 * @param prop - e.g. '.user.purchases.average'
 * @returns {Array}
 */
export let sortByDeepProp = (arr, prop) => {

    let copy = JSON.parse(JSON.stringify(arr)),
        deepProp = prop.split('.');

    return copy.sort(function (a, b) {

        deepProp.reduce((full, curr) => {
            a = a[curr];
            b = b[curr];
        });

        if (a > b) {
            return 1;
        }
        else if (a < b) {
            return -1;
        }

        return 0;
    });
};<commit_msg>add array by 'type' filter<commit_after>'use strict';

import path from 'path';
import shorturl from 'shorturl';
import fs from 'fs';

/**
 * joins current dir and given filePath together
 *
 * @param filePath
 * @returns {string}
 */
export let buildLocalPath = (filePath, dir) => path.join(dir, filePath);

/**
 *
 * @param filePath
 */
export let getJSON = (filePath, dir) => fs.readFileSync(buildLocalPath(filePath, dir), 'utf8');

/**
 *
 * @param input
 */
export let parseJSON = input => JSON.parse(input);

/**
 * loads json config
 *
 * @param filePath
 * @returns {object}
 */
export let getConfig = (filePath, dir) => parseJSON(getJSON(filePath, dir));

/**
 * check if object has a specific property set (not undefined/null/false/empty string)
 *
 * @param prop
 * @returns {function(): boolean}
 */
export let hasPropSet = prop => {
    return obj => !!obj && (!!obj[prop] || obj[prop] === 0 || obj[prop] === '');
};

/**
 * check if an object has all properties set given by an array (not undefined/null/false/empty string)
 *
 * @param props
 * @returns {function(): boolean}
 */
export let hasAllPropsSet = props => {

    return obj => {

        return props.reduce((hasAll, prop) => {

            if (!hasAll) {
                return false;
            }
            else {
                return hasPropSet(prop)(obj);
            }
        }, true);
    };
};

export let anyHasPropSet = prop => {

    return arr => {

        return arr.reduce((anyHas, obj) => {

            if (anyHas) {
                return true;
            }
            else {
                return hasPropSet(prop)(obj);
            }
        }, false);
    };
};

/**
 * checks if object has property with a specific value
 *
 * @param prop
 * @param value
 * @returns {Function}
 */
export let hasPropValue = (prop, value) => {

    return el => el[prop] === value;
};

/**
 * checks if object has a specific value on property 'name'
 *
 * @param name
 * @returns {Function}
 */
export let hasNameValue = name => hasPropValue('name', name);

/**
 * checks if object has a specific value on property 'type'
 *
 * @param type
 * @returns {Function}
 */
export let hasTypeValue = type => hasPropValue('type', type);

/**
 * filter array for specific objects with specific name property
 *
 * @param arr
 * @param name
 * @returns {Array}
 */
export let getByName = (arr, name) => arr.filter(hasNameValue(name));

/**
 * filter array for specific objects with specific type property
 *
 * @param arr
 * @param type
 * @returns {Array}
 */
export let getByType = (arr, type) => arr.filter(hasTypeValue(type));

/**
 * get's first object with specific name property
 *
 * @param arr
 * @param name
 * @returns {object}
 */
export let getFirstByName = (arr, name) => getByName(arr, name)[0];

/**
 * get's first object with specific type property
 *
 * @param arr
 * @param type
 * @returns {object}
 */
export let getFirstByType = (arr, type) => getByType(arr, type)[0];

/**
 * get comma separated string of name properties values from an array of objects
 *
 * @param arr
 * @returns {string}
 */
export let getNameList = arr => {
    return arr.reduce((list, category) => {

        if (list.length) {
            return `${list}, ${category.name}`
        }

        return category.name;
    }, '');
};

/**
 * get random entry from array
 *
 * @param arr
 * @returns {*}
 */
export let getRandomEntry = arr => arr[Math.floor(Math.random() * arr.length)];

/**
 * shorten url
 *
 * @param url
 * @returns {Promise}
 */
export let shortenUrl = url => {

    return new Promise(function (resolve, reject) {

        shorturl(url, result => {

            if (!result) {
                reject('shortenUrl: service not available');
            }
            else {
                resolve(result);
            }
        });
    });
};

/**
 * deep copy of an object
 *
 * @param obj
 */
export let copyObject = obj => JSON.parse(JSON.stringify(obj));

/**
 * deep copy of an array
 *
 * @param obj
 */
export let copyArray = arr => copyObject(arr);

/**
 * returns a new array sorted by a property value
 *
 * @param arr
 * @param prop
 * @returns {Array}
 */
export let sortByProp = (arr, prop) => {

    let copy = copyArray(arr);

    return copy.sort(function (a, b) {
        if (a[prop] > b[prop]) {
            return 1;
        }
        else if (a[prop] < b[prop]) {
            return -1;
        }

        return 0;
    });
};

/**
 * returns a new array sorted by a property value that is in a deeper level
 *
 *
 * @param arr
 * @param prop - e.g. '.user.purchases.average'
 * @returns {Array}
 */
export let sortByDeepProp = (arr, prop) => {

    let copy = JSON.parse(JSON.stringify(arr)),
        deepProp = prop.split('.');

    return copy.sort(function (a, b) {

        deepProp.reduce((full, curr) => {
            a = a[curr];
            b = b[curr];
        });

        if (a > b) {
            return 1;
        }
        else if (a < b) {
            return -1;
        }

        return 0;
    });
};<|endoftext|>


<commit_before>// Validation errors messages for Parsley
import Parsley from '../parsley';

Parsley.addMessages('pl', {
  defaultMessage: "Wartość wygląda na nieprawidłową",
  type: {
    email:        "Wpisz poprawny adres e-mail.",
    url:          "Wpisz poprawny adres URL.",
    number:       "Wpisz poprawną liczbę.",
    integer:      "Dozwolone są jedynie liczby całkowite.",
    digits:       "Dozwolone są jedynie cyfry.",
    alphanum:     "Dozwolone są jedynie znaki alfanumeryczne."
  },
  notblank:       "Pole nie może być puste.",
  required:       "Pole jest wymagane.",
  pattern:        "Pole zawiera nieprawidłową wartość.",
  min:            "Wartość nie może być mniejsza od %s.",
  max:            "Wartość nie może być większa od %s.",
  range:          "Wartość powinna zaweriać się pomiędzy %s a %s.",
  minlength:      "Minimalna ilość znaków wynosi %s.",
  maxlength:      "Maksymalna ilość znaków wynosi %s.",
  length:         "Ilość znaków wynosi od %s do %s.",
  mincheck:       "Wybierz minimalnie %s opcji.",
  maxcheck:       "Wybierz maksymalnie %s opcji.",
  check:          "Wybierz od %s do %s opcji.",
  equalto:        "Wartości nie są identyczne."
});

Parsley.setLocale('pl');
<commit_msg>Improved Polish translation<commit_after>// Validation errors messages for Parsley
import Parsley from '../parsley';

Parsley.addMessages('pl', {
  defaultMessage: "Wartość wygląda na nieprawidłową",
  type: {
    email:        "Wpisz poprawny adres e-mail.",
    url:          "Wpisz poprawny adres URL.",
    number:       "Wpisz poprawną liczbę.",
    integer:      "Dozwolone są jedynie liczby całkowite.",
    digits:       "Dozwolone są jedynie cyfry.",
    alphanum:     "Dozwolone są jedynie znaki alfanumeryczne."
  },
  notblank:       "Pole nie może być puste.",
  required:       "Pole jest wymagane.",
  pattern:        "Pole zawiera nieprawidłową wartość.",
  min:            "Wartość nie może być mniejsza od %s.",
  max:            "Wartość nie może być większa od %s.",
  range:          "Wartość powinna zawierać się pomiędzy %s a %s.",
  minlength:      "Minimalna ilość znaków wynosi %s.",
  maxlength:      "Maksymalna ilość znaków wynosi %s.",
  length:         "Ilość znaków wynosi od %s do %s.",
  mincheck:       "Wybierz minimalnie %s opcji.",
  maxcheck:       "Wybierz maksymalnie %s opcji.",
  check:          "Wybierz od %s do %s opcji.",
  equalto:        "Wartości nie są identyczne."
});

Parsley.setLocale('pl');
<|endoftext|>