Merge branch 'master' into gh-pages
This commit is contained in:
@@ -29,11 +29,11 @@
|
|||||||
<link rel="stylesheet" href="../vendor/bootstrap/2.0.2/css/bootstrap-responsive.css">
|
<link rel="stylesheet" href="../vendor/bootstrap/2.0.2/css/bootstrap-responsive.css">
|
||||||
|
|
||||||
<!-- 3rd party JS libraries -->
|
<!-- 3rd party JS libraries -->
|
||||||
<script type="text/javascript" src="../vendor/jquery-1.7.1.js"></script>
|
<script type="text/javascript" src="../vendor/jquery/1.7.1/jquery.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/underscore-1.1.6.js"></script>
|
<script type="text/javascript" src="../vendor/underscore/1.1.6/underscore.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/backbone-0.5.1.js"></script>
|
<script type="text/javascript" src="../vendor/backbone/0.5.1/backbone.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/jquery-ui-1.8.14.custom.min.js"></script>
|
<script type="text/javascript" src="../vendor/jquery-ui-1.8.14.custom.min.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/jquery.flot-0.7.js"></script>
|
<script type="text/javascript" src="../vendor/jquery.flot/0.7/jquery.flot.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/jquery.mustache.js"></script>
|
<script type="text/javascript" src="../vendor/jquery.mustache.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/bootstrap/2.0.2/bootstrap.js"></script>
|
<script type="text/javascript" src="../vendor/bootstrap/2.0.2/bootstrap.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/leaflet/0.3.1/leaflet.js"></script>
|
<script type="text/javascript" src="../vendor/leaflet/0.3.1/leaflet.js"></script>
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
// backends (see recline.Model.Dataset.initialize).
|
// backends (see recline.Model.Dataset.initialize).
|
||||||
__type__: 'base',
|
__type__: 'base',
|
||||||
|
|
||||||
|
|
||||||
|
// ### readonly
|
||||||
|
//
|
||||||
|
// Class level attribute indicating that this backend is read-only (that
|
||||||
|
// is, cannot be written to).
|
||||||
|
readonly: true,
|
||||||
|
|
||||||
// ### sync
|
// ### sync
|
||||||
//
|
//
|
||||||
// An implementation of Backbone.sync that will be used to override
|
// An implementation of Backbone.sync that will be used to override
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
// Note that this is a **read-only** backend.
|
// Note that this is a **read-only** backend.
|
||||||
my.DataProxy = my.Base.extend({
|
my.DataProxy = my.Base.extend({
|
||||||
__type__: 'dataproxy',
|
__type__: 'dataproxy',
|
||||||
|
readonly: true,
|
||||||
defaults: {
|
defaults: {
|
||||||
dataproxy_url: 'http://jsonpdataproxy.appspot.com'
|
dataproxy_url: 'http://jsonpdataproxy.appspot.com'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
// <pre>http://localhost:9200/twitter/tweet</pre>
|
// <pre>http://localhost:9200/twitter/tweet</pre>
|
||||||
my.ElasticSearch = my.Base.extend({
|
my.ElasticSearch = my.Base.extend({
|
||||||
__type__: 'elasticsearch',
|
__type__: 'elasticsearch',
|
||||||
|
readonly: true,
|
||||||
_getESUrl: function(dataset) {
|
_getESUrl: function(dataset) {
|
||||||
var out = dataset.get('elasticsearch_url');
|
var out = dataset.get('elasticsearch_url');
|
||||||
if (out) return out;
|
if (out) return out;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
// </pre>
|
// </pre>
|
||||||
my.GDoc = my.Base.extend({
|
my.GDoc = my.Base.extend({
|
||||||
__type__: 'gdoc',
|
__type__: 'gdoc',
|
||||||
|
readonly: true,
|
||||||
getUrl: function(dataset) {
|
getUrl: function(dataset) {
|
||||||
var url = dataset.get('url');
|
var url = dataset.get('url');
|
||||||
if (url.indexOf('feeds/list') != -1) {
|
if (url.indexOf('feeds/list') != -1) {
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
// </pre>
|
// </pre>
|
||||||
my.Memory = my.Base.extend({
|
my.Memory = my.Base.extend({
|
||||||
__type__: 'memory',
|
__type__: 'memory',
|
||||||
|
readonly: false,
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
this.datasets = {};
|
this.datasets = {};
|
||||||
},
|
},
|
||||||
@@ -158,7 +159,8 @@ this.recline.Backend = this.recline.Backend || {};
|
|||||||
_.each(terms, function(term) {
|
_.each(terms, function(term) {
|
||||||
var foundmatch = false;
|
var foundmatch = false;
|
||||||
dataset.fields.each(function(field) {
|
dataset.fields.each(function(field) {
|
||||||
var value = rawdoc[field.id].toString();
|
var value = rawdoc[field.id];
|
||||||
|
if (value !== null) { value = value.toString(); }
|
||||||
// TODO regexes?
|
// TODO regexes?
|
||||||
foundmatch = foundmatch || (value === term);
|
foundmatch = foundmatch || (value === term);
|
||||||
// TODO: early out (once we are true should break to spare unnecessary testing)
|
// TODO: early out (once we are true should break to spare unnecessary testing)
|
||||||
|
|||||||
19
src/model.js
19
src/model.js
@@ -217,7 +217,8 @@ my.DocumentList = Backbone.Collection.extend({
|
|||||||
// * format: (optional) used to indicate how the data should be formatted. For example:
|
// * format: (optional) used to indicate how the data should be formatted. For example:
|
||||||
// * type=date, format=yyyy-mm-dd
|
// * type=date, format=yyyy-mm-dd
|
||||||
// * type=float, format=percentage
|
// * type=float, format=percentage
|
||||||
// * type=float, format='###,###.##'
|
// * type=string, format=link (render as hyperlink)
|
||||||
|
// * type=string, format=markdown (render as markdown if Showdown available)
|
||||||
// * is_derived: (default: false) attribute indicating this field has no backend data but is just derived from other fields (see below).
|
// * is_derived: (default: false) attribute indicating this field has no backend data but is just derived from other fields (see below).
|
||||||
//
|
//
|
||||||
// Following additional instance properties:
|
// Following additional instance properties:
|
||||||
@@ -273,6 +274,22 @@ my.Field = Backbone.Model.extend({
|
|||||||
if (format === 'percentage') {
|
if (format === 'percentage') {
|
||||||
return val + '%';
|
return val + '%';
|
||||||
}
|
}
|
||||||
|
return val;
|
||||||
|
},
|
||||||
|
'string': function(val, field, doc) {
|
||||||
|
var format = field.get('format');
|
||||||
|
if (format === 'link') {
|
||||||
|
return '<a href="VAL">VAL</a>'.replace(/VAL/g, val);
|
||||||
|
} else if (format === 'markdown') {
|
||||||
|
if (typeof Showdown !== 'undefined') {
|
||||||
|
var showdown = new Showdown.converter();
|
||||||
|
out = showdown.makeHtml(val);
|
||||||
|
return out;
|
||||||
|
} else {
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -256,9 +256,12 @@ my.Map = Backbone.View.extend({
|
|||||||
|
|
||||||
if (!(docs instanceof Array)) docs = [docs];
|
if (!(docs instanceof Array)) docs = [docs];
|
||||||
|
|
||||||
|
var count = 0;
|
||||||
|
var wrongSoFar = 0;
|
||||||
_.every(docs,function(doc){
|
_.every(docs,function(doc){
|
||||||
|
count += 1;
|
||||||
var feature = self._getGeometryFromDocument(doc);
|
var feature = self._getGeometryFromDocument(doc);
|
||||||
if (typeof feature === 'undefined'){
|
if (typeof feature === 'undefined' || feature === null){
|
||||||
// Empty field
|
// Empty field
|
||||||
return true;
|
return true;
|
||||||
} else if (feature instanceof Object){
|
} else if (feature instanceof Object){
|
||||||
@@ -275,16 +278,20 @@ my.Map = Backbone.View.extend({
|
|||||||
feature.properties.cid = doc.cid;
|
feature.properties.cid = doc.cid;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
self.features.addGeoJSON(feature);
|
self.features.addGeoJSON(feature);
|
||||||
} catch (except) {
|
} catch (except) {
|
||||||
var msg = 'Wrong geometry value';
|
wrongSoFar += 1;
|
||||||
if (except.message) msg += ' (' + except.message + ')';
|
var msg = 'Wrong geometry value';
|
||||||
|
if (except.message) msg += ' (' + except.message + ')';
|
||||||
|
if (wrongSoFar <= 10) {
|
||||||
my.notify(msg,{category:'error'});
|
my.notify(msg,{category:'error'});
|
||||||
return false;
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
my.notify('Wrong geometry value',{category:'error'});
|
wrongSoFar += 1
|
||||||
return false;
|
if (wrongSoFar <= 10) {
|
||||||
|
my.notify('Wrong geometry value',{category:'error'});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
@@ -317,13 +324,17 @@ my.Map = Backbone.View.extend({
|
|||||||
return doc.attributes[this.state.get('geomField')];
|
return doc.attributes[this.state.get('geomField')];
|
||||||
} else if (this.state.get('lonField') && this.state.get('latField')){
|
} else if (this.state.get('lonField') && this.state.get('latField')){
|
||||||
// We'll create a GeoJSON like point object from the two lat/lon fields
|
// We'll create a GeoJSON like point object from the two lat/lon fields
|
||||||
return {
|
var lon = doc.get(this.state.get('lonField'));
|
||||||
type: 'Point',
|
var lat = doc.get(this.state.get('latField'));
|
||||||
coordinates: [
|
if (lon && lat) {
|
||||||
doc.attributes[this.state.get('lonField')],
|
return {
|
||||||
doc.attributes[this.state.get('latField')]
|
type: 'Point',
|
||||||
]
|
coordinates: [
|
||||||
};
|
doc.attributes[this.state.get('lonField')],
|
||||||
|
doc.attributes[this.state.get('latField')]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -335,12 +346,16 @@ my.Map = Backbone.View.extend({
|
|||||||
// If not found, the user can define them via the UI form.
|
// If not found, the user can define them via the UI form.
|
||||||
_setupGeometryField: function(){
|
_setupGeometryField: function(){
|
||||||
var geomField, latField, lonField;
|
var geomField, latField, lonField;
|
||||||
this.state.set({
|
|
||||||
geomField: this._checkField(this.geometryFieldNames),
|
|
||||||
latField: this._checkField(this.latitudeFieldNames),
|
|
||||||
lonField: this._checkField(this.longitudeFieldNames)
|
|
||||||
});
|
|
||||||
this.geomReady = (this.state.get('geomField') || (this.state.get('latField') && this.state.get('lonField')));
|
this.geomReady = (this.state.get('geomField') || (this.state.get('latField') && this.state.get('lonField')));
|
||||||
|
// should not overwrite if we have already set this (e.g. explicitly via state)
|
||||||
|
if (!this.geomReady) {
|
||||||
|
this.state.set({
|
||||||
|
geomField: this._checkField(this.geometryFieldNames),
|
||||||
|
latField: this._checkField(this.latitudeFieldNames),
|
||||||
|
lonField: this._checkField(this.longitudeFieldNames)
|
||||||
|
});
|
||||||
|
this.geomReady = (this.state.get('geomField') || (this.state.get('latField') && this.state.get('lonField')));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Private: Check if a field in the current model exists in the provided
|
// Private: Check if a field in the current model exists in the provided
|
||||||
|
|||||||
@@ -184,8 +184,8 @@ my.DataExplorer = Backbone.View.extend({
|
|||||||
initialize: function(options) {
|
initialize: function(options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.el = $(this.el);
|
this.el = $(this.el);
|
||||||
// Hash of 'page' views (i.e. those for whole page) keyed by page name
|
|
||||||
this._setupState(options.state);
|
this._setupState(options.state);
|
||||||
|
// Hash of 'page' views (i.e. those for whole page) keyed by page name
|
||||||
if (options.views) {
|
if (options.views) {
|
||||||
this.pageViews = options.views;
|
this.pageViews = options.views;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ function makeBackendDataset() {
|
|||||||
return dataset;
|
return dataset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test('Memory Backend: readonly', function () {
|
||||||
|
var backend = new recline.Backend.Memory();
|
||||||
|
equal(backend.readonly, false);
|
||||||
|
});
|
||||||
|
|
||||||
test('Memory Backend: createDataset', function () {
|
test('Memory Backend: createDataset', function () {
|
||||||
var dataset = recline.Backend.createDataset(memoryData.documents, memoryData.fields, memoryData.metadata);
|
var dataset = recline.Backend.createDataset(memoryData.documents, memoryData.fields, memoryData.metadata);
|
||||||
equal(memoryData.metadata.id, dataset.id);
|
equal(memoryData.metadata.id, dataset.id);
|
||||||
@@ -217,6 +222,8 @@ test('DataProxy Backend', function() {
|
|||||||
// needed only if not stubbing
|
// needed only if not stubbing
|
||||||
// stop();
|
// stop();
|
||||||
var backend = new recline.Backend.DataProxy();
|
var backend = new recline.Backend.DataProxy();
|
||||||
|
ok(backend.readonly, false);
|
||||||
|
|
||||||
var dataset = new recline.Model.Dataset({
|
var dataset = new recline.Model.Dataset({
|
||||||
url: 'http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv'
|
url: 'http://webstore.thedatahub.org/rufuspollock/gold_prices/data.csv'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,13 +7,14 @@
|
|||||||
<!-- need this stylesheet because flot will complain if canvas does not have a height -->
|
<!-- need this stylesheet because flot will complain if canvas does not have a height -->
|
||||||
<link rel="stylesheet" href="../css/graph.css" type="text/css" media="screen" />
|
<link rel="stylesheet" href="../css/graph.css" type="text/css" media="screen" />
|
||||||
|
|
||||||
<script type="text/javascript" src="../vendor/jquery-1.7.1.js"></script>
|
<script type="text/javascript" src="../vendor/jquery/1.7.1/jquery.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/underscore-1.1.6.js"></script>
|
<script type="text/javascript" src="../vendor/underscore/1.1.6/underscore.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/backbone-0.5.1.js"></script>
|
<script type="text/javascript" src="../vendor/backbone/0.5.1/backbone.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/jquery-ui-1.8.14.custom.min.js"></script>
|
<script type="text/javascript" src="../vendor/jquery-ui-1.8.14.custom.min.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/jquery.flot-0.7.js"></script>
|
<script type="text/javascript" src="../vendor/jquery.flot/0.7/jquery.flot.js"></script>
|
||||||
<script type="text/javascript" src="../vendor/leaflet/0.3.1/leaflet.js"></script>
|
|
||||||
<script type="text/javascript" src="../vendor/jquery.mustache.js"></script>
|
<script type="text/javascript" src="../vendor/jquery.mustache.js"></script>
|
||||||
|
<script type="text/javascript" src="../vendor/bootstrap/2.0.2/bootstrap.js"></script>
|
||||||
|
<script type="text/javascript" src="../vendor/leaflet/0.3.1/leaflet.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="qunit/qunit.js"></script>
|
<script type="text/javascript" src="qunit/qunit.js"></script>
|
||||||
<script src="sinon/1.1.1/sinon.js"></script>
|
<script src="sinon/1.1.1/sinon.js"></script>
|
||||||
|
|||||||
@@ -39,7 +39,12 @@ test('Field: basics', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Field: default renderers', function () {
|
test('Field: default renderers', function () {
|
||||||
var doc = new recline.Model.Document({x: 12.3, myobject: {a: 1, b: 2}});
|
var doc = new recline.Model.Document({
|
||||||
|
x: 12.3,
|
||||||
|
myobject: {a: 1, b: 2},
|
||||||
|
link: 'http://abc.com/',
|
||||||
|
markdown: '### ABC'
|
||||||
|
});
|
||||||
var field = new recline.Model.Field({id: 'myobject', type: 'object'});
|
var field = new recline.Model.Field({id: 'myobject', type: 'object'});
|
||||||
var out = doc.getFieldValue(field);
|
var out = doc.getFieldValue(field);
|
||||||
var exp = '{"a":1,"b":2}';
|
var exp = '{"a":1,"b":2}';
|
||||||
@@ -49,6 +54,17 @@ test('Field: default renderers', function () {
|
|||||||
var out = doc.getFieldValue(field);
|
var out = doc.getFieldValue(field);
|
||||||
var exp = '12.3%';
|
var exp = '12.3%';
|
||||||
equal(out, exp);
|
equal(out, exp);
|
||||||
|
|
||||||
|
var field = new recline.Model.Field({id: 'link', type: 'string', format: 'link'});
|
||||||
|
var out = doc.getFieldValue(field);
|
||||||
|
var exp = '<a href="http://abc.com/">http://abc.com/</a>';
|
||||||
|
equal(out, exp);
|
||||||
|
|
||||||
|
var field = new recline.Model.Field({id: 'markdown', type: 'string', format: 'markdown'});
|
||||||
|
var out = doc.getFieldValue(field);
|
||||||
|
// Showdown is not installed so nothing should happen
|
||||||
|
var exp = doc.get('markdown');
|
||||||
|
equal(out, exp);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Field: custom deriver and renderer', function () {
|
test('Field: custom deriver and renderer', function () {
|
||||||
|
|||||||
@@ -47,17 +47,26 @@ test('initialize state', function () {
|
|||||||
currentView: 'graph',
|
currentView: 'graph',
|
||||||
'view-grid': {
|
'view-grid': {
|
||||||
hiddenFields: ['x']
|
hiddenFields: ['x']
|
||||||
|
},
|
||||||
|
'view-map': {
|
||||||
|
latField: 'lat1',
|
||||||
|
lonField: 'lon1'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
ok(explorer.state.get('readOnly'));
|
ok(explorer.state.get('readOnly'));
|
||||||
ok(explorer.state.get('currentView'), 'graph');
|
ok(explorer.state.get('currentView'), 'graph');
|
||||||
|
|
||||||
// check the correct view is visible
|
// check the correct view is visible
|
||||||
var css = explorer.el.find('.navigation a[data-view="graph"]').attr('class').split(' ');
|
var css = explorer.el.find('.navigation a[data-view="graph"]').attr('class').split(' ');
|
||||||
ok(_.contains(css, 'disabled'), css);
|
ok(_.contains(css, 'disabled'), css);
|
||||||
|
|
||||||
var css = explorer.el.find('.navigation a[data-view="grid"]').attr('class').split(' ');
|
var css = explorer.el.find('.navigation a[data-view="grid"]').attr('class').split(' ');
|
||||||
ok(!(_.contains(css, 'disabled')), css);
|
ok(!(_.contains(css, 'disabled')), css);
|
||||||
|
|
||||||
|
// check pass through of view config
|
||||||
|
deepEqual(explorer.state.get('view-grid')['hiddenFields'], ['x']);
|
||||||
|
equal(explorer.state.get('view-map')['lonField'], 'lon1');
|
||||||
|
|
||||||
$el.remove();
|
$el.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user