Merge pull request #100 from amercader/master
Reapply a lost fix, fix built demo and tests and rebuild library
This commit is contained in:
commit
30f4d7359e
149
app/built.html
149
app/built.html
@ -2,7 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Recline Data Explorer Demo</title>
|
||||
<title>Recline Data Explorer (Built Sources)</title>
|
||||
<meta name="description" content="A demo of the Recline Data Explorer">
|
||||
<meta name="author" content="Rufus Pollock and Max Ogden">
|
||||
|
||||
@ -11,46 +11,161 @@
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
<link rel="stylesheet" href="../vendor/bootstrap/2.0.2/css/bootstrap.css">
|
||||
<link rel="stylesheet" href="../vendor/leaflet/0.3.1/leaflet.css">
|
||||
<!--[if lte IE 8]>
|
||||
<link rel="stylesheet" href="../vendor/leaflet/0.3.1/leaflet.ie.css" />
|
||||
<![endif]-->
|
||||
|
||||
<!-- Recline CSS components -->
|
||||
<link rel="stylesheet" href="../css/data-explorer.css">
|
||||
<link rel="stylesheet" href="../css/grid.css">
|
||||
<link rel="stylesheet" href="../css/graph.css">
|
||||
<link rel="stylesheet" href="../css/map.css">
|
||||
<!-- /Recline CSS components -->
|
||||
|
||||
<!-- Custom CSS for the Data Explorer Online App -->
|
||||
<link rel="stylesheet" href="style/demo.css">
|
||||
|
||||
<script type="text/javascript" src="../vendor/jquery-1.7.1.js"></script>
|
||||
<script type="text/javascript" src="../vendor/underscore-1.1.6.js"></script>
|
||||
<script type="text/javascript" src="../vendor/backbone-0.5.1.js"></script>
|
||||
<link rel="stylesheet" href="../vendor/bootstrap/2.0.2/css/bootstrap-responsive.css">
|
||||
|
||||
<!-- 3rd party JS libraries -->
|
||||
<script type="text/javascript" src="../vendor/jquery/1.7.1/jquery.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/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.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/bootstrap/2.0.2/bootstrap.js"></script>
|
||||
<script type="text/javascript" src="../vendor/leaflet/0.3.1/leaflet.js"></script>
|
||||
|
||||
<!-- recline library -->
|
||||
<script type="text/javascript" src="../recline.js"></script>
|
||||
|
||||
<!-- non-library javascript specific to this demo -->
|
||||
<script type="text/javascript" src="js/app.js"></script>
|
||||
</head>
|
||||
</head>
|
||||
<body>
|
||||
<div class="recline-app">
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="brand" href="#">Recline Data Explorer</a>
|
||||
<ul class="nav pull-right">
|
||||
<li><a class="set-read-only" title="Put into read-only mode">Read-only</a></li>
|
||||
<a class="brand" href="../">Recline Data Explorer</a>
|
||||
<ul class="nav">
|
||||
<li><a href="../#docs">Documentation</a></li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<li class="dropdown">
|
||||
<a data-toggle="dropdown" class="dropdown-toggle">
|
||||
Import <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu js-import">
|
||||
<li>
|
||||
<a data-toggle="modal" href=".js-import-dialog-url">Import from URL</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-toggle="modal" href=".js-import-dialog-file">Import from File</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href=".js-share-and-embed-dialog" data-toggle="modal">
|
||||
Share and Embed
|
||||
<i class="icon-share icon-white"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<form class="webstore-load pull-right navbar-search" title="Update from the specified webstore dataset">
|
||||
<input type="text" name="source" size="50" />
|
||||
<select name="backend_type">
|
||||
<option value="elasticsearch">ElasticSearch</option>
|
||||
<option value="dataproxy">DataProxy</option>
|
||||
<option value="gdocs">Google Spreadsheets</option>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade in js-import-dialog-url" style="display: none;">
|
||||
<div class="modal-header">
|
||||
<a class="close" data-dismiss="modal">×</a>
|
||||
<h3>Import from URL</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="js-import-url form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label">URL</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="source" class="input-xlarge" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">Type of data</label>
|
||||
<div class="controls">
|
||||
<select name="backend_type">
|
||||
<option value="elasticsearch">ElasticSearch</option>
|
||||
<option value="dataproxy">CSV or Excel</option>
|
||||
<option value="gdocs">Google Spreadsheet</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Import »</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade in js-import-dialog-file" style="display: none;">
|
||||
<div class="modal-header">
|
||||
<a class="close" data-dismiss="modal">×</a>
|
||||
<h3>Import from File</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label">File</label>
|
||||
<div class="controls">
|
||||
<input type="file" name="source" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">Separator</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="separator" value="," class="spam1"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">Text delimiter</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="delimiter" value='"' />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Encoding</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="encoding" value="UTF-8" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Import »</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade in js-share-and-embed-dialog" style="display: none;">
|
||||
<div class="modal-header">
|
||||
<a class="close" data-dismiss="modal">×</a>
|
||||
<h3>Share and Embed</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h4>Sharable Link to current View</h4>
|
||||
<textarea class="view-link" style="width: 100%; height: 100px;"></textarea>
|
||||
<h4>Embed this View</h4>
|
||||
<textarea class="view-embed" style="width: 100%; height: 200px;"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="content">
|
||||
<div class="data-explorer-here"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
107
recline.js
107
recline.js
@ -1404,7 +1404,7 @@ this.recline.View = this.recline.View || {};
|
||||
//
|
||||
// <pre>
|
||||
// {
|
||||
// // geomField if specified will be used in preference to lat/lon
|
||||
// // geomField if specified will be used in preference to lat/lon
|
||||
// geomField: {id of field containing geometry in the dataset}
|
||||
// lonField: {id of field containing longitude in the dataset}
|
||||
// latField: {id of field containing latitude in the dataset}
|
||||
@ -1462,6 +1462,11 @@ my.Map = Backbone.View.extend({
|
||||
<div class="editor-buttons"> \
|
||||
<button class="btn editor-update-map">Update</button> \
|
||||
</div> \
|
||||
<div class="editor-options" > \
|
||||
<label class="checkbox"> \
|
||||
<input type="checkbox" id="editor-auto-zoom" checked="checked" /> \
|
||||
Auto zoom to features</label> \
|
||||
</div> \
|
||||
<input type="hidden" class="editor-id" value="map-1" /> \
|
||||
</div> \
|
||||
</form> \
|
||||
@ -1479,7 +1484,8 @@ my.Map = Backbone.View.extend({
|
||||
// Define here events for UI elements
|
||||
events: {
|
||||
'click .editor-update-map': 'onEditorSubmit',
|
||||
'change .editor-field-type': 'onFieldTypeChange'
|
||||
'change .editor-field-type': 'onFieldTypeChange',
|
||||
'change #editor-auto-zoom': 'onAutoZoomChange'
|
||||
},
|
||||
|
||||
initialize: function(options) {
|
||||
@ -1498,15 +1504,27 @@ my.Map = Backbone.View.extend({
|
||||
|
||||
// Listen to changes in the documents
|
||||
this.model.currentDocuments.bind('add', function(doc){self.redraw('add',doc)});
|
||||
this.model.currentDocuments.bind('change', function(doc){
|
||||
self.redraw('remove',doc);
|
||||
self.redraw('add',doc);
|
||||
});
|
||||
this.model.currentDocuments.bind('remove', function(doc){self.redraw('remove',doc)});
|
||||
this.model.currentDocuments.bind('reset', function(){self.redraw('reset')});
|
||||
|
||||
// If the div was hidden, Leaflet needs to recalculate some sizes
|
||||
// to display properly
|
||||
this.bind('view:show',function(){
|
||||
if (self.map) {
|
||||
self.map.invalidateSize();
|
||||
// If the div was hidden, Leaflet needs to recalculate some sizes
|
||||
// to display properly
|
||||
if (self.map){
|
||||
self.map.invalidateSize();
|
||||
if (self._zoomPending && self.autoZoom) {
|
||||
self._zoomToFeatures();
|
||||
self._zoomPending = false;
|
||||
}
|
||||
}
|
||||
self.visible = true;
|
||||
});
|
||||
this.bind('view:hide',function(){
|
||||
self.visible = false;
|
||||
});
|
||||
|
||||
var stateData = _.extend({
|
||||
@ -1518,6 +1536,7 @@ my.Map = Backbone.View.extend({
|
||||
);
|
||||
this.state = new recline.Model.ObjectState(stateData);
|
||||
|
||||
this.autoZoom = true;
|
||||
this.mapReady = false;
|
||||
this.render();
|
||||
},
|
||||
@ -1583,6 +1602,13 @@ my.Map = Backbone.View.extend({
|
||||
this.features.clearLayers();
|
||||
this._add(this.model.currentDocuments.models);
|
||||
}
|
||||
if (action != 'reset' && this.autoZoom){
|
||||
if (this.visible){
|
||||
this._zoomToFeatures();
|
||||
} else {
|
||||
this._zoomPending = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -1629,6 +1655,10 @@ my.Map = Backbone.View.extend({
|
||||
}
|
||||
},
|
||||
|
||||
onAutoZoomChange: function(e){
|
||||
this.autoZoom = !this.autoZoom;
|
||||
},
|
||||
|
||||
// Private: Add one or n features to the map
|
||||
//
|
||||
// For each document passed, a GeoJSON geometry will be extracted and added
|
||||
@ -1656,7 +1686,9 @@ my.Map = Backbone.View.extend({
|
||||
// TODO: mustache?
|
||||
html = ''
|
||||
for (key in doc.attributes){
|
||||
html += '<div><strong>' + key + '</strong>: '+ doc.attributes[key] + '</div>'
|
||||
if (!(self.state.get('geomField') && key == self.state.get('geomField'))){
|
||||
html += '<div><strong>' + key + '</strong>: '+ doc.attributes[key] + '</div>';
|
||||
}
|
||||
}
|
||||
feature.properties = {popupContent: html};
|
||||
|
||||
@ -1707,19 +1739,22 @@ my.Map = Backbone.View.extend({
|
||||
_getGeometryFromDocument: function(doc){
|
||||
if (this.geomReady){
|
||||
if (this.state.get('geomField')){
|
||||
// We assume that the contents of the field are a valid GeoJSON object
|
||||
return doc.attributes[this.state.get('geomField')];
|
||||
var value = doc.get(this.state.get('geomField'));
|
||||
if (typeof(value) === 'string'){
|
||||
// We have a GeoJSON string representation
|
||||
return $.parseJSON(value);
|
||||
} else {
|
||||
// We assume that the contents of the field are a valid GeoJSON object
|
||||
return value;
|
||||
}
|
||||
} else if (this.state.get('lonField') && this.state.get('latField')){
|
||||
// We'll create a GeoJSON like point object from the two lat/lon fields
|
||||
var lon = doc.get(this.state.get('lonField'));
|
||||
var lat = doc.get(this.state.get('latField'));
|
||||
if (lon && lat) {
|
||||
if (!isNaN(parseFloat(lon)) && !isNaN(parseFloat(lat))) {
|
||||
return {
|
||||
type: 'Point',
|
||||
coordinates: [
|
||||
doc.attributes[this.state.get('lonField')],
|
||||
doc.attributes[this.state.get('latField')]
|
||||
]
|
||||
coordinates: [lon,lat]
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -1761,6 +1796,18 @@ my.Map = Backbone.View.extend({
|
||||
return null;
|
||||
},
|
||||
|
||||
// Private: Zoom to map to current features extent if any, or to the full
|
||||
// extent if none.
|
||||
//
|
||||
_zoomToFeatures: function(){
|
||||
var bounds = this.features.getBounds();
|
||||
if (bounds){
|
||||
this.map.fitBounds(bounds);
|
||||
} else {
|
||||
this.map.setView(new L.LatLng(0, 0), 2);
|
||||
}
|
||||
},
|
||||
|
||||
// Private: Sets up the Leaflet map control and the features layer.
|
||||
//
|
||||
// The map uses a base layer from [MapQuest](http://www.mapquest.com) based
|
||||
@ -1785,6 +1832,24 @@ my.Map = Backbone.View.extend({
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// This will be available in the next Leaflet stable release.
|
||||
// In the meantime we add it manually to our layer.
|
||||
this.features.getBounds = function(){
|
||||
var bounds = new L.LatLngBounds();
|
||||
this._iterateLayers(function (layer) {
|
||||
if (layer instanceof L.Marker){
|
||||
bounds.extend(layer.getLatLng());
|
||||
} else {
|
||||
if (layer.getBounds){
|
||||
bounds.extend(layer.getBounds().getNorthEast());
|
||||
bounds.extend(layer.getBounds().getSouthWest());
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
return (typeof bounds.getNorthEast() !== 'undefined') ? bounds : null;
|
||||
}
|
||||
|
||||
this.map.addLayer(this.features);
|
||||
|
||||
this.map.setView(new L.LatLng(0, 0), 2);
|
||||
@ -3404,7 +3469,9 @@ this.recline.Backend = this.recline.Backend || {};
|
||||
var options = options || {};
|
||||
var trm = options.trim;
|
||||
var separator = options.separator || ',';
|
||||
|
||||
var delimiter = options.delimiter || '"';
|
||||
|
||||
|
||||
var cur = '', // The character we are currently processing.
|
||||
inQuote = false,
|
||||
fieldQuoted = false,
|
||||
@ -3451,8 +3518,8 @@ this.recline.Backend = this.recline.Backend || {};
|
||||
field = '';
|
||||
fieldQuoted = false;
|
||||
} else {
|
||||
// If it's not a ", add it to the field buffer
|
||||
if (cur !== '"') {
|
||||
// If it's not a delimiter, add it to the field buffer
|
||||
if (cur !== delimiter) {
|
||||
field += cur;
|
||||
} else {
|
||||
if (!inQuote) {
|
||||
@ -3460,9 +3527,9 @@ this.recline.Backend = this.recline.Backend || {};
|
||||
inQuote = true;
|
||||
fieldQuoted = true;
|
||||
} else {
|
||||
// Next char is ", this is an escaped "
|
||||
if (s.charAt(i + 1) === '"') {
|
||||
field += '"';
|
||||
// Next char is delimiter, this is an escaped delimiter
|
||||
if (s.charAt(i + 1) === delimiter) {
|
||||
field += delimiter;
|
||||
// Skip the next char
|
||||
i += 1;
|
||||
} else {
|
||||
|
||||
@ -127,10 +127,12 @@ my.Map = Backbone.View.extend({
|
||||
this.bind('view:show',function(){
|
||||
// If the div was hidden, Leaflet needs to recalculate some sizes
|
||||
// to display properly
|
||||
self.map.invalidateSize();
|
||||
if (self._zoomPending && self.autoZoom) {
|
||||
self._zoomToFeatures();
|
||||
self._zoomPending = false;
|
||||
if (self.map){
|
||||
self.map.invalidateSize();
|
||||
if (self._zoomPending && self.autoZoom) {
|
||||
self._zoomToFeatures();
|
||||
self._zoomPending = false;
|
||||
}
|
||||
}
|
||||
self.visible = true;
|
||||
});
|
||||
|
||||
52
test/built.html
Normal file
52
test/built.html
Normal file
@ -0,0 +1,52 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Qunit Tests</title>
|
||||
<link rel="stylesheet" href="qunit/qunit.css" type="text/css" media="screen" />
|
||||
<!-- 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" />
|
||||
|
||||
<script type="text/javascript" src="../vendor/jquery/1.7.1/jquery.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/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.flot/0.7/jquery.flot.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 src="sinon/1.1.1/sinon.js"></script>
|
||||
<script src="sinon-qunit/1.0.0/sinon-qunit.js"></script>
|
||||
|
||||
<!-- Link to the built version of recline -->
|
||||
<script type="text/javascript" src="../recline.js"></script>
|
||||
|
||||
<script type="text/javascript" src="base.js"></script>
|
||||
|
||||
<script type="text/javascript" src="model.test.js"></script>
|
||||
<script type="text/javascript" src="backend.test.js"></script>
|
||||
<script type="text/javascript" src="backend.elasticsearch.test.js"></script>
|
||||
<script type="text/javascript" src="backend.localcsv.test.js"></script>
|
||||
|
||||
<script type="text/javascript" src="view-grid.test.js"></script>
|
||||
<script type="text/javascript" src="view-graph.test.js"></script>
|
||||
<script type="text/javascript" src="view-map.test.js"></script>
|
||||
<script type="text/javascript" src="view.test.js"></script>
|
||||
<script type="text/javascript" src="util.test.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h1 id="qunit-header">Qunit Tests</h1>
|
||||
<h2 id="qunit-banner"></h2>
|
||||
<div id="qunit-testrunner-toolbar"></div>
|
||||
<h2 id="qunit-userAgent"></h2>
|
||||
<ol id="qunit-tests"></ol>
|
||||
<div class="fixtures">
|
||||
<table class="test-datatable">
|
||||
</table>
|
||||
|
||||
<div class="data-explorer-here"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user