From 89c1e753045ae91e5b37834585b1eb98bfc7c2c2 Mon Sep 17 00:00:00 2001 From: Rufus Pollock Date: Sun, 11 Mar 2012 01:25:47 +0000 Subject: [PATCH] [build][xs]: latest version of recline.js. --- recline.js | 697 +++++++++++++++++++++++++++-------------------------- 1 file changed, 350 insertions(+), 347 deletions(-) diff --git a/recline.js b/recline.js index 3102ad36..0add56e4 100644 --- a/recline.js +++ b/recline.js @@ -989,353 +989,6 @@ my.DataGridRow = Backbone.View.extend({ this.recline = this.recline || {}; this.recline.View = this.recline.View || {}; -(function($, my) { -// ## DataExplorer -// -// The primary view for the entire application. Usage: -// -//
-// var myExplorer = new model.recline.DataExplorer({
-//   model: {{recline.Model.Dataset instance}}
-//   el: {{an existing dom element}}
-//   views: {{page views}}
-//   config: {{config options -- see below}}
-// });
-// 
-// -// ### Parameters -// -// **model**: (required) Dataset instance. -// -// **el**: (required) DOM element. -// -// **views**: (optional) the views (Grid, Graph etc) for DataExplorer to -// show. This is an array of view hashes. If not provided -// just initialize a DataGrid with id 'grid'. Example: -// -//
-// var views = [
-//   {
-//     id: 'grid', // used for routing
-//     label: 'Grid', // used for view switcher
-//     view: new recline.View.DataGrid({
-//       model: dataset
-//     })
-//   },
-//   {
-//     id: 'graph',
-//     label: 'Graph',
-//     view: new recline.View.FlotGraph({
-//       model: dataset
-//     })
-//   }
-// ];
-// 
-// -// **config**: Config options like: -// -// * readOnly: true/false (default: false) value indicating whether to -// operate in read-only mode (hiding all editing options). -// -// NB: the element already being in the DOM is important for rendering of -// FlotGraph subview. -my.DataExplorer = Backbone.View.extend({ - template: ' \ -
\ -
\ - \ -
\ - \ -
\ - Results found {{docCount}} \ -
\ -
\ -
\ - \ - \ -
\ - ', - - initialize: function(options) { - var self = this; - this.el = $(this.el); - this.config = _.extend({ - readOnly: false - }, - options.config); - if (this.config.readOnly) { - this.setReadOnly(); - } - // Hash of 'page' views (i.e. those for whole page) keyed by page name - if (options.views) { - this.pageViews = options.views; - } else { - this.pageViews = [{ - id: 'grid', - label: 'Grid', - view: new my.DataGrid({ - model: this.model - }) - }]; - } - // this must be called after pageViews are created - this.render(); - - this.router = new Backbone.Router(); - this.setupRouting(); - - this.model.bind('query:start', function() { - my.notify('Loading data', {loader: true}); - }); - this.model.bind('query:done', function() { - my.clearNotifications(); - self.el.find('.doc-count').text(self.model.docCount || 'Unknown'); - my.notify('Data loaded', {category: 'success'}); - }); - this.model.bind('query:fail', function(error) { - my.clearNotifications(); - var msg = ''; - if (typeof(error) == 'string') { - msg = error; - } else if (typeof(error) == 'object') { - if (error.title) { - msg = error.title + ': '; - } - if (error.message) { - msg += error.message; - } - } else { - msg = 'There was an error querying the backend'; - } - my.notify(msg, {category: 'error', persist: true}); - }); - - // retrieve basic data like fields etc - // note this.model and dataset returned are the same - this.model.fetch() - .done(function(dataset) { - self.el.find('.doc-count').text(self.model.docCount || 'Unknown'); - self.model.query(); - }) - .fail(function(error) { - my.notify(error.message, {category: 'error', persist: true}); - }); - }, - - setReadOnly: function() { - this.el.addClass('read-only'); - }, - - render: function() { - var tmplData = this.model.toTemplateJSON(); - tmplData.displayCount = this.config.displayCount; - tmplData.views = this.pageViews; - var template = $.mustache(this.template, tmplData); - $(this.el).html(template); - var $dataViewContainer = this.el.find('.data-view-container'); - _.each(this.pageViews, function(view, pageName) { - $dataViewContainer.append(view.view.el) - }); - var queryEditor = new my.QueryEditor({ - model: this.model.queryState - }); - this.el.find('.header').append(queryEditor.el); - }, - - setupRouting: function() { - var self = this; - // Default route - this.router.route('', this.pageViews[0].id, function() { - self.updateNav(self.pageViews[0].id); - }); - $.each(this.pageViews, function(idx, view) { - self.router.route(/^([^?]+)(\?.*)?/, 'view', function(viewId, queryString) { - self.updateNav(viewId, queryString); - }); - }); - }, - - updateNav: function(pageName, queryString) { - this.el.find('.navigation li').removeClass('active'); - this.el.find('.navigation li a').removeClass('disabled'); - var $el = this.el.find('.navigation li a[href=#' + pageName + ']'); - $el.parent().addClass('active'); - $el.addClass('disabled'); - // show the specific page - _.each(this.pageViews, function(view, idx) { - if (view.id === pageName) { - view.view.el.show(); - } else { - view.view.el.hide(); - } - }); - } -}); - - -my.QueryEditor = Backbone.View.extend({ - className: 'recline-query-editor', - template: ' \ -
\ - \ - \ - \ -
\ - ', - - events: { - 'submit form': 'onFormSubmit', - 'click .action-pagination-update': 'onPaginationUpdate' - }, - - initialize: function() { - _.bindAll(this, 'render'); - this.el = $(this.el); - this.model.bind('change', this.render); - this.render(); - }, - onFormSubmit: function(e) { - e.preventDefault(); - var newFrom = parseInt(this.el.find('input[name="from"]').val()); - var newSize = parseInt(this.el.find('input[name="to"]').val()) - newFrom; - var query = this.el.find('.text-query').val(); - this.model.set({size: newSize, from: newFrom, q: query}); - }, - onPaginationUpdate: function(e) { - e.preventDefault(); - var $el = $(e.target); - if ($el.parent().hasClass('prev')) { - var newFrom = this.model.get('from') - Math.max(0, this.model.get('size')); - } else { - var newFrom = this.model.get('from') + this.model.get('size'); - } - this.model.set({from: newFrom}); - }, - render: function() { - var tmplData = this.model.toJSON(); - tmplData.to = this.model.get('from') + this.model.get('size'); - var templated = $.mustache(this.template, tmplData); - this.el.html(templated); - } -}); - - -/* ========================================================== */ -// ## Miscellaneous Utilities - -var urlPathRegex = /^([^?]+)(\?.*)?/; - -// Parse the Hash section of a URL into path and query string -my.parseHashUrl = function(hashUrl) { - var parsed = urlPathRegex.exec(hashUrl); - if (parsed == null) { - return {}; - } else { - return { - path: parsed[1], - query: parsed[2] || '' - } - } -} - -// Parse a URL query string (?xyz=abc...) into a dictionary. -my.parseQueryString = function(q) { - var urlParams = {}, - e, d = function (s) { - return unescape(s.replace(/\+/g, " ")); - }, - r = /([^&=]+)=?([^&]*)/g; - - if (q && q.length && q[0] === '?') { - q = q.slice(1); - } - while (e = r.exec(q)) { - // TODO: have values be array as query string allow repetition of keys - urlParams[d(e[1])] = d(e[2]); - } - return urlParams; -} - -// Parse the query string out of the URL hash -my.parseHashQueryString = function() { - q = my.parseHashUrl(window.location.hash).query; - return my.parseQueryString(q); -} - -// Compse a Query String -my.composeQueryString = function(queryParams) { - var queryString = '?'; - var items = []; - $.each(queryParams, function(key, value) { - items.push(key + '=' + JSON.stringify(value)); - }); - queryString += items.join('&'); - return queryString; -} - -my.setHashQueryString = function(queryParams) { - window.location.hash = window.location.hash.split('?')[0] + my.composeQueryString(queryParams); -} - -// ## notify -// -// Create a notification (a div.alert in div.alert-messsages) using provide messages and options. Options are: -// -// * category: warning (default), success, error -// * persist: if true alert is persistent, o/w hidden after 3s (default = false) -// * loader: if true show loading spinner -my.notify = function(message, options) { - if (!options) var options = {}; - var tmplData = _.extend({ - msg: message, - category: 'warning' - }, - options); - var _template = ' \ -
× \ - {{msg}} \ - {{#loader}} \ -   \ - {{/loader}} \ -
'; - var _templated = $.mustache(_template, tmplData); - _templated = $(_templated).appendTo($('.data-explorer .alert-messages')); - if (!options.persist) { - setTimeout(function() { - $(_templated).fadeOut(1000, function() { - $(this).remove(); - }); - }, 1000); - } -} - -// ## clearNotifications -// -// Clear all existing notifications -my.clearNotifications = function() { - var $notifications = $('.data-explorer .alert-messages .alert'); - $notifications.remove(); -} - -})(jQuery, recline.View); - -this.recline = this.recline || {}; -this.recline.View = this.recline.View || {}; - // Views module following classic module pattern (function($, my) { @@ -1539,6 +1192,356 @@ my.ColumnTransform = Backbone.View.extend({ }); })(jQuery, recline.View); +this.recline = this.recline || {}; +this.recline.View = this.recline.View || {}; + +(function($, my) { +// ## DataExplorer +// +// The primary view for the entire application. Usage: +// +//
+// var myExplorer = new model.recline.DataExplorer({
+//   model: {{recline.Model.Dataset instance}}
+//   el: {{an existing dom element}}
+//   views: {{page views}}
+//   config: {{config options -- see below}}
+// });
+// 
+// +// ### Parameters +// +// **model**: (required) Dataset instance. +// +// **el**: (required) DOM element. +// +// **views**: (optional) the views (Grid, Graph etc) for DataExplorer to +// show. This is an array of view hashes. If not provided +// just initialize a DataGrid with id 'grid'. Example: +// +//
+// var views = [
+//   {
+//     id: 'grid', // used for routing
+//     label: 'Grid', // used for view switcher
+//     view: new recline.View.DataGrid({
+//       model: dataset
+//     })
+//   },
+//   {
+//     id: 'graph',
+//     label: 'Graph',
+//     view: new recline.View.FlotGraph({
+//       model: dataset
+//     })
+//   }
+// ];
+// 
+// +// **config**: Config options like: +// +// * readOnly: true/false (default: false) value indicating whether to +// operate in read-only mode (hiding all editing options). +// +// NB: the element already being in the DOM is important for rendering of +// FlotGraph subview. +my.DataExplorer = Backbone.View.extend({ + template: ' \ +
\ +
\ + \ +
\ + \ +
\ + Results found {{docCount}} \ +
\ +
\ +
\ + \ + \ +
\ + ', + + initialize: function(options) { + var self = this; + this.el = $(this.el); + this.config = _.extend({ + readOnly: false + }, + options.config); + if (this.config.readOnly) { + this.setReadOnly(); + } + // Hash of 'page' views (i.e. those for whole page) keyed by page name + if (options.views) { + this.pageViews = options.views; + } else { + this.pageViews = [{ + id: 'grid', + label: 'Grid', + view: new my.DataGrid({ + model: this.model + }) + }]; + } + // this must be called after pageViews are created + this.render(); + + this.router = new Backbone.Router(); + this.setupRouting(); + + this.model.bind('query:start', function() { + my.notify('Loading data', {loader: true}); + }); + this.model.bind('query:done', function() { + my.clearNotifications(); + self.el.find('.doc-count').text(self.model.docCount || 'Unknown'); + my.notify('Data loaded', {category: 'success'}); + }); + this.model.bind('query:fail', function(error) { + my.clearNotifications(); + var msg = ''; + if (typeof(error) == 'string') { + msg = error; + } else if (typeof(error) == 'object') { + if (error.title) { + msg = error.title + ': '; + } + if (error.message) { + msg += error.message; + } + } else { + msg = 'There was an error querying the backend'; + } + my.notify(msg, {category: 'error', persist: true}); + }); + + // retrieve basic data like fields etc + // note this.model and dataset returned are the same + this.model.fetch() + .done(function(dataset) { + self.el.find('.doc-count').text(self.model.docCount || 'Unknown'); + self.model.query(); + }) + .fail(function(error) { + my.notify(error.message, {category: 'error', persist: true}); + }); + }, + + setReadOnly: function() { + this.el.addClass('read-only'); + }, + + render: function() { + var tmplData = this.model.toTemplateJSON(); + tmplData.displayCount = this.config.displayCount; + tmplData.views = this.pageViews; + var template = $.mustache(this.template, tmplData); + $(this.el).html(template); + var $dataViewContainer = this.el.find('.data-view-container'); + _.each(this.pageViews, function(view, pageName) { + $dataViewContainer.append(view.view.el) + }); + var queryEditor = new my.QueryEditor({ + model: this.model.queryState + }); + this.el.find('.header').append(queryEditor.el); + }, + + setupRouting: function() { + var self = this; + // Default route + this.router.route('', this.pageViews[0].id, function() { + self.updateNav(self.pageViews[0].id); + }); + $.each(this.pageViews, function(idx, view) { + self.router.route(/^([^?]+)(\?.*)?/, 'view', function(viewId, queryString) { + self.updateNav(viewId, queryString); + }); + }); + }, + + updateNav: function(pageName, queryString) { + this.el.find('.navigation li').removeClass('active'); + this.el.find('.navigation li a').removeClass('disabled'); + var $el = this.el.find('.navigation li a[href=#' + pageName + ']'); + $el.parent().addClass('active'); + $el.addClass('disabled'); + // show the specific page + _.each(this.pageViews, function(view, idx) { + if (view.id === pageName) { + view.view.el.show(); + } else { + view.view.el.hide(); + } + }); + } +}); + + +my.QueryEditor = Backbone.View.extend({ + className: 'recline-query-editor', + template: ' \ +
\ +
\ + \ + \ +
\ + \ + \ +
\ + ', + + events: { + 'submit form': 'onFormSubmit', + 'click .action-pagination-update': 'onPaginationUpdate' + }, + + initialize: function() { + _.bindAll(this, 'render'); + this.el = $(this.el); + this.model.bind('change', this.render); + this.render(); + }, + onFormSubmit: function(e) { + e.preventDefault(); + var newFrom = parseInt(this.el.find('input[name="from"]').val()); + var newSize = parseInt(this.el.find('input[name="to"]').val()) - newFrom; + var query = this.el.find('.text-query input').val(); + this.model.set({size: newSize, from: newFrom, q: query}); + }, + onPaginationUpdate: function(e) { + e.preventDefault(); + var $el = $(e.target); + if ($el.parent().hasClass('prev')) { + var newFrom = this.model.get('from') - Math.max(0, this.model.get('size')); + } else { + var newFrom = this.model.get('from') + this.model.get('size'); + } + this.model.set({from: newFrom}); + }, + render: function() { + var tmplData = this.model.toJSON(); + tmplData.to = this.model.get('from') + this.model.get('size'); + var templated = $.mustache(this.template, tmplData); + this.el.html(templated); + } +}); + + +/* ========================================================== */ +// ## Miscellaneous Utilities + +var urlPathRegex = /^([^?]+)(\?.*)?/; + +// Parse the Hash section of a URL into path and query string +my.parseHashUrl = function(hashUrl) { + var parsed = urlPathRegex.exec(hashUrl); + if (parsed == null) { + return {}; + } else { + return { + path: parsed[1], + query: parsed[2] || '' + } + } +} + +// Parse a URL query string (?xyz=abc...) into a dictionary. +my.parseQueryString = function(q) { + var urlParams = {}, + e, d = function (s) { + return unescape(s.replace(/\+/g, " ")); + }, + r = /([^&=]+)=?([^&]*)/g; + + if (q && q.length && q[0] === '?') { + q = q.slice(1); + } + while (e = r.exec(q)) { + // TODO: have values be array as query string allow repetition of keys + urlParams[d(e[1])] = d(e[2]); + } + return urlParams; +} + +// Parse the query string out of the URL hash +my.parseHashQueryString = function() { + q = my.parseHashUrl(window.location.hash).query; + return my.parseQueryString(q); +} + +// Compse a Query String +my.composeQueryString = function(queryParams) { + var queryString = '?'; + var items = []; + $.each(queryParams, function(key, value) { + items.push(key + '=' + JSON.stringify(value)); + }); + queryString += items.join('&'); + return queryString; +} + +my.setHashQueryString = function(queryParams) { + window.location.hash = window.location.hash.split('?')[0] + my.composeQueryString(queryParams); +} + +// ## notify +// +// Create a notification (a div.alert in div.alert-messsages) using provide messages and options. Options are: +// +// * category: warning (default), success, error +// * persist: if true alert is persistent, o/w hidden after 3s (default = false) +// * loader: if true show loading spinner +my.notify = function(message, options) { + if (!options) var options = {}; + var tmplData = _.extend({ + msg: message, + category: 'warning' + }, + options); + var _template = ' \ +
× \ + {{msg}} \ + {{#loader}} \ +   \ + {{/loader}} \ +
'; + var _templated = $.mustache(_template, tmplData); + _templated = $(_templated).appendTo($('.data-explorer .alert-messages')); + if (!options.persist) { + setTimeout(function() { + $(_templated).fadeOut(1000, function() { + $(this).remove(); + }); + }, 1000); + } +} + +// ## clearNotifications +// +// Clear all existing notifications +my.clearNotifications = function() { + var $notifications = $('.data-explorer .alert-messages .alert'); + $notifications.remove(); +} + +})(jQuery, recline.View); + // # Recline Backends // // Backends are connectors to backend data sources and stores