UNPKG

forerunnerdb

Version:

A NoSQL document store database for browsers and Node.js.

742 lines (616 loc) 21.2 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: Grid.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: Grid.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>"use strict"; // Import external names locally var Shared, Db, Collection, CollectionGroup, View, CollectionInit, DbInit, ReactorIO; //Shared = ForerunnerDB.shared; Shared = require('./Shared'); /** * Creates a new grid instance. * @name Grid * @class Grid * @param {String} selector jQuery selector. * @param {String} template The template selector. * @param {Object=} options The options object to apply to the grid. * @constructor */ var Grid = function (selector, template, options) { this.init.apply(this, arguments); }; Grid.prototype.init = function (selector, template, options) { var self = this; this._selector = selector; this._template = template; this._options = options || {}; this._debug = {}; this._id = this.objectId(); this._collectionDroppedWrap = function () { self._collectionDropped.apply(self, arguments); }; }; Shared.addModule('Grid', Grid); Shared.mixin(Grid.prototype, 'Mixin.Common'); Shared.mixin(Grid.prototype, 'Mixin.ChainReactor'); Shared.mixin(Grid.prototype, 'Mixin.Constants'); Shared.mixin(Grid.prototype, 'Mixin.Triggers'); Shared.mixin(Grid.prototype, 'Mixin.Events'); Collection = require('./Collection'); CollectionGroup = require('./CollectionGroup'); View = require('./View'); ReactorIO = require('./ReactorIO'); CollectionInit = Collection.prototype.init; Db = Shared.modules.Db; DbInit = Db.prototype.init; /** * Gets / sets the current state. * @func state * @memberof Grid * @param {String=} val The name of the state to set. * @returns {Grid} */ Shared.synthesize(Grid.prototype, 'state'); /** * Gets / sets the current name. * @func name * @memberof Grid * @param {String=} val The name to set. * @returns {Grid} */ Shared.synthesize(Grid.prototype, 'name'); /** * Executes an insert against the grid's underlying data-source. * @func insert * @memberof Grid */ Grid.prototype.insert = function () { this._from.insert.apply(this._from, arguments); }; /** * Executes an update against the grid's underlying data-source. * @func update * @memberof Grid */ Grid.prototype.update = function () { this._from.update.apply(this._from, arguments); }; /** * Executes an updateById against the grid's underlying data-source. * @func updateById * @memberof Grid */ Grid.prototype.updateById = function () { this._from.updateById.apply(this._from, arguments); }; /** * Executes a remove against the grid's underlying data-source. * @func remove * @memberof Grid */ Grid.prototype.remove = function () { this._from.remove.apply(this._from, arguments); }; /** * Sets the collection from which the grid will assemble its data. * @func from * @memberof Grid * @param {Collection} collection The collection to use to assemble grid data. * @returns {Grid} */ Grid.prototype.from = function (collection) { //var self = this; if (collection !== undefined) { // Check if we have an existing from if (this._from) { // Remove the listener to the drop event this._from.off('drop', this._collectionDroppedWrap); this._from._removeGrid(this); } if (typeof(collection) === 'string') { collection = this._db.collection(collection); } this._from = collection; this._from.on('drop', this._collectionDroppedWrap); this.refresh(); } return this; }; /** * Gets / sets the db instance this class instance belongs to. * @func db * @memberof Grid * @param {Db=} db The db instance. * @returns {*} */ Shared.synthesize(Grid.prototype, 'db', function (db) { if (db) { // Apply the same debug settings this.debug(db.debug()); } return this.$super.apply(this, arguments); }); Grid.prototype._collectionDropped = function (collection) { if (collection) { // Collection was dropped, remove from grid delete this._from; } }; /** * Drops a grid and all it's stored data from the database. * @func drop * @memberof Grid * @returns {boolean} True on success, false on failure. */ Grid.prototype.drop = function () { if (!this.isDropped()) { if (this._from) { // Remove data-binding this._from.unlink(this._selector, this.template()); // Kill listeners and references this._from.off('drop', this._collectionDroppedWrap); this._from._removeGrid(this); if (this.debug() || (this._db &amp;&amp; this._db.debug())) { console.log(this.logIdentifier() + ' Dropping grid ' + this._selector); } this._state = 'dropped'; if (this._db &amp;&amp; this._selector) { delete this._db._grid[this._selector]; } this.emit('drop', this); delete this._selector; delete this._template; delete this._from; delete this._db; return true; } } else { return true; } return false; }; /** * Gets / sets the grid's HTML template to use when rendering. * @func template * @memberof Grid * @param {Selector} template The template's jQuery selector. * @returns {*} */ Grid.prototype.template = function (template) { if (template !== undefined) { this._template = template; return this; } return this._template; }; Grid.prototype._sortGridClick = function (e) { var elem = window.jQuery(e.currentTarget), sortColText = elem.attr('data-grid-sort') || '', sortColDir = parseInt((elem.attr('data-grid-dir') || "-1"), 10) === -1 ? 1 : -1, sortCols = sortColText.split(','), sortObj = {}, i; // Remove all grid sort tags from the grid window.jQuery(this._selector).find('[data-grid-dir]').removeAttr('data-grid-dir'); // Flip the sort direction elem.attr('data-grid-dir', sortColDir); for (i = 0; i &lt; sortCols.length; i++) { sortObj[sortCols] = sortColDir; } Shared.mixin(sortObj, this._options.$orderBy); this._from.orderBy(sortObj); this.emit('sort', sortObj); }; /** * Refreshes the grid data such as ordering etc. * @func refresh * @memberof Grid */ Grid.prototype.refresh = function () { if (this._from) { if (this._from.link) { var self = this, elem = window.jQuery(this._selector), sortClickListener = function () { self._sortGridClick.apply(self, arguments); }; // Clear the container elem.html(''); if (self._from.orderBy) { // Remove listeners elem.off('click', '[data-grid-sort]', sortClickListener); } if (self._from.query) { // Remove listeners elem.off('click', '[data-grid-filter]', sortClickListener ); } // Set wrap name if none is provided self._options.$wrap = self._options.$wrap || 'gridRow'; // Auto-bind the data to the grid template self._from.link(self._selector, self.template(), self._options); // Check if the data source (collection or view) has an // orderBy method (usually only views) and if so activate // the sorting system if (self._from.orderBy) { // Listen for sort requests elem.on('click', '[data-grid-sort]', sortClickListener); } if (self._from.query) { // Listen for filter requests var queryObj = {}; elem.find('[data-grid-filter]').each(function (index, filterElem) { filterElem = window.jQuery(filterElem); var filterField = filterElem.attr('data-grid-filter'), filterVarType = filterElem.attr('data-grid-vartype'), filterSort = {}, title = filterElem.html(), dropDownButton, dropDownMenu, template, filterQuery, filterView = self._db.view('tmpGridFilter_' + self._id + '_' + filterField); filterSort[filterField] = 1; filterQuery = { $distinct: filterSort }; filterView .query(filterQuery) .orderBy(filterSort) .from(self._from._from); template = [ '&lt;div class="dropdown" id="' + self._id + '_' + filterField + '">', '&lt;button class="btn btn-default dropdown-toggle" type="button" id="' + self._id + '_' + filterField + '_dropdownButton" data-toggle="dropdown" aria-expanded="true">', title + ' &lt;span class="caret">&lt;/span>', '&lt;/button>', '&lt;/div>' ]; dropDownButton = window.jQuery(template.join('')); dropDownMenu = window.jQuery('&lt;ul class="dropdown-menu" role="menu" id="' + self._id + '_' + filterField + '_dropdownMenu">&lt;/ul>'); dropDownButton.append(dropDownMenu); filterElem.html(dropDownButton); // Data-link the underlying data to the grid filter drop-down filterView.link(dropDownMenu, { template: [ '&lt;li role="presentation" class="input-group" style="width: 240px; padding-left: 10px; padding-right: 10px; padding-top: 5px;">', '&lt;input type="search" class="form-control gridFilterSearch" placeholder="Search...">', '&lt;span class="input-group-btn">', '&lt;button class="btn btn-default gridFilterClearSearch" type="button">&lt;span class="glyphicon glyphicon-remove-circle glyphicons glyphicons-remove">&lt;/span>&lt;/button>', '&lt;/span>', '&lt;/li>', '&lt;li role="presentation" class="divider">&lt;/li>', '&lt;li role="presentation" data-val="$all">', '&lt;a role="menuitem" tabindex="-1">', '&lt;input type="checkbox" checked>&amp;nbsp;All', '&lt;/a>', '&lt;/li>', '&lt;li role="presentation" class="divider">&lt;/li>', '{^{for options}}', '&lt;li role="presentation" data-link="data-val{:' + filterField + '}">', '&lt;a role="menuitem" tabindex="-1">', '&lt;input type="checkbox">&amp;nbsp;{^{:' + filterField + '}}', '&lt;/a>', '&lt;/li>', '{{/for}}' ].join('') }, { $wrap: 'options' }); elem.on('keyup', '#' + self._id + '_' + filterField + '_dropdownMenu .gridFilterSearch', function (e) { var elem = window.jQuery(this), query = filterView.query(), search = elem.val(); if (search) { query[filterField] = new RegExp(search, 'gi'); } else { delete query[filterField]; } filterView.query(query); }); elem.on('click', '#' + self._id + '_' + filterField + '_dropdownMenu .gridFilterClearSearch', function (e) { // Clear search text box window.jQuery(this).parents('li').find('.gridFilterSearch').val(''); // Clear view query var query = filterView.query(); delete query[filterField]; filterView.query(query); }); elem.on('click', '#' + self._id + '_' + filterField + '_dropdownMenu li', function (e) { e.stopPropagation(); var fieldValue, elem = $(this), checkbox = elem.find('input[type="checkbox"]'), checked, addMode = true, fieldInArr, liElem, i; // If the checkbox is not the one clicked on if (!window.jQuery(e.target).is('input')) { // Set checkbox to opposite of current value checkbox.prop('checked', !checkbox.prop('checked')); checked = checkbox.is(':checked'); } else { checkbox.prop('checked', checkbox.prop('checked')); checked = checkbox.is(':checked'); } liElem = window.jQuery(this); fieldValue = liElem.attr('data-val'); // Check if the selection is the "all" option if (fieldValue === '$all') { // Remove the field from the query delete queryObj[filterField]; // Clear all other checkboxes liElem.parent().find('li[data-val!="$all"]').find('input[type="checkbox"]').prop('checked', false); } else { // Clear the "all" checkbox liElem.parent().find('[data-val="$all"]').find('input[type="checkbox"]').prop('checked', false); // Check if the type needs casting switch (filterVarType) { case 'integer': fieldValue = parseInt(fieldValue, 10); break; case 'float': fieldValue = parseFloat(fieldValue); break; default: } // Check if the item exists already queryObj[filterField] = queryObj[filterField] || { $in: [] }; fieldInArr = queryObj[filterField].$in; for (i = 0; i &lt; fieldInArr.length; i++) { if (fieldInArr[i] === fieldValue) { // Item already exists if (checked === false) { // Remove the item fieldInArr.splice(i, 1); } addMode = false; break; } } if (addMode &amp;&amp; checked) { fieldInArr.push(fieldValue); } if (!fieldInArr.length) { // Remove the field from the query delete queryObj[filterField]; } } // Set the view query self._from.queryData(queryObj); if (self._from.pageFirst) { self._from.pageFirst(); } }); }); } self.emit('refresh'); } else { throw('Grid requires the AutoBind module in order to operate!'); } } return this; }; /** * Returns the number of documents currently in the grid. * @func count * @memberof Grid * @returns {Number} */ Grid.prototype.count = function () { return this._from.count(); }; /** * Creates a grid and assigns the collection as its data source. * @func grid * @memberof Collection * @param {String} selector jQuery selector of grid output target. * @param {String} template The table template to use when rendering the grid. * @param {Object=} options The options object to apply to the grid. * @returns {*} */ Collection.prototype.grid = View.prototype.grid = function (selector, template, options) { if (this._db &amp;&amp; this._db._grid ) { if (selector !== undefined) { if (template !== undefined) { if (!this._db._grid[selector]) { var grid = new Grid(selector, template, options) .db(this._db) .from(this); this._grid = this._grid || []; this._grid.push(grid); this._db._grid[selector] = grid; return grid; } else { throw(this.logIdentifier() + ' Cannot create a grid because a grid with this name already exists: ' + selector); } } return this._db._grid[selector]; } return this._db._grid; } }; /** * Removes a grid safely from the DOM. Must be called when grid is * no longer required / is being removed from DOM otherwise references * will stick around and cause memory leaks. * @func unGrid * @memberof Collection * @param {String} selector jQuery selector of grid output target. * @param {String} template The table template to use when rendering the grid. * @param {Object=} options The options object to apply to the grid. * @returns {*} */ Collection.prototype.unGrid = View.prototype.unGrid = function (selector, template, options) { var i, grid; if (this._db &amp;&amp; this._db._grid ) { if (selector &amp;&amp; template) { if (this._db._grid[selector]) { grid = this._db._grid[selector]; delete this._db._grid[selector]; return grid.drop(); } else { throw(this.logIdentifier() + ' Cannot remove grid because a grid with this name does not exist: ' + name); } } else { // No parameters passed, remove all grids from this module for (i in this._db._grid) { if (this._db._grid.hasOwnProperty(i)) { grid = this._db._grid[i]; delete this._db._grid[i]; grid.drop(); if (this.debug()) { console.log(this.logIdentifier() + ' Removed grid binding "' + i + '"'); } } } this._db._grid = {}; } } }; /** * Adds a grid to the internal grid lookup. * @func _addGrid * @memberof Collection * @param {Grid} grid The grid to add. * @returns {Collection} * @private */ Collection.prototype._addGrid = CollectionGroup.prototype._addGrid = View.prototype._addGrid = function (grid) { if (grid !== undefined) { this._grid = this._grid || []; this._grid.push(grid); } return this; }; /** * Removes a grid from the internal grid lookup. * @func _removeGrid * @memberof Collection * @param {Grid} grid The grid to remove. * @returns {Collection} * @private */ Collection.prototype._removeGrid = CollectionGroup.prototype._removeGrid = View.prototype._removeGrid = function (grid) { if (grid !== undefined &amp;&amp; this._grid) { var index = this._grid.indexOf(grid); if (index > -1) { this._grid.splice(index, 1); } } return this; }; // Extend DB with grids init Db.prototype.init = function () { this._grid = {}; DbInit.apply(this, arguments); }; /** * Determine if a grid with the passed name already exists. * @func gridExists * @memberof Db * @param {String} selector The jQuery selector to bind the grid to. * @returns {boolean} */ Db.prototype.gridExists = function (selector) { return Boolean(this._grid[selector]); }; /** * Creates a grid based on the passed arguments. * @func grid * @memberof Db * @param {String} selector The jQuery selector of the grid to retrieve. * @param {String} template The table template to use when rendering the grid. * @param {Object=} options The options object to apply to the grid. * @returns {*} */ Db.prototype.grid = function (selector, template, options) { if (!this._grid[selector]) { if (this.debug() || (this._db &amp;&amp; this._db.debug())) { console.log(this.logIdentifier() + ' Creating grid ' + selector); } } this._grid[selector] = this._grid[selector] || new Grid(selector, template, options).db(this); return this._grid[selector]; }; /** * Removes a grid based on the passed arguments. * @func unGrid * @memberof Db * @param {String} selector The jQuery selector of the grid to retrieve. * @param {String} template The table template to use when rendering the grid. * @param {Object=} options The options object to apply to the grid. * @returns {*} */ Db.prototype.unGrid = function (selector, template, options) { if (!this._grid[selector]) { if (this.debug() || (this._db &amp;&amp; this._db.debug())) { console.log(this.logIdentifier() + ' Creating grid ' + selector); } } this._grid[selector] = this._grid[selector] || new Grid(selector, template, options).db(this); return this._grid[selector]; }; /** * Returns an array of grids the DB currently has. * @func grids * @memberof Db * @returns {Array} An array of objects containing details of each grid * the database is currently managing. */ Db.prototype.grids = function () { var arr = [], item, i; for (i in this._grid) { if (this._grid.hasOwnProperty(i)) { item = this._grid[i]; arr.push({ name: i, count: item.count(), linked: item.isLinked !== undefined ? item.isLinked() : false }); } } return arr; }; Shared.finishModule('Grid'); module.exports = Grid;</code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="ActiveBucket.html">ActiveBucket</a></li><li><a href="Angular.html">Angular</a></li><li><a href="AutoBind.html">AutoBind</a></li><li><a href="BinaryTree.html">BinaryTree</a></li><li><a href="Collection.html">Collection</a></li><li><a href="CollectionGroup.html">CollectionGroup</a></li><li><a href="Core.html">Core</a></li><li><a href="Db.html">Db</a></li><li><a href="Document.html">Document</a></li><li><a href="Grid.html">Grid</a></li><li><a href="Highchart.html">Highchart</a></li><li><a href="IndexBinaryTree.html">IndexBinaryTree</a></li><li><a href="IndexHashMap.html">IndexHashMap</a></li><li><a href="Infinilist.html">Infinilist</a></li><li><a href="KeyValueStore.html">KeyValueStore</a></li><li><a href="Metrics.html">Metrics</a></li><li><a href="OldView.html">OldView</a></li><li><a href="Operation.html">Operation</a></li><li><a href="Overload.html">Overload</a></li><li><a href="Path.html">Path</a></li><li><a href="Persist.html">Persist</a></li><li><a href="ReactorIO.html">ReactorIO</a></li><li><a href="Serialiser.html">Serialiser</a></li><li><a href="Shared.overload.html">overload</a></li><li><a href="View.html">View</a></li></ul><h3>Mixins</h3><ul><li><a href="ChainReactor.html">ChainReactor</a></li><li><a href="crcTable.html">crcTable</a></li><li><a href="Shared.html">Shared</a></li></ul><h3>Global</h3><ul><li><a href="global.html#%2522boolean,function%2522">"boolean, function"</a></li><li><a href="global.html#%2522string,*,function%2522">"string, *, function"</a></li><li><a href="global.html#%2522string,function%2522">"string, function"</a></li><li><a href="global.html#boolean">boolean</a></li><li><a href="global.html#function">function</a></li></ul> </nav> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.3.3</a> on Thu Nov 19 2015 13:31:32 GMT+0000 (GMT) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>