diff --git a/src/costco.js b/src/costco.js index 7c5b089c..edce7590 100755 --- a/src/costco.js +++ b/src/costco.js @@ -25,6 +25,7 @@ var costco = function() { preview.push({before: JSON.stringify(before), after: JSON.stringify(after)}); } } + // TODO: 2012-01-05 Move this out of this function and up into (view) functions that call this util.render('editPreview', 'expression-preview-container', {rows: preview}); } @@ -166,4 +167,4 @@ var costco = function() { ensureCommit: ensureCommit, uploadCSV: uploadCSV }; -}(); \ No newline at end of file +}(); diff --git a/src/view.js b/src/view.js index 3beb60f2..e416d697 100644 --- a/src/view.js +++ b/src/view.js @@ -147,8 +147,8 @@ my.DataTable = Backbone.View.extend({ var self = this; e.preventDefault(); var actions = { - bulkEdit: function() { self.showDialog('bulkEdit', {name: self.state.currentColumn}) }, - transform: function() { showDialog('transform') }, + bulkEdit: function() { self.showTransformColumnDialog('bulkEdit', {name: self.state.currentColumn}) }, + transform: function() { self.showTransformDialog('transform') }, csv: function() { window.location.href = app.csvUrl }, json: function() { window.location.href = "_rewrite/api/json" }, urlImport: function() { showDialog('urlImport') }, @@ -180,6 +180,37 @@ my.DataTable = Backbone.View.extend({ actions[$(e.target).attr('data-action')](); }, + showTransformColumnDialog: function() { + var $el = $('.dialog-content'); + util.show('dialog'); + var view = new my.ColumnTransform({ + model: this.model + }); + view.state = this.state; + view.render(); + $el.empty(); + $el.append(view.el); + util.observeExit($el, function() { + util.hide('dialog'); + }) + $('.dialog').draggable({ handle: '.dialog-header', cursor: 'move' }); + }, + + showTransformDialog: function() { + var $el = $('.dialog-content'); + util.show('dialog'); + var view = new my.DataTransform({ + }); + view.render(); + $el.empty(); + $el.append(view.el); + util.observeExit($el, function() { + util.hide('dialog'); + }) + $('.dialog').draggable({ handle: '.dialog-header', cursor: 'move' }); + }, + + // ====================================================== // Core Templating template: ' \ @@ -308,6 +339,205 @@ my.DataTableRow = Backbone.View.extend({ } }); + +// View (Dialog) for doing data transformations (on columns of data). +my.ColumnTransform = Backbone.View.extend({ + className: 'transform-column-view', + template: ' \ +
\ + Functional transform on column {{name}} \ +
\ +
\ +
\ + \ + \ + \ + \ + \ + \ +
\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
\ + Expression \ +
\ +
\ + \ +
\ +
\ + No syntax error. \ +
\ +
\ + Preview \ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ + \ + ', + + events: { + 'click .okButton': 'onSubmit' + , 'keydown .expression-preview-code': 'onEditorKeydown' + }, + + initialize: function() { + this.el = $(this.el); + }, + + render: function() { + var htmls = $.mustache(this.template, + {name: this.state.currentColumn} + ) + this.el.html(htmls); + // Put in the basic (identity) transform script + // TODO: put this into the template? + var editor = this.el.find('.expression-preview-code'); + editor.val("function(doc) {\n doc['"+ this.state.currentColumn+"'] = doc['"+ this.state.currentColumn+"'];\n return doc;\n}"); + editor.focus().get(0).setSelectionRange(18, 18); + editor.keydown(); + }, + + onSubmit: function(e) { + var self = this; + var funcText = this.el.find('.expression-preview-code').val(); + var editFunc = costco.evalFunction(funcText); + if (editFunc.errorMessage) { + util.notify("Error with function! " + editFunc.errorMessage); + return; + } + util.hide('dialog'); + util.notify("Updating all visible docs. This could take a while...", {persist: true, loader: true}); + var docs = self.model.currentDocuments.map(function(doc) { + return doc.toJSON(); + }); + // TODO: notify about failed docs? + var toUpdate = costco.mapDocs(docs, editFunc).edited; + var totalToUpdate = toUpdate.length; + function onCompletedUpdate() { + totalToUpdate += -1; + if (totalToUpdate === 0) { + util.notify(toUpdate.length + " documents updated successfully"); + alert('WARNING: We have only updated the docs in this view. (Updating of all docs not yet implemented!)'); + self.remove(); + } + } + // TODO: Very inefficient as we search through all docs every time! + _.each(toUpdate, function(editedDoc) { + var realDoc = self.model.currentDocuments.get(editedDoc.id); + realDoc.set(editedDoc); + realDoc.save().then(onCompletedUpdate).fail(onCompletedUpdate) + }); + }, + + onEditorKeydown: function(e) { + var self = this; + // if you don't setTimeout it won't grab the latest character if you call e.target.value + window.setTimeout( function() { + var errors = self.el.find('.expression-preview-parsing-status'); + var editFunc = costco.evalFunction(e.target.value); + if (!editFunc.errorMessage) { + errors.text('No syntax error.'); + var docs = self.model.currentDocuments.map(function(doc) { + return doc.toJSON(); + }); + costco.previewTransform(docs, editFunc, self.state.currentColumn); + } else { + errors.text(editFunc.errorMessage); + } + }, 1, true); + } +}); + +// View (Dialog) for doing data transformations on whole dataset. +my.DataTransform = Backbone.View.extend({ + className: 'transform-view', + template: ' \ +
\ + Recursive transform on all rows \ +
\ +
\ +
\ +

Traverse and transform objects by visiting every node on a recursive walk using js-traverse.

\ + \ + \ + \ + \ + \ + \ +
\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
\ + Expression \ +
\ +
\ + \ +
\ +
\ + No syntax error. \ +
\ +
\ + Preview \ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ +
\ + \ + ', + + initialize: function() { + this.el = $(this.el); + }, + + render: function() { + this.el.html(this.template); + } +}); + + my.FlotGraph = Backbone.View.extend({ tagName: "div",