[build][xs]: commit latest 'build' of recline.js.
This commit is contained in:
parent
657a7fe81b
commit
d2766ad2c8
400
recline.js
400
recline.js
@ -78,16 +78,19 @@ this.recline.Model = this.recline.Model || {};
|
||||
alert('Not supported: sync on BackendMemory with method ' + method + ' and model ' + model);
|
||||
}
|
||||
},
|
||||
getDocuments: function(model, numRows, start) {
|
||||
if (start === undefined) {
|
||||
start = 0;
|
||||
}
|
||||
if (numRows === undefined) {
|
||||
numRows = 10;
|
||||
}
|
||||
query: function(model, queryObj) {
|
||||
var numRows = queryObj.size;
|
||||
var start = queryObj.offset;
|
||||
var dfd = $.Deferred();
|
||||
rows = model.backendConfig.data.rows;
|
||||
var results = rows.slice(start, start+numRows);
|
||||
results = model.backendConfig.data.rows;
|
||||
// not complete sorting!
|
||||
_.each(queryObj.sort, function(item) {
|
||||
results = _.sortBy(results, function(row) {
|
||||
var _out = row[item[0]];
|
||||
return (item[1] == 'asc') ? _out : -1*_out;
|
||||
});
|
||||
});
|
||||
var results = results.slice(start, start+numRows);
|
||||
dfd.resolve(results);
|
||||
return dfd.promise();
|
||||
}
|
||||
@ -133,19 +136,18 @@ this.recline.Model = this.recline.Model || {};
|
||||
}
|
||||
}
|
||||
},
|
||||
getDocuments: function(model, numRows, start) {
|
||||
if (start === undefined) {
|
||||
start = 0;
|
||||
}
|
||||
if (numRows === undefined) {
|
||||
numRows = 10;
|
||||
}
|
||||
query: function(model, queryObj) {
|
||||
var base = model.backendConfig.url;
|
||||
var data = {
|
||||
_limit: queryObj.size
|
||||
, _offset: queryObj.offset
|
||||
};
|
||||
var jqxhr = $.ajax({
|
||||
url: base + '.json?_limit=' + numRows,
|
||||
dataType: 'jsonp',
|
||||
jsonp: '_callback',
|
||||
cache: true
|
||||
url: base + '.json',
|
||||
data: data,
|
||||
dataType: 'jsonp',
|
||||
jsonp: '_callback',
|
||||
cache: true
|
||||
});
|
||||
var dfd = $.Deferred();
|
||||
jqxhr.then(function(results) {
|
||||
@ -206,17 +208,11 @@ this.recline.Model = this.recline.Model || {};
|
||||
alert('This backend only supports read operations');
|
||||
}
|
||||
},
|
||||
getDocuments: function(dataset, numRows, start) {
|
||||
if (start === undefined) {
|
||||
start = 0;
|
||||
}
|
||||
if (numRows === undefined) {
|
||||
numRows = 10;
|
||||
}
|
||||
query: function(dataset, queryObj) {
|
||||
var base = my.backends['dataproxy'].get('dataproxy');
|
||||
var data = {
|
||||
url: dataset.backendConfig.url
|
||||
, 'max-results': numRows
|
||||
, 'max-results': queryObj.size
|
||||
, type: dataset.backendConfig.format
|
||||
};
|
||||
var jqxhr = $.ajax({
|
||||
@ -260,7 +256,7 @@ this.recline.Model = this.recline.Model || {};
|
||||
return dfd.promise(); }
|
||||
},
|
||||
|
||||
getDocuments: function(dataset, start, numRows) {
|
||||
query: function(dataset, queryObj) {
|
||||
var dfd = $.Deferred();
|
||||
var fields = dataset.get('headers');
|
||||
|
||||
@ -581,6 +577,11 @@ this.recline.Model = this.recline.Model || {};
|
||||
this.currentDocuments = new my.DocumentList();
|
||||
this.docCount = null;
|
||||
this.backend = null;
|
||||
this.defaultQuery = {
|
||||
size: 100
|
||||
, offset: 0
|
||||
};
|
||||
// this.queryState = {};
|
||||
},
|
||||
|
||||
// ### getDocuments
|
||||
@ -595,11 +596,14 @@ this.recline.Model = this.recline.Model || {};
|
||||
//
|
||||
// this does not fit very well with Backbone setup. Backbone really expects you to know the ids of objects your are fetching (which you do in classic RESTful ajax-y world). But this paradigm does not fill well with data set up we have here.
|
||||
// This also illustrates the limitations of separating the Dataset and the Backend
|
||||
getDocuments: function(numRows, start) {
|
||||
query: function(queryObj) {
|
||||
this.queryState = queryObj || this.defaultQuery;
|
||||
this.queryState = _.extend({size: 100, offset: 0}, this.queryState);
|
||||
|
||||
var self = this;
|
||||
var backend = my.backends[this.backendConfig.type];
|
||||
var dfd = $.Deferred();
|
||||
backend.getDocuments(this, numRows, start).then(function(rows) {
|
||||
backend.query(this, this.queryState).then(function(rows) {
|
||||
var docs = _.map(rows, function(row) {
|
||||
var _doc = new my.Document(row);
|
||||
_doc.backendConfig = self.backendConfig;
|
||||
@ -637,10 +641,17 @@ var util = function() {
|
||||
var templates = {
|
||||
transformActions: '<li><a data-action="transform" class="menuAction" href="JavaScript:void(0);">Global transform...</a></li>'
|
||||
, columnActions: ' \
|
||||
<li><a data-action="bulkEdit" class="menuAction" href="JavaScript:void(0);">Transform...</a></li> \
|
||||
<li><a data-action="deleteColumn" class="menuAction" href="JavaScript:void(0);">Delete this column</a></li> \
|
||||
<li class="write-op"><a data-action="bulkEdit" class="menuAction" href="JavaScript:void(0);">Transform...</a></li> \
|
||||
<li class="write-op"><a data-action="deleteColumn" class="menuAction" href="JavaScript:void(0);">Delete this column</a></li> \
|
||||
<li><a data-action="sortAsc" class="menuAction" href="JavaScript:void(0);">Sort ascending</a></li> \
|
||||
<li><a data-action="sortDesc" class="menuAction" href="JavaScript:void(0);">Sort descending</a></li> \
|
||||
<li><a data-action="hideColumn" class="menuAction" href="JavaScript:void(0);">Hide this column</a></li> \
|
||||
'
|
||||
, rowActions: '<li><a data-action="deleteRow" class="menuAction" href="JavaScript:void(0);">Delete this row</a></li>'
|
||||
, rowActions: '<li><a data-action="deleteRow" class="menuAction write-op" href="JavaScript:void(0);">Delete this row</a></li>'
|
||||
, rootActions: ' \
|
||||
{{#columns}} \
|
||||
<li><a data-action="showColumn" data-column="{{.}}" class="menuAction" href="JavaScript:void(0);">Add column: {{.}}</a></li> \
|
||||
{{/columns}}'
|
||||
, cellEditor: ' \
|
||||
<div class="menu-container data-table-cell-editor"> \
|
||||
<textarea class="data-table-cell-editor-editor" bind="textarea">{{value}}</textarea> \
|
||||
@ -698,14 +709,6 @@ var util = function() {
|
||||
return o;
|
||||
};
|
||||
|
||||
function inURL(url, str) {
|
||||
var exists = false;
|
||||
if ( url.indexOf( str ) > -1 ) {
|
||||
exists = true;
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
function registerEmitter() {
|
||||
var Emitter = function(obj) {
|
||||
this.emit = function(obj, channel) {
|
||||
@ -810,256 +813,7 @@ var util = function() {
|
||||
}
|
||||
}
|
||||
|
||||
function formatMetadata(data) {
|
||||
out = '<dl>';
|
||||
$.each(data, function(key, val) {
|
||||
if (typeof(val) == 'string' && key[0] != '_') {
|
||||
out = out + '<dt>' + key + '<dd>' + val;
|
||||
} else if (typeof(val) == 'object' && key != "geometry" && val != null) {
|
||||
if (key == 'properties') {
|
||||
$.each(val, function(attr, value){
|
||||
out = out + '<dt>' + attr + '<dd>' + value;
|
||||
})
|
||||
} else {
|
||||
out = out + '<dt>' + key + '<dd>' + val.join(', ');
|
||||
}
|
||||
}
|
||||
});
|
||||
out = out + '</dl>';
|
||||
return out;
|
||||
}
|
||||
|
||||
function getBaseURL(url) {
|
||||
var baseURL = "";
|
||||
if ( inURL(url, '_design') ) {
|
||||
if (inURL(url, '_rewrite')) {
|
||||
var path = url.split("#")[0];
|
||||
if (path[path.length - 1] === "/") {
|
||||
baseURL = "";
|
||||
} else {
|
||||
baseURL = '_rewrite/';
|
||||
}
|
||||
} else {
|
||||
baseURL = '_rewrite/';
|
||||
}
|
||||
}
|
||||
return baseURL;
|
||||
}
|
||||
|
||||
var persist = {
|
||||
restore: function() {
|
||||
$('.persist').each(function(i, el) {
|
||||
var inputId = $(el).attr('id');
|
||||
if(localStorage.getItem(inputId)) $('#' + inputId).val(localStorage.getItem(inputId));
|
||||
})
|
||||
},
|
||||
save: function(id) {
|
||||
localStorage.setItem(id, $('#' + id).val());
|
||||
},
|
||||
clear: function() {
|
||||
$('.persist').each(function(i, el) {
|
||||
localStorage.removeItem($(el).attr('id'));
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// simple debounce adapted from underscore.js
|
||||
function delay(func, wait) {
|
||||
return function() {
|
||||
var context = this, args = arguments;
|
||||
var throttler = function() {
|
||||
delete app.timeout;
|
||||
func.apply(context, args);
|
||||
};
|
||||
if (!app.timeout) app.timeout = setTimeout(throttler, wait);
|
||||
};
|
||||
};
|
||||
|
||||
function resetForm(form) {
|
||||
$(':input', form)
|
||||
.not(':button, :submit, :reset, :hidden')
|
||||
.val('')
|
||||
.removeAttr('checked')
|
||||
.removeAttr('selected');
|
||||
}
|
||||
|
||||
function largestWidth(selector, min) {
|
||||
var min_width = min || 0;
|
||||
$(selector).each(function(i, n){
|
||||
var this_width = $(n).width();
|
||||
if (this_width > min_width) {
|
||||
min_width = this_width;
|
||||
}
|
||||
});
|
||||
return min_width;
|
||||
}
|
||||
|
||||
function getType(obj) {
|
||||
if (obj === null) {
|
||||
return 'null';
|
||||
}
|
||||
if (typeof obj === 'object') {
|
||||
if (obj.constructor.toString().indexOf("Array") !== -1) {
|
||||
return 'array';
|
||||
} else {
|
||||
return 'object';
|
||||
}
|
||||
} else {
|
||||
return typeof obj;
|
||||
}
|
||||
}
|
||||
|
||||
function lookupPath(path) {
|
||||
var docs = app.apiDocs;
|
||||
try {
|
||||
_.each(path, function(node) {
|
||||
docs = docs[node];
|
||||
})
|
||||
} catch(e) {
|
||||
util.notify("Error selecting documents" + e);
|
||||
docs = [];
|
||||
}
|
||||
return docs;
|
||||
}
|
||||
|
||||
function nodePath(docField) {
|
||||
if (docField.children('.object-key').length > 0) return docField.children('.object-key').text();
|
||||
if (docField.children('.array-key').length > 0) return docField.children('.array-key').text();
|
||||
if (docField.children('.doc-key').length > 0) return docField.children('.doc-key').text();
|
||||
return "";
|
||||
}
|
||||
|
||||
function selectedTreePath() {
|
||||
var nodes = []
|
||||
, parent = $('.chosen');
|
||||
while (parent.length > 0) {
|
||||
nodes.push(nodePath(parent));
|
||||
parent = parent.parents('.doc-field:first');
|
||||
}
|
||||
return _.compact(nodes).reverse();
|
||||
}
|
||||
|
||||
// TODO refactor handlers so that they dont stack up as the tree gets bigger
|
||||
function handleTreeClick(e) {
|
||||
var clicked = $(e.target);
|
||||
if(clicked.hasClass('expand')) return;
|
||||
if (clicked.children('.array').length > 0) {
|
||||
var field = clicked;
|
||||
} else if (clicked.siblings('.array').length > 0) {
|
||||
var field = clicked.parents('.doc-field:first');
|
||||
} else {
|
||||
var field = clicked.parents('.array').parents('.doc-field:first');
|
||||
}
|
||||
$('.chosen').removeClass('chosen');
|
||||
field.addClass('chosen');
|
||||
return false;
|
||||
}
|
||||
|
||||
var createTreeNode = {
|
||||
"string": function (obj, key) {
|
||||
var val = $('<div class="doc-value string-type"></div>');
|
||||
if (obj[key].length > 45) {
|
||||
val.append($('<span class="string-type"></span>')
|
||||
.text(obj[key].slice(0, 45)))
|
||||
.append(
|
||||
$('<span class="expand">...</span>')
|
||||
.click(function () {
|
||||
val.html('')
|
||||
.append($('<span class="string-type"></span>')
|
||||
.text(obj[key].length ? obj[key] : " ")
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
else {
|
||||
var val = $('<div class="doc-value string-type"></div>');
|
||||
val.append(
|
||||
$('<span class="string-type"></span>')
|
||||
.text(obj[key].length ? obj[key] : " ")
|
||||
)
|
||||
}
|
||||
return val;
|
||||
}
|
||||
, "number": function (obj, key) {
|
||||
var val = $('<div class="doc-value number"></div>')
|
||||
val.append($('<span class="number-type">' + obj[key] + '</span>'))
|
||||
return val;
|
||||
}
|
||||
, "null": function (obj, key) {
|
||||
var val = $('<div class="doc-value null"></div>')
|
||||
val.append($('<span class="null-type">' + obj[key] + '</span>'))
|
||||
return val;
|
||||
}
|
||||
, "boolean": function (obj, key) {
|
||||
var val = $('<div class="fue null"></div>')
|
||||
val.append($('<span class="null-type">' + obj[key] + '</span>'))
|
||||
return val;
|
||||
}
|
||||
, "array": function (obj, key, indent) {
|
||||
if (!indent) indent = 1;
|
||||
var val = $('<div class="doc-value array"></div>')
|
||||
$('<span class="array-type">[</span><span class="expand" style="float:left">...</span><span class="array-type">]</span>')
|
||||
.click(function (e) {
|
||||
var n = $(this).parent();
|
||||
var cls = 'sub-'+key+'-'+indent
|
||||
n.html('')
|
||||
n.append('<span style="padding-left:'+((indent - 1) * 10)+'px" class="array-type">[</span>')
|
||||
for (i in obj[key]) {
|
||||
var field = $('<div class="doc-field"></div>').click(handleTreeClick);
|
||||
n.append(
|
||||
field
|
||||
.append('<div class="array-key '+cls+'" >'+i+'</div>')
|
||||
.append(createTreeNode[getType(obj[key][i])](obj[key], i, indent + 1))
|
||||
)
|
||||
}
|
||||
n.append('<span style="padding-left:'+((indent - 1) * 10)+'px" class="array-type">]</span>')
|
||||
$('div.'+cls).width(largestWidth('div.'+cls))
|
||||
})
|
||||
.appendTo($('<div class="array-type"></div>').appendTo(val))
|
||||
return val;
|
||||
}
|
||||
, "object": function (obj, key, indent) {
|
||||
if (!indent) indent = 1;
|
||||
var val = $('<div class="doc-value object"></div>')
|
||||
$('<span class="object-type">{</span><span class="expand" style="float:left">...</span><span class="object-type">}</span>')
|
||||
.click(function (e) {
|
||||
var n = $(this).parent();
|
||||
n.html('')
|
||||
n.append('<span style="padding-left:'+((indent - 1) * 10)+'px" class="object-type">{</span>')
|
||||
for (i in obj[key]) {
|
||||
var field = $('<div class="doc-field"></div>').click(handleTreeClick);
|
||||
var p = $('<div class="id-space" style="margin-left:'+(indent * 10)+'px"/>');
|
||||
var di = $('<div class="object-key">'+i+'</div>')
|
||||
field.append(p)
|
||||
.append(di)
|
||||
.append(createTreeNode[getType(obj[key][i])](obj[key], i, indent + 1))
|
||||
n.append(field)
|
||||
}
|
||||
|
||||
n.append('<span style="padding-left:'+((indent - 1) * 10)+'px" class="object-type">}</span>')
|
||||
di.width(largestWidth('div.object-key'))
|
||||
})
|
||||
.appendTo($('<div class="object-type"></div>').appendTo(val))
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
function renderTree(doc) {
|
||||
var d = $('div#document-editor');
|
||||
for (i in doc) {
|
||||
var field = $('<div class="doc-field"></div>').click(handleTreeClick);
|
||||
$('<div class="id-space" />').appendTo(field);
|
||||
field.append('<div class="doc-key doc-key-base">'+i+'</div>')
|
||||
field.append(createTreeNode[getType(doc[i])](doc, i));
|
||||
d.append(field);
|
||||
}
|
||||
|
||||
$('div.doc-key-base').width(largestWidth('div.doc-key-base'))
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
inURL: inURL,
|
||||
registerEmitter: registerEmitter,
|
||||
listenFor: listenFor,
|
||||
show: show,
|
||||
@ -1067,15 +821,7 @@ var util = function() {
|
||||
position: position,
|
||||
render: render,
|
||||
notify: notify,
|
||||
observeExit: observeExit,
|
||||
formatMetadata:formatMetadata,
|
||||
getBaseURL:getBaseURL,
|
||||
resetForm: resetForm,
|
||||
delay: delay,
|
||||
persist: persist,
|
||||
lookupPath: lookupPath,
|
||||
selectedTreePath: selectedTreePath,
|
||||
renderTree: renderTree
|
||||
observeExit: observeExit
|
||||
};
|
||||
}();
|
||||
this.recline = this.recline || {};
|
||||
@ -1184,14 +930,20 @@ my.DataExplorer = Backbone.View.extend({
|
||||
this.model.fetch().then(function(dataset) {
|
||||
self.el.find('.doc-count').text(self.model.docCount || 'Unknown');
|
||||
// initialize of dataTable calls render
|
||||
self.model.getDocuments(self.config.displayCount);
|
||||
var queryObj = {
|
||||
size: self.config.displayCount
|
||||
};
|
||||
self.model.query(queryObj);
|
||||
});
|
||||
},
|
||||
|
||||
onDisplayCountUpdate: function(e) {
|
||||
e.preventDefault();
|
||||
this.config.displayCount = parseInt(this.el.find('input[name="displayCount"]').val());
|
||||
this.model.getDocuments(this.config.displayCount);
|
||||
var queryObj = {
|
||||
size: this.config.displayCount
|
||||
};
|
||||
this.model.query(queryObj);
|
||||
},
|
||||
|
||||
setReadOnly: function() {
|
||||
@ -1260,11 +1012,13 @@ my.DataTable = Backbone.View.extend({
|
||||
this.model.currentDocuments.bind('reset', this.render);
|
||||
this.model.currentDocuments.bind('remove', this.render);
|
||||
this.state = {};
|
||||
this.hiddenHeaders = [];
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .column-header-menu': 'onColumnHeaderClick'
|
||||
, 'click .row-header-menu': 'onRowHeaderClick'
|
||||
, 'click .root-header-menu': 'onRootHeaderClick'
|
||||
, 'click .data-table-menu li a': 'onMenuClick'
|
||||
},
|
||||
|
||||
@ -1294,6 +1048,11 @@ my.DataTable = Backbone.View.extend({
|
||||
util.position('data-table-menu', e);
|
||||
util.render('rowActions', 'data-table-menu');
|
||||
},
|
||||
|
||||
onRootHeaderClick: function(e) {
|
||||
util.position('data-table-menu', e);
|
||||
util.render('rootActions', 'data-table-menu', {'columns': this.hiddenHeaders});
|
||||
},
|
||||
|
||||
onMenuClick: function(e) {
|
||||
var self = this;
|
||||
@ -1301,6 +1060,10 @@ my.DataTable = Backbone.View.extend({
|
||||
var actions = {
|
||||
bulkEdit: function() { self.showTransformColumnDialog('bulkEdit', {name: self.state.currentColumn}) },
|
||||
transform: function() { self.showTransformDialog('transform') },
|
||||
sortAsc: function() { self.setColumnSort('asc') },
|
||||
sortDesc: function() { self.setColumnSort('desc') },
|
||||
hideColumn: function() { self.hideColumn() },
|
||||
showColumn: function() { self.showColumn(e) },
|
||||
// TODO: Delete or re-implement ...
|
||||
csv: function() { window.location.href = app.csvUrl },
|
||||
json: function() { window.location.href = "_rewrite/api/json" },
|
||||
@ -1364,6 +1127,20 @@ my.DataTable = Backbone.View.extend({
|
||||
$('.dialog').draggable({ handle: '.dialog-header', cursor: 'move' });
|
||||
},
|
||||
|
||||
setColumnSort: function(order) {
|
||||
var query = _.extend(this.model.queryState, {sort: [[this.state.currentColumn, order]]});
|
||||
this.model.query(query);
|
||||
},
|
||||
|
||||
hideColumn: function() {
|
||||
this.hiddenHeaders.push(this.state.currentColumn);
|
||||
this.render();
|
||||
},
|
||||
|
||||
showColumn: function(e) {
|
||||
this.hiddenHeaders = _.without(this.hiddenHeaders, $(e.target).data('column'));
|
||||
this.render();
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// Core Templating
|
||||
@ -1373,7 +1150,14 @@ my.DataTable = Backbone.View.extend({
|
||||
<table class="data-table" cellspacing="0"> \
|
||||
<thead> \
|
||||
<tr> \
|
||||
{{#notEmpty}}<th class="column-header"></th>{{/notEmpty}} \
|
||||
{{#notEmpty}} \
|
||||
<th class="column-header"> \
|
||||
<div class="column-header-title"> \
|
||||
<a class="root-header-menu"></a> \
|
||||
<span class="column-header-name"></span> \
|
||||
</div> \
|
||||
</th> \
|
||||
{{/notEmpty}} \
|
||||
{{#headers}} \
|
||||
<th class="column-header"> \
|
||||
<div class="column-header-title"> \
|
||||
@ -1391,11 +1175,15 @@ my.DataTable = Backbone.View.extend({
|
||||
|
||||
toTemplateJSON: function() {
|
||||
var modelData = this.model.toJSON()
|
||||
modelData.notEmpty = ( modelData.headers.length > 0 )
|
||||
modelData.notEmpty = ( this.headers.length > 0 )
|
||||
modelData.headers = this.headers;
|
||||
return modelData;
|
||||
},
|
||||
render: function() {
|
||||
var self = this;
|
||||
this.headers = _.filter(this.model.get('headers'), function(header) {
|
||||
return _.indexOf(self.hiddenHeaders, header) == -1;
|
||||
});
|
||||
var htmls = $.mustache(this.template, this.toTemplateJSON());
|
||||
this.el.html(htmls);
|
||||
this.model.currentDocuments.forEach(function(doc) {
|
||||
@ -1404,10 +1192,11 @@ my.DataTable = Backbone.View.extend({
|
||||
var newView = new my.DataTableRow({
|
||||
model: doc,
|
||||
el: tr,
|
||||
headers: self.model.get('headers')
|
||||
headers: self.headers,
|
||||
});
|
||||
newView.render();
|
||||
});
|
||||
$(".root-header-menu").toggle((self.hiddenHeaders.length > 0));
|
||||
return this;
|
||||
}
|
||||
});
|
||||
@ -1423,6 +1212,7 @@ my.DataTableRow = Backbone.View.extend({
|
||||
this.el = $(this.el);
|
||||
this.model.bind('change', this.render);
|
||||
},
|
||||
|
||||
template: ' \
|
||||
<td><a class="row-header-menu"></a></td> \
|
||||
{{#cells}} \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user