all files / src/ GridDispatch.js

100% Statements 60/60
100% Branches 44/44
100% Functions 9/9
100% Lines 60/60
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166                27×     26×                     28×     27×     26×       24×       23×       22× 22×     22×   22×                   13× 13× 13× 13× 13× 15× 15× 13× 13×       13× 15×                                                                                           10×                          
/* global GridHandler: true */
/**
 * Implements the top level registration of grid handlers and manages their
 * states.
 *
 * @param {Object} GridDispatch.grids  Collection of grid handlers
 * @constructor
 */
var GridDispatch = function() {
  if (!enquire) {
    throw new Error('enquire.js not present, please load it before calling any methods');
  }
 
  this.grids = {};
};
 
/**
 * Registers a single grid handler
 *
 * @param  {String} selector The selector of the grid element
 * @param  {Object} options  Defines the number of columns a grid should have
 *   for each media query registered.
 * @return {Object}          The dispatch object instance
 */
GridDispatch.prototype.init = function(selector, options) {
  if (!selector) {
    throw new TypeError('Missing selector');
  }
 
  if (typeof selector !== 'string') {
    throw new TypeError('Selector must be a string');
  }
 
  if (typeof options !== 'object') {
    throw new TypeError('Options must be an object');
  }
 
  // Prevent setting up the same grid selector more than once.
  if (this.grids[selector]) {
    return this;
  }
 
  // Do not act if element cannot be found.
  if (document.querySelectorAll(selector).length < 1) {
    return this;
  }
 
  // Construct GridHandlers and register them.
  this.grids[selector] = new GridHandler(selector, options);
  this.grids[selector].register(options);
 
  // Dispatch event.
  window.dispatchEvent(new CustomEvent('savvior:init'));
 
  return this;
};
 
/**
 * Restores one or all of the grids into their original state
 *
 * @param  {Array} selector     The selectors of the grids to destroy as given
 *   during the init call.
 * @param  {Function} callback  Optional. Callback function to call when done
 */
GridDispatch.prototype.destroy = function(selectors, callback) {
  var evt = new CustomEvent('savvior:destroy', {detail: {selectors: selectors}});
  var grids = (selectors === undefined || isEmpty(selectors)) ? Object.keys(this.grids) : selectors;
  var total = grids.length;
  var counter = 0;
  var done = function(args) {
    delete this.grids[grids[counter]];
    if (++counter === total) {
      window.dispatchEvent(evt);
      isFunction(callback) && callback.call(args, this);
    }
  }.bind(this);
 
  each(grids, function(selector) {
    (this.grids[selector]) && this.grids[selector].unregister(done);
  }, this);
};
 
/**
 * Tells if one or all the grids are initialised
 *
 * @param  {String} selector Optional. The selector of the grid used in init()
 * @return {Boolean}         If selector is given, returns a boolean value, or
 *   undefined if selector does not exist. If called without an argument, an
 *   array of ready grids is returned.
 */
GridDispatch.prototype.ready = function(selector) {
  if (selector === undefined) {
    var grids = [];
    for (var key in this.grids) {
      (this.grids[key].ready) && grids.push(key);
    }
    return (grids.length > 0) ? grids : false;
  }
 
  return (this.grids[selector]) ? this.grids[selector].ready : false;
};
 
/**
 * Add elements to a grid.
 *
 * @param  {String}   gridSelector The selector used to created the grid.
 * @param  {Mixed}    elements     A string, array of Nodes or a NodeList
 *   representing the elements to add to the grid.
 * @param  {Object}   options      An object of options. Optional.
 *   - method: can be 'append' or 'prepend' based on whether new items should be
 *     added to the front of the grid or the end. Default is append.
 *   - clone: set this to true when elements need copying not moving. Default is
 *     false
 * @param  {Function} callback     Callback function to execute after the
 *   elements are appended. The callback is called with the Grid instance.
 *   Optional.
 *
 * @return {Object}                GridDispatch instance.
 *
 * @see Grid.prototype.addItems
 */
GridDispatch.prototype.addItems = function (gridSelector, elements, options, callback) {
  var cb;
  var opts;
  var defaults = {
    clone: false,
    method: 'append'
  };
 
  // Check if the grid already exists.
  if (!this.grids[gridSelector]) {
    throw new TypeError('Grid does not exist.');
  }
 
  // If a selector is given, turn them into Element nodes.
  if (typeof elements === 'string') {
    elements = document.querySelectorAll(elements);
  }
 
  if (elements instanceof Array) {
    each(elements, function (el) {
      if (!(el instanceof Node)) {
        throw new TypeError('Supplied element in array is not instance of Node.');
      }
    }, this);
  }
  else if (!(elements instanceof Node) && !(elements instanceof NodeList)) {
    throw new TypeError('Supplied argument is not a Node or a NodeList.');
  }
 
  if (isFunction(options)) {
    cb = options;
    opts = defaults;
  }
  else {
    cb = callback;
    opts = extend(options, defaults);
  }
 
  each(this.grids[gridSelector].grids, function(grid) {
    grid.addItems(elements, opts, cb);
  });
 
  return this;
};