o: ActiveSupport::Cache::Entry :@compressedF:@expires_in0:@created_atf1349975508.3463418: @value"*{I" class:EFI"ProcessedAsset;FI"logical_path;FI"tableling-core.js;FI" pathname;FI"W/Users/unknow/Projects/tableling-rails/vendor/assets/javascripts/tableling-core.js;FI"content_type;FI"application/javascript;FI" mtime;FI"2012-10-11T19:11:18+02:00;FI" length;Fiè&I" digest;F"%fb400bb9c67935333b2c85f9b9546a9aI" source;FI"è&/*! * Tableling v0.0.3 * Copyright (c) 2012 Simon Oulevay (Alpha Hydrae) * Distributed under MIT license * https://github.com/AlphaHydrae/tableling */ (function(module) { // Tableling // --------- // // A tableling table is a Marionette layout which fetches data // from a Backbone collection. It is controlled with an EventAggregator. module.Tableling = Tableling = Backbone.Marionette.Layout.extend({ className: 'tableling', // Default table options can be overriden by subclasses. tableling : { page : 1, pageSize : 15 }, initialize : function(options) { options = options || {}; // Table options can also be overriden for each instance by passing // a `tableling` object in the options. this.tableling = _.extend(_.clone(this.tableling), options.tableling || {}); // We use an event aggregator to manage the layout and its components. // You can use your own by passing a `vent` option. this.vent = options.vent || new Backbone.Marionette.EventAggregator(); // Components should trigger the `tableling:update` event to update // the table (e.g. change page size, sort) and fetch the new data. this.vent.on('tableling:update', this.update, this); this.on('render', this.setup, this); }, // Called once rendering is complete. By default, it updates the table. setup : function() { this.vent.trigger('tableling:update'); }, // Subclasses must return the Backbone.Collection used to fetch data. getCollection : function() { throw new Error('#getCollection not implemented. It should return the Backbone.Collection instance used to fetch data.'); }, // ### Refreshing the table update : function(config, options) { _.each(this.filterConfig(config || {}), _.bind(this.updateValue, this)); // Set the `refresh` option to false to update the table configuration // without refreshing. if (!options || typeof(options.refresh) == 'undefined' || options.refresh) { this.refresh(); } }, updateValue : function(value, key) { if (value && value.toString().length) { this.tableling[key] = value; } else { // Blank values are deleted to avoid sending them in ajax requests. delete this.tableling[key]; } }, refresh : function() { // `tableling:refreshing` is triggered every time new data is being fetched. // The first argument is the request data. var data = this.requestData(); this.ventTrigger('tableling:refreshing', data); // You can provide a `tableling.request` option to add properties to the // fetch request. // // var MyTable = Tableling.extend({ // tableling : { // type : 'POST' // fetch data with POST // } // }); this.getCollection().fetch(_.extend(this.tableling.request || {}, { data: data, success: _.bind(this.processResponse, this) })); }, // ### Response processResponse : function(collection, response) { this.tableling.length = collection.length; // Tableling expects the response from a fetch to have a `total` property // which is the total number of items (not just in the current page). this.tableling.total = response.total; // `tableling:refreshed` is triggered after every refresh. The first argument // is the current table configuration with the following additional meta data: // // * `total` - the total number of items // * `length` - the number of items in the current page this.ventTrigger('tableling:refreshed', this.filterConfig(this.tableling, true)); }, // ### Request // Builds the request data. Subclasses may override this if they need to // send additional data. requestData : function() { return this.filterConfig(this.tableling); }, // ### Utilities // Whitelists the given configuration to contain only table configuration properties. // Pass `true` as the second argument to include meta data (i.e. total & length). filterConfig : function(config, all) { if (all) { return _.pick(config, 'page', 'pageSize', 'quickSearch', 'sort', 'length', 'total'); } else { return _.pick(config, 'page', 'pageSize', 'quickSearch', 'sort'); } }, // Triggers an event in the event aggregator. If `Tableling.debug` is set, it also // logs the event and its arguments. ventTrigger : function() { var args = Array.prototype.slice.call(arguments); this.vent.trigger.apply(this.vent, args); if (Tableling.debug) { console.log(args.shift() + ' - ' + JSON.stringify(args)); } } }); // Tableling.Collection // -------------------- // // Tableling expects fetch responses to have a `total` property in addition // to the model data. You can extend this Backbone.Collection subclass which // expects the following response format: // // { // "total": 12, // "data": [ // { /* ... model data ... */ }, // { /* ... model data ... */ } // ] // } Tableling.Collection = Backbone.Collection.extend({ parse : function(response) { return response.data; } }); // Tableling.Modular // ----------------- // // Tableling subclass which splits functionality into *modules* // and handles rendering. Tableling.Modular = Tableling.extend({ // The list of module names must be specified by subclasses. modules : [], // Modules are set up after rendering, before refreshing. setup : function() { this.moduleViews = {}; _.each(this.modules, _.bind(this.setupModule, this)); Tableling.prototype.setup.call(this); }, // ### Modules // Each module is identified by a name, for example `pageSize`. setupModule : function(name) { // The layout must have a region named after the module, e.g. `pageSizeRegion`. var region = name + 'Region'; // It must have a view class, e.g. `pageSizeView`, which will be shown into // the region. var viewClass = this[name + 'View']; // When instantiated, the view class will be passed the event // aggregator as the `vent` option. Additional options can be // given named after the view class, e.g. `pageSizeViewOptions`. var options = _.extend(this[name + 'ViewOptions'] || {}, { vent: this.vent }); var view = new viewClass(options); // Module view instances are stored by name in the `moduleViews` property // for future reference. this.moduleViews[name] = view; this[region].show(view); return view; }, // By default, a modular table expects a `table` module which // should have a collection (e.g. a Marionette CompositeView or // CollectionView). If your subclass does not have that, it // should override this method to return the Backbone.Collection // used to fetch table data. getCollection : function() { return this.moduleViews.table.collection; } }); // ### Example // This is how a `PageSizeView` module might be registered in a subclass: // // var MyTable = Tableling.Modular.extend({ // // modules : [ 'pageSize' ], // // pageSizeView : PageSizeView, // pageSizeViewOptions : { // itemView : PageSizeItem // }, // // regions : { // pageSizeRegion : '.pageSize' // } // }); // ### Utilities _.extend(Tableling.Modular, { // **createModule** creates an item view that is automatically bound // to the layout's event aggregator. createModule : function(options) { return Backbone.Marionette.ItemView.extend(_.extend({ initialize : function(options) { this.vent = options.vent; // The `refresh` method of the view is called once the view is rendered // and every time the table is refreshed. this.vent.on('tableling:refreshed', this.refresh, this); this.on('render', this.refresh, this); }, // Call `update` to trigger an update of the table. update : function() { this.vent.trigger('tableling:update', this.config()); }, // Implementations should override this to stay up to date with // the table state. Note that the data parameter will be undefined // on the first refresh when the view is rendered. refresh : function(data) { }, // New table configuration to be sent on updates. For example, // a page size view might update the `pageSize` property. config : function() { return {}; } }, options)); }, // **createFieldModule** creates a basic module with a single form field. // It comes with sensible defaults and only requires a `template` parameter. createFieldModule : function(name, options) { var definition = { // The name attribute of the form field is expected to be the name of // the module, e.g. `pageSize`. ui : { field : '[name="' + name + '"]' }, events : {}, // The table property updated is the one with the same name as the module. config : function() { var config = {}; config[name] = this.ui.field.val(); return config; } }; // The `change` even triggers an update. definition.events['change [name="' + name + '"]'] = 'update'; return Tableling.Modular.createModule(_.extend(definition, options)); } // This is how a `PageSizeView` module might be implemented: // // var html = ''; // // var PageSizeView = // Tableling.Modular.createFieldModule('pageSize', { // // template : _.template(html) // }); // // When the value of the input field changes, the event aggregator will // receive a `tableling:update` event with the `pageSize` property set // to that value. }); })(this); // Implementations // --------------- // // tableling-bootstrap provides views styled // with [Twitter Bootstrap](http://twitter.github.com/bootstrap/) classes. ; ;FI"dependency_digest;F"%d9a22b21cd03696777d7672559677d8eI"required_paths;F[I"W/Users/unknow/Projects/tableling-rails/vendor/assets/javascripts/tableling-core.js;FI"dependency_paths;F[{I" path;FI"W/Users/unknow/Projects/tableling-rails/vendor/assets/javascripts/tableling-core.js;FI" mtime;FI"2012-10-11T19:11:18+02:00;FI" digest;F"%73f7f2fcfcbead0ca05ffaa9cb409215I" _version;F"%9f3b95dd7ea3030dc35985c0a8020862