diff --git a/ckanext/reclinepreview/theme/public/preview_recline.js b/ckanext/reclinepreview/theme/public/preview_recline.js index c8bf386c5ea..7b700d03e1b 100644 --- a/ckanext/reclinepreview/theme/public/preview_recline.js +++ b/ckanext/reclinepreview/theme/public/preview_recline.js @@ -15,7 +15,7 @@ this.ckan.module('reclinepreview', function (jQuery, _) { jQuery.proxyAll(this, /_on/); this.el.ready(this._onReady); // hack to make leaflet use a particular location to look for images - L.Icon.Default.imagePath = this.options.site_url + 'vendor/leaflet/0.4.4/images' + L.Icon.Default.imagePath = this.options.site_url + 'vendor/leaflet/0.4.4/images'; }, _onReady: function() { @@ -125,9 +125,9 @@ this.ckan.module('reclinepreview', function (jQuery, _) { var sidebarViews = [ { - id: 'filterEditor', + id: 'valueFilter', label: 'Filters', - view: new recline.View.FilterEditor({ + view: new recline.View.ValueFilter({ model: dataset }) } diff --git a/ckanext/reclinepreview/theme/public/vendor/recline/recline.css b/ckanext/reclinepreview/theme/public/vendor/recline/recline.css index e6437a11baf..c030e764692 100644 --- a/ckanext/reclinepreview/theme/public/vendor/recline/recline.css +++ b/ckanext/reclinepreview/theme/public/vendor/recline/recline.css @@ -395,6 +395,18 @@ div.data-table-cell-content-numeric > a.data-table-cell-edit { width: 175px; } +.recline-filter-editor input { + margin-top: 0.5em; +} + +.recline-filter-editor .add-filter { + margin-top: 1em; + margin-bottom: 2em; +} + +.recline-filter-editor .update-filter { + margin-top: 1em; +} /********************************************************** * Fields Widget diff --git a/ckanext/reclinepreview/theme/public/vendor/recline/recline.dataset.js b/ckanext/reclinepreview/theme/public/vendor/recline/recline.dataset.js index 92183702532..cdd33a0eb92 100644 --- a/ckanext/reclinepreview/theme/public/vendor/recline/recline.dataset.js +++ b/ckanext/reclinepreview/theme/public/vendor/recline/recline.dataset.js @@ -55,8 +55,8 @@ my.Dataset = Backbone.Model.extend({ if (this.backend !== recline.Backend.Memory) { this.backend.fetch(this.toJSON()) .done(handleResults) - .fail(function(arguments) { - dfd.reject(arguments); + .fail(function(args) { + dfd.reject(args); }); } else { // special case where we have been given data directly @@ -79,8 +79,8 @@ my.Dataset = Backbone.Model.extend({ .done(function() { dfd.resolve(self); }) - .fail(function(arguments) { - dfd.reject(arguments); + .fail(function(args) { + dfd.reject(args); }); } @@ -198,9 +198,9 @@ my.Dataset = Backbone.Model.extend({ self.trigger('query:done'); dfd.resolve(self.records); }) - .fail(function(arguments) { - self.trigger('query:fail', arguments); - dfd.reject(arguments); + .fail(function(args) { + self.trigger('query:fail', args); + dfd.reject(args); }); return dfd.promise(); }, @@ -309,9 +309,11 @@ my.Record = Backbone.Model.extend({ // // For the provided Field get the corresponding rendered computed data value // for this record. + // + // NB: if field is undefined a default '' value will be returned getFieldValue: function(field) { val = this.getFieldValueUnrendered(field); - if (field.renderer) { + if (field && !_.isUndefined(field.renderer)) { val = field.renderer(val, field, this.toJSON()); } return val; @@ -321,7 +323,12 @@ my.Record = Backbone.Model.extend({ // // For the provided Field get the corresponding computed data value // for this record. + // + // NB: if field is undefined a default '' value will be returned getFieldValueUnrendered: function(field) { + if (!field) { + return ''; + } var val = this.get(field.id); if (field.deriver) { val = field.deriver(val, field, this); @@ -443,7 +450,7 @@ my.Field = Backbone.Model.extend({ if (val && typeof val === 'string') { val = val.replace(/(https?:\/\/[^ ]+)/g, '$1'); } - return val + return val; } } } diff --git a/ckanext/reclinepreview/theme/public/vendor/recline/recline.dataset.min.js b/ckanext/reclinepreview/theme/public/vendor/recline/recline.dataset.min.js index 441e3937d81..c09914ac855 100644 --- a/ckanext/reclinepreview/theme/public/vendor/recline/recline.dataset.min.js +++ b/ckanext/reclinepreview/theme/public/vendor/recline/recline.dataset.min.js @@ -1,7 +1,7 @@ this.recline=this.recline||{};this.recline.Model=this.recline.Model||{};(function(my){var Deferred=_.isUndefined(this.jQuery)?_.Deferred:jQuery.Deferred;my.Dataset=Backbone.Model.extend({constructor:function Dataset(){Backbone.Model.prototype.constructor.apply(this,arguments);},initialize:function(){_.bindAll(this,'query');this.backend=null;if(this.get('backend')){this.backend=this._backendFromString(this.get('backend'));}else{if(this.get('records')){this.backend=recline.Backend.Memory;}} -this.fields=new my.FieldList();this.records=new my.RecordList();this._changes={deletes:[],updates:[],creates:[]};this.facets=new my.FacetList();this.recordCount=null;this.queryState=new my.Query();this.queryState.bind('change',this.query);this.queryState.bind('facet:add',this.query);this._store=this.backend;if(this.backend==recline.Backend.Memory){this.fetch();}},fetch:function(){var self=this;var dfd=new Deferred();if(this.backend!==recline.Backend.Memory){this.backend.fetch(this.toJSON()).done(handleResults).fail(function(arguments){dfd.reject(arguments);});}else{handleResults({records:this.get('records'),fields:this.get('fields'),useMemoryStore:true});} +this.fields=new my.FieldList();this.records=new my.RecordList();this._changes={deletes:[],updates:[],creates:[]};this.facets=new my.FacetList();this.recordCount=null;this.queryState=new my.Query();this.queryState.bind('change',this.query);this.queryState.bind('facet:add',this.query);this._store=this.backend;if(this.backend==recline.Backend.Memory){this.fetch();}},fetch:function(){var self=this;var dfd=new Deferred();if(this.backend!==recline.Backend.Memory){this.backend.fetch(this.toJSON()).done(handleResults).fail(function(args){dfd.reject(args);});}else{handleResults({records:this.get('records'),fields:this.get('fields'),useMemoryStore:true});} function handleResults(results){var out=self._normalizeRecordsAndFields(results.records,results.fields);if(results.useMemoryStore){self._store=new recline.Backend.Memory.Store(out.records,out.fields);} -self.set(results.metadata);self.fields.reset(out.fields);self.query().done(function(){dfd.resolve(self);}).fail(function(arguments){dfd.reject(arguments);});} +self.set(results.metadata);self.fields.reset(out.fields);self.query().done(function(){dfd.resolve(self);}).fail(function(args){dfd.reject(args);});} return dfd.promise();},_normalizeRecordsAndFields:function(records,fields){if(!fields&&records&&records.length>0){if(records[0]instanceof Array){fields=records[0];records=records.slice(1);}else{fields=_.map(_.keys(records[0]),function(key){return{id:key};});}} if(fields&&fields.length>0&&(fields[0]===null||typeof(fields[0])!='object')){var seen={};fields=_.map(fields,function(field,index){if(field===null){field='';}else{field=field.toString();} var fieldId=field.replace(/^\s+|\s+$/g,'');if(fieldId===''){fieldId='_noname_';field=fieldId;} @@ -11,10 +11,11 @@ return{id:fieldId};});} if(records&&records.length>0&&records[0]instanceof Array){records=_.map(records,function(doc){var tmp={};_.each(fields,function(field,idx){tmp[field.id]=doc[idx];});return tmp;});} return{fields:fields,records:records};},save:function(){var self=this;return this._store.save(this._changes,this.toJSON());},transform:function(editFunc){var self=this;if(!this._store.transform){alert('Transform is not supported with this backend: '+this.get('backend'));return;} this.trigger('recline:flash',{message:"Updating all visible docs. This could take a while...",persist:true,loader:true});this._store.transform(editFunc).done(function(){self.query();self.trigger('recline:flash',{message:"Records updated successfully"});});},query:function(queryObj){var self=this;var dfd=new Deferred();this.trigger('query:start');if(queryObj){this.queryState.set(queryObj,{silent:true});} -var actualQuery=this.queryState.toJSON();this._store.query(actualQuery,this.toJSON()).done(function(queryResult){self._handleQueryResult(queryResult);self.trigger('query:done');dfd.resolve(self.records);}).fail(function(arguments){self.trigger('query:fail',arguments);dfd.reject(arguments);});return dfd.promise();},_handleQueryResult:function(queryResult){var self=this;self.recordCount=queryResult.total;var docs=_.map(queryResult.hits,function(hit){var _doc=new my.Record(hit);_doc.fields=self.fields;_doc.bind('change',function(doc){self._changes.updates.push(doc.toJSON());});_doc.bind('destroy',function(doc){self._changes.deletes.push(doc.toJSON());});return _doc;});self.records.reset(docs);if(queryResult.facets){var facets=_.map(queryResult.facets,function(facetResult,facetId){facetResult.id=facetId;return new my.Facet(facetResult);});self.facets.reset(facets);}},toTemplateJSON:function(){var data=this.toJSON();data.recordCount=this.recordCount;data.fields=this.fields.toJSON();return data;},getFieldsSummary:function(){var self=this;var query=new my.Query();query.set({size:0});this.fields.each(function(field){query.addFacet(field.id);});var dfd=new Deferred();this._store.query(query.toJSON(),this.toJSON()).done(function(queryResult){if(queryResult.facets){_.each(queryResult.facets,function(facetResult,facetId){facetResult.id=facetId;var facet=new my.Facet(facetResult);self.fields.get(facetId).facets.reset(facet);});} +var actualQuery=this.queryState.toJSON();this._store.query(actualQuery,this.toJSON()).done(function(queryResult){self._handleQueryResult(queryResult);self.trigger('query:done');dfd.resolve(self.records);}).fail(function(args){self.trigger('query:fail',args);dfd.reject(args);});return dfd.promise();},_handleQueryResult:function(queryResult){var self=this;self.recordCount=queryResult.total;var docs=_.map(queryResult.hits,function(hit){var _doc=new my.Record(hit);_doc.fields=self.fields;_doc.bind('change',function(doc){self._changes.updates.push(doc.toJSON());});_doc.bind('destroy',function(doc){self._changes.deletes.push(doc.toJSON());});return _doc;});self.records.reset(docs);if(queryResult.facets){var facets=_.map(queryResult.facets,function(facetResult,facetId){facetResult.id=facetId;return new my.Facet(facetResult);});self.facets.reset(facets);}},toTemplateJSON:function(){var data=this.toJSON();data.recordCount=this.recordCount;data.fields=this.fields.toJSON();return data;},getFieldsSummary:function(){var self=this;var query=new my.Query();query.set({size:0});this.fields.each(function(field){query.addFacet(field.id);});var dfd=new Deferred();this._store.query(query.toJSON(),this.toJSON()).done(function(queryResult){if(queryResult.facets){_.each(queryResult.facets,function(facetResult,facetId){facetResult.id=facetId;var facet=new my.Facet(facetResult);self.fields.get(facetId).facets.reset(facet);});} dfd.resolve(queryResult);});return dfd.promise();},recordSummary:function(record){return record.summary();},_backendFromString:function(backendString){var backend=null;if(recline&&recline.Backend){_.each(_.keys(recline.Backend),function(name){if(name.toLowerCase()===backendString.toLowerCase()){backend=recline.Backend[name];}});} -return backend;}});my.Record=Backbone.Model.extend({constructor:function Record(){Backbone.Model.prototype.constructor.apply(this,arguments);},initialize:function(){_.bindAll(this,'getFieldValue');},getFieldValue:function(field){val=this.getFieldValueUnrendered(field);if(field.renderer){val=field.renderer(val,field,this.toJSON());} -return val;},getFieldValueUnrendered:function(field){var val=this.get(field.id);if(field.deriver){val=field.deriver(val,field,this);} +return backend;}});my.Record=Backbone.Model.extend({constructor:function Record(){Backbone.Model.prototype.constructor.apply(this,arguments);},initialize:function(){_.bindAll(this,'getFieldValue');},getFieldValue:function(field){val=this.getFieldValueUnrendered(field);if(field&&!_.isUndefined(field.renderer)){val=field.renderer(val,field,this.toJSON());} +return val;},getFieldValueUnrendered:function(field){if(!field){return'';} +var val=this.get(field.id);if(field.deriver){val=field.deriver(val,field,this);} return val;},summary:function(record){var self=this;var html='
';this.fields.each(function(field){if(field.id!='id'){html+='
'+field.get('label')+': '+self.getFieldValue(field)+'
';}});html+='
';return html;},fetch:function(){},save:function(){},destroy:function(){this.trigger('destroy',this);}});my.RecordList=Backbone.Collection.extend({constructor:function RecordList(){Backbone.Collection.prototype.constructor.apply(this,arguments);},model:my.Record});my.Field=Backbone.Model.extend({constructor:function Field(){Backbone.Model.prototype.constructor.apply(this,arguments);},defaults:{label:null,type:'string',format:null,is_derived:false},initialize:function(data,options){if('0'in data){throw new Error('Looks like you did not pass a proper hash with id to Field constructor');} if(this.attributes.label===null){this.set({label:this.id});} if(this.attributes.type.toLowerCase()in this._typeMap){this.attributes.type=this._typeMap[this.attributes.type.toLowerCase()];} @@ -22,7 +23,7 @@ if(options){this.renderer=options.renderer;this.deriver=options.deriver;} if(!this.renderer){this.renderer=this.defaultRenderers[this.get('type')];} this.facets=new my.FacetList();},_typeMap:{'text':'string','double':'number','float':'number','numeric':'number','int':'integer','datetime':'date-time','bool':'boolean','timestamp':'date-time','json':'object'},defaultRenderers:{object:function(val,field,doc){return JSON.stringify(val);},geo_point:function(val,field,doc){return JSON.stringify(val);},'number':function(val,field,doc){var format=field.get('format');if(format==='percentage'){return val+'%';} return val;},'string':function(val,field,doc){var format=field.get('format');if(format==='markdown'){if(typeof Showdown!=='undefined'){var showdown=new Showdown.converter();out=showdown.makeHtml(val);return out;}else{return val;}}else if(format=='plain'){return val;}else{if(val&&typeof val==='string'){val=val.replace(/(https?:\/\/[^ ]+)/g,'$1');} -return val}}}});my.FieldList=Backbone.Collection.extend({constructor:function FieldList(){Backbone.Collection.prototype.constructor.apply(this,arguments);},model:my.Field});my.Query=Backbone.Model.extend({constructor:function Query(){Backbone.Model.prototype.constructor.apply(this,arguments);},defaults:function(){return{size:100,from:0,q:'',facets:{},filters:[]};},_filterTemplates:{term:{type:'term',field:'',term:''},range:{type:'range',start:'',stop:''},geo_distance:{type:'geo_distance',distance:10,unit:'km',point:{lon:0,lat:0}}},addFilter:function(filter){var ourfilter=JSON.parse(JSON.stringify(filter));if(_.keys(filter).length<=3){ourfilter=_.defaults(ourfilter,this._filterTemplates[filter.type]);} +return val;}}}});my.FieldList=Backbone.Collection.extend({constructor:function FieldList(){Backbone.Collection.prototype.constructor.apply(this,arguments);},model:my.Field});my.Query=Backbone.Model.extend({constructor:function Query(){Backbone.Model.prototype.constructor.apply(this,arguments);},defaults:function(){return{size:100,from:0,q:'',facets:{},filters:[]};},_filterTemplates:{term:{type:'term',field:'',term:''},range:{type:'range',start:'',stop:''},geo_distance:{type:'geo_distance',distance:10,unit:'km',point:{lon:0,lat:0}}},addFilter:function(filter){var ourfilter=JSON.parse(JSON.stringify(filter));if(_.keys(filter).length<=3){ourfilter=_.defaults(ourfilter,this._filterTemplates[filter.type]);} var filters=this.get('filters');filters.push(ourfilter);this.trigger('change:filters:new-blank');},updateFilter:function(index,value){},removeFilter:function(filterIndex){var filters=this.get('filters');filters.splice(filterIndex,1);this.set({filters:filters});this.trigger('change');},addFacet:function(fieldId){var facets=this.get('facets');if(_.contains(_.keys(facets),fieldId)){return;} facets[fieldId]={terms:{field:fieldId}};this.set({facets:facets},{silent:true});this.trigger('facet:add',this);},addHistogramFacet:function(fieldId){var facets=this.get('facets');facets[fieldId]={date_histogram:{field:fieldId,interval:'day'}};this.set({facets:facets},{silent:true});this.trigger('facet:add',this);}});my.Facet=Backbone.Model.extend({constructor:function Facet(){Backbone.Model.prototype.constructor.apply(this,arguments);},defaults:function(){return{_type:'terms',total:0,other:0,missing:0,terms:[]};}});my.FacetList=Backbone.Collection.extend({constructor:function FacetList(){Backbone.Collection.prototype.constructor.apply(this,arguments);},model:my.Facet});my.ObjectState=Backbone.Model.extend({});Backbone.sync=function(method,model,options){return model.backend.sync(method,model,options);};}(this.recline.Model));this.recline=this.recline||{};this.recline.Backend=this.recline.Backend||{};this.recline.Backend.Memory=this.recline.Backend.Memory||{};(function(my){my.__type__='memory';var Deferred=_.isUndefined(this.jQuery)?_.Deferred:jQuery.Deferred;my.Store=function(records,fields){var self=this;this.records=records;this.data=this.records;if(fields){this.fields=fields;}else{if(records){this.fields=_.map(records[0],function(value,key){return{id:key,type:'string'};});}} this.update=function(doc){_.each(self.records,function(internalDoc,idx){if(doc.id===internalDoc.id){self.records[idx]=doc;}});};this.remove=function(doc){var newdocs=_.reject(self.records,function(internalDoc){return(doc.id===internalDoc.id);});this.records=newdocs;};this.save=function(changes,dataset){var self=this;var dfd=new Deferred();_.each(changes.updates,function(record){self.update(record);});_.each(changes.deletes,function(record){self.remove(record);});dfd.resolve();return dfd.promise();},this.query=function(queryObj){var dfd=new Deferred();var numRows=queryObj.size||this.records.length;var start=queryObj.from||0;var results=this.records;results=this._applyFilters(results,queryObj);results=this._applyFreeTextQuery(results,queryObj);_.each(queryObj.sort,function(sortObj){var fieldName=sortObj.field;results=_.sortBy(results,function(doc){var _out=doc[fieldName];return _out;});if(sortObj.order=='desc'){results.reverse();}});var facets=this.computeFacets(results,queryObj);var out={total:results.length,hits:results.slice(start,start+numRows),facets:facets};dfd.resolve(out);return dfd.promise();};this._applyFilters=function(results,queryObj){var filters=queryObj.filters;var filterFunctions={term:term,range:range,geo_distance:geo_distance};var dataParsers={integer:function(e){return parseFloat(e,10);},'float':function(e){return parseFloat(e,10);},number:function(e){return parseFloat(e,10);},string:function(e){return e.toString()},date:function(e){return new Date(e).valueOf()},datetime:function(e){return new Date(e).valueOf()}};var keyedFields={};_.each(self.fields,function(field){keyedFields[field.id]=field;});function getDataParser(filter){var fieldType=keyedFields[filter.field].type||'string';return dataParsers[fieldType];} diff --git a/ckanext/reclinepreview/theme/public/vendor/recline/recline.js b/ckanext/reclinepreview/theme/public/vendor/recline/recline.js index adb0ab154fe..89258b2353e 100644 --- a/ckanext/reclinepreview/theme/public/vendor/recline/recline.js +++ b/ckanext/reclinepreview/theme/public/vendor/recline/recline.js @@ -37,12 +37,13 @@ this.recline.Backend.Ckan = this.recline.Backend.Ckan || {}; // ### fetch my.fetch = function(dataset) { + var wrapper; if (dataset.endpoint) { - var wrapper = my.DataStore(dataset.endpoint); + wrapper = my.DataStore(dataset.endpoint); } else { var out = my._parseCkanResourceUrl(dataset.url); dataset.id = out.resource_id; - var wrapper = my.DataStore(out.endpoint); + wrapper = my.DataStore(out.endpoint); } var dfd = new Deferred(); var jqxhr = wrapper.search({resource_id: dataset.id, limit: 0}); @@ -66,25 +67,36 @@ this.recline.Backend.Ckan = this.recline.Backend.Ckan || {}; var actualQuery = { resource_id: dataset.id, q: queryObj.q, + filters: {}, limit: queryObj.size || 10, offset: queryObj.from || 0 }; + if (queryObj.sort && queryObj.sort.length > 0) { var _tmp = _.map(queryObj.sort, function(sortObj) { return sortObj.field + ' ' + (sortObj.order || ''); }); actualQuery.sort = _tmp.join(','); } + + if (queryObj.filters && queryObj.filters.length > 0) { + _.each(queryObj.filters, function(filter) { + if (filter.type === "term") { + actualQuery.filters[filter.field] = filter.term; + } + }); + } return actualQuery; }; my.query = function(queryObj, dataset) { + var wrapper; if (dataset.endpoint) { - var wrapper = my.DataStore(dataset.endpoint); + wrapper = my.DataStore(dataset.endpoint); } else { var out = my._parseCkanResourceUrl(dataset.url); dataset.id = out.resource_id; - var wrapper = my.DataStore(out.endpoint); + wrapper = my.DataStore(out.endpoint); } var actualQuery = my._normalizeQuery(queryObj, dataset); var dfd = new Deferred(); @@ -105,15 +117,14 @@ this.recline.Backend.Ckan = this.recline.Backend.Ckan || {}; // // @param endpoint: CKAN api endpoint (e.g. http://datahub.io/api) my.DataStore = function(endpoint) { - var that = { - endpoint: endpoint || my.API_ENDPOINT - }; + var that = {endpoint: endpoint || my.API_ENDPOINT}; + that.search = function(data) { var searchUrl = that.endpoint + '/3/action/datastore_search'; var jqxhr = jQuery.ajax({ url: searchUrl, - data: data, - dataType: 'json' + type: 'POST', + data: JSON.stringify(data) }); return jqxhr; }; @@ -476,8 +487,8 @@ this.recline.Backend.DataProxy = this.recline.Backend.DataProxy || {}; useMemoryStore: true }); }) - .fail(function(arguments) { - dfd.reject(arguments); + .fail(function(args) { + dfd.reject(args); }); return dfd.promise(); }; @@ -494,17 +505,17 @@ this.recline.Backend.DataProxy = this.recline.Backend.DataProxy || {}; message: 'Request Error: Backend did not respond after ' + (my.timeout / 1000) + ' seconds' }); }, my.timeout); - ourFunction.done(function(arguments) { + ourFunction.done(function(args) { clearTimeout(timer); - dfd.resolve(arguments); + dfd.resolve(args); }) - .fail(function(arguments) { + .fail(function(args) { clearTimeout(timer); - dfd.reject(arguments); + dfd.reject(args); }) ; return dfd.promise(); - } + }; }(this.recline.Backend.DataProxy)); this.recline = this.recline || {}; @@ -1396,8 +1407,8 @@ my.Dataset = Backbone.Model.extend({ if (this.backend !== recline.Backend.Memory) { this.backend.fetch(this.toJSON()) .done(handleResults) - .fail(function(arguments) { - dfd.reject(arguments); + .fail(function(args) { + dfd.reject(args); }); } else { // special case where we have been given data directly @@ -1420,8 +1431,8 @@ my.Dataset = Backbone.Model.extend({ .done(function() { dfd.resolve(self); }) - .fail(function(arguments) { - dfd.reject(arguments); + .fail(function(args) { + dfd.reject(args); }); } @@ -1539,9 +1550,9 @@ my.Dataset = Backbone.Model.extend({ self.trigger('query:done'); dfd.resolve(self.records); }) - .fail(function(arguments) { - self.trigger('query:fail', arguments); - dfd.reject(arguments); + .fail(function(args) { + self.trigger('query:fail', args); + dfd.reject(args); }); return dfd.promise(); }, @@ -1650,9 +1661,11 @@ my.Record = Backbone.Model.extend({ // // For the provided Field get the corresponding rendered computed data value // for this record. + // + // NB: if field is undefined a default '' value will be returned getFieldValue: function(field) { val = this.getFieldValueUnrendered(field); - if (field.renderer) { + if (field && !_.isUndefined(field.renderer)) { val = field.renderer(val, field, this.toJSON()); } return val; @@ -1662,7 +1675,12 @@ my.Record = Backbone.Model.extend({ // // For the provided Field get the corresponding computed data value // for this record. + // + // NB: if field is undefined a default '' value will be returned getFieldValueUnrendered: function(field) { + if (!field) { + return ''; + } var val = this.get(field.id); if (field.deriver) { val = field.deriver(val, field, this); @@ -1784,7 +1802,7 @@ my.Field = Backbone.Model.extend({ if (val && typeof val === 'string') { val = val.replace(/(https?:\/\/[^ ]+)/g, '$1'); } - return val + return val; } } } @@ -2092,14 +2110,19 @@ my.Flot = Backbone.View.extend({ var xtype = xfield.get('type'); var isDateTime = (xtype === 'date' || xtype === 'date-time' || xtype === 'time'); - if (this.model.records.models[parseInt(x, 10)]) { - x = this.model.records.models[parseInt(x, 10)].get(this.state.attributes.group); - if (isDateTime) { - x = new Date(x).toLocaleDateString(); - } - } else if (isDateTime) { - x = new Date(parseInt(x, 10)).toLocaleDateString(); + if (this.xvaluesAreIndex) { + x = parseInt(x, 10); + // HACK: deal with bar graph style cases where x-axis items were strings + // In this case x at this point is the index of the item in the list of + // records not its actual x-axis value + x = this.model.records.models[x].get(this.state.attributes.group); + } + if (isDateTime) { + x = new Date(x).toLocaleDateString(); } + // } else if (isDateTime) { + // x = new Date(parseInt(x, 10)).toLocaleDateString(); + // } return x; }, @@ -2119,13 +2142,13 @@ my.Flot = Backbone.View.extend({ // convert x to a string and make sure that it is not too long or the // tick labels will overlap // TODO: find a more accurate way of calculating the size of tick labels - var label = self._xaxisLabel(x); + var label = self._xaxisLabel(x) || ""; if (typeof label !== 'string') { label = label.toString(); } - if (self.state.attributes.graphType !== 'bars' && label.length > 8) { - label = label.slice(0, 5) + "..."; + if (self.state.attributes.graphType !== 'bars' && label.length > 10) { + label = label.slice(0, 10) + "..."; } return label; @@ -2134,31 +2157,16 @@ my.Flot = Backbone.View.extend({ var xaxis = {}; xaxis.tickFormatter = tickFormatter; - // calculate the x-axis ticks - // - // the number of ticks should be a multiple of the number of points so that - // each tick lines up with a point - if (numPoints) { - var ticks = [], - maxTicks = 10, - x = 1, - i = 0; - - // show all ticks in bar graphs - // for other graphs only show up to maxTicks ticks - if (self.state.attributes.graphType !== 'bars') { - while (x <= maxTicks) { - if ((numPoints / x) <= maxTicks) { - break; - } - x = x + 1; - } + // for labels case we only want ticks at the label intervals + // HACK: however we also get this case with Date fields. In that case we + // could have a lot of values and so we limit to max 15 (we assume) + if (this.xvaluesAreIndex) { + var numTicks = Math.min(this.model.records.length, 15); + var increment = this.model.records.length / numTicks; + var ticks = []; + for (i=0; i= 0; i--){ - if (_.indexOf(_.pluck(visibleColumns,'id'),columns[i].id) == -1){ + if (_.indexOf(_.pluck(visibleColumns,'id'),columns[i].id) === -1){ tempHiddenColumns.push(columns.splice(i,1)[0]); } } @@ -4551,18 +4558,18 @@ my.SlickGrid = Backbone.View.extend({ this.push = function(model, row) { models.push(model); rows.push(row); - } + }; - this.getLength = function() { return rows.length; } - this.getItem = function(index) { return rows[index];} - this.getItemMetadata= function(index) { return {};} - this.getModel= function(index) { return models[index]; } - this.getModelRow = function(m) { return models.indexOf(m);} - this.updateItem = function(m,i) { + this.getLength = function() {return rows.length; }; + this.getItem = function(index) {return rows[index];}; + this.getItemMetadata = function(index) {return {};}; + this.getModel = function(index) {return models[index];}; + this.getModelRow = function(m) {return models.indexOf(m);}; + this.updateItem = function(m,i) { rows[i] = toRow(m); - models[i] = m + models[i] = m; }; - }; + } var data = new RowSet(); @@ -4576,7 +4583,7 @@ my.SlickGrid = Backbone.View.extend({ var sortInfo = this.model.queryState.get('sort'); if (sortInfo){ var column = sortInfo[0].field; - var sortAsc = !(sortInfo[0].order == 'desc'); + var sortAsc = sortInfo[0].order !== 'desc'; this.grid.setSortColumn(column, sortAsc); } @@ -4610,7 +4617,7 @@ my.SlickGrid = Backbone.View.extend({ // var grid = args.grid; var model = data.getModel(args.row); - var field = grid.getColumns()[args.cell]['id']; + var field = grid.getColumns()[args.cell].id; var v = {}; v[field] = args.item[field]; model.set(v); @@ -4671,7 +4678,7 @@ my.SlickGrid = Backbone.View.extend({ $menu = $('