Implemented preview expression dialog.
git-svn-id: http://google-refine.googlecode.com/svn/trunk@31 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
a123b0840e
commit
fb34d6f507
@ -27,6 +27,7 @@ import com.metaweb.gridworks.commands.GetHistoryCommand;
|
||||
import com.metaweb.gridworks.commands.GetProcessesCommand;
|
||||
import com.metaweb.gridworks.commands.GetProjectMetadataCommand;
|
||||
import com.metaweb.gridworks.commands.GetRowsCommand;
|
||||
import com.metaweb.gridworks.commands.PreviewExpressionCommand;
|
||||
import com.metaweb.gridworks.commands.ReconcileCommand;
|
||||
import com.metaweb.gridworks.commands.UndoRedoCommand;
|
||||
|
||||
@ -54,6 +55,8 @@ public class GridworksServlet extends HttpServlet {
|
||||
_commands.put("approve-reconcile", new ApproveReconcileCommand());
|
||||
_commands.put("approve-new-reconcile", new ApproveNewReconcileCommand());
|
||||
_commands.put("discard-reconcile", new DiscardReconcileCommand());
|
||||
|
||||
_commands.put("preview-expression", new PreviewExpressionCommand());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -15,6 +15,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.NotImplementedException;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.json.JSONTokener;
|
||||
@ -163,6 +164,12 @@ public abstract class Command {
|
||||
return o;
|
||||
}
|
||||
|
||||
protected JSONArray jsonStringToArray(String s) throws JSONException {
|
||||
JSONTokener t = new JSONTokener(s);
|
||||
JSONArray a = (JSONArray) t.nextValue();
|
||||
return a;
|
||||
}
|
||||
|
||||
protected Engine getEngine(HttpServletRequest request, Project project) throws Exception {
|
||||
Engine engine = new Engine(project);
|
||||
String json = request.getParameter("engine");
|
||||
|
@ -0,0 +1,80 @@
|
||||
package com.metaweb.gridworks.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONWriter;
|
||||
|
||||
|
||||
import com.metaweb.gridworks.expr.Evaluable;
|
||||
import com.metaweb.gridworks.expr.Parser;
|
||||
import com.metaweb.gridworks.model.Cell;
|
||||
import com.metaweb.gridworks.model.Project;
|
||||
import com.metaweb.gridworks.model.Row;
|
||||
|
||||
public class PreviewExpressionCommand extends Command {
|
||||
|
||||
@Override
|
||||
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
|
||||
try {
|
||||
Project project = getProject(request);
|
||||
|
||||
int cellIndex = Integer.parseInt(request.getParameter("cellIndex"));
|
||||
|
||||
String expression = request.getParameter("expression");
|
||||
Evaluable eval = new Parser(expression).getExpression();
|
||||
|
||||
String rowIndicesString = request.getParameter("rowIndices");
|
||||
if (rowIndicesString == null) {
|
||||
respond(response, "{ \"code\" : \"error\", \"message\" : \"No row indices specified\" }");
|
||||
return;
|
||||
}
|
||||
|
||||
JSONArray rowIndices = jsonStringToArray(rowIndicesString);
|
||||
int length = rowIndices.length();
|
||||
|
||||
JSONWriter writer = new JSONWriter(response.getWriter());
|
||||
|
||||
writer.object();
|
||||
writer.key("code"); writer.value("ok");
|
||||
writer.key("results"); writer.array();
|
||||
|
||||
Properties bindings = new Properties();
|
||||
bindings.put("project", project);
|
||||
for (int i = 0; i < length; i++) {
|
||||
Object result = null;
|
||||
|
||||
int rowIndex = rowIndices.getInt(i);
|
||||
if (rowIndex >= 0 && rowIndex < project.rows.size()) {
|
||||
Row row = project.rows.get(rowIndex);
|
||||
if (cellIndex < row.cells.size()) {
|
||||
Cell cell = row.cells.get(cellIndex);
|
||||
if (cell.value != null) {
|
||||
bindings.put("cell", cell);
|
||||
bindings.put("value", cell.value);
|
||||
|
||||
try {
|
||||
result = eval.evaluate(bindings);
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.value(result);
|
||||
}
|
||||
writer.endArray();
|
||||
writer.endObject();
|
||||
} catch (Exception e) {
|
||||
respondException(response, e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1 +1 @@
|
||||
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Gridlock</title>
<link type="text/css" rel="stylesheet" href="http://freebaselibs.com/static/suggest/1.0.3/suggest.min.css" />
<link type="text/css" rel="stylesheet" href="externals/jquery-ui/css/ui-lightness/jquery-ui-1.7.2.custom.css" />
<link rel="stylesheet" href="/styles/common.css" />
<link rel="stylesheet" href="/styles/project.css" />
<link rel="stylesheet" href="/styles/history.css" />
<link rel="stylesheet" href="/styles/browsing.css" />
<link rel="stylesheet" href="/styles/process.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script type="text/javascript" src="http://freebaselibs.com/static/suggest/1.0.3/suggest.min.js"></script>
<script type="text/javascript" src="externals/jquery-ui/jquery-ui-1.7.2.custom.min.js"></script>
<script type="text/javascript" src="scripts/util/misc.js"></script>
<script type="text/javascript" src="scripts/util/url.js"></script>
<script type="text/javascript" src="scripts/util/string.js"></script>
<script type="text/javascript" src="scripts/util/ajax.js"></script>
<script type="text/javascript" src="scripts/util/menu.js"></script>
<script type="text/javascript" src="scripts/util/dialog.js"></script>
<script type="text/javascript" src="scripts/project.js"></script>
<script type="text/javascript" src="scripts/project/list-facet.js"></script>
<script type="text/javascript" src="scripts/project/range-facet.js"></script>
<script type="text/javascript" src="scripts/project/text-search-facet.js"></script>
<script type="text/javascript" src="scripts/project/browsing-engine.js"></script>
<script type="text/javascript" src="scripts/project/data-table-view.js"></script>
<script type="text/javascript" src="scripts/project/history-widget.js"></script>
<script type="text/javascript" src="scripts/project/process-widget.js"></script>
<script type="text/javascript" src="scripts/project/recon-dialog.js"></script>
</head>
<body>
<div id="header">
<h1 id="title"><a href="./index.html">Gridworks</a> » </h1>
</div>
<div id="body">
Loading ...
</div>
</body>
</html>
|
||||
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Gridlock</title>
<link type="text/css" rel="stylesheet" href="http://freebaselibs.com/static/suggest/1.0.3/suggest.min.css" />
<link type="text/css" rel="stylesheet" href="externals/jquery-ui/css/ui-lightness/jquery-ui-1.7.2.custom.css" />
<link rel="stylesheet" href="/styles/common.css" />
<link rel="stylesheet" href="/styles/project.css" />
<link rel="stylesheet" href="/styles/history.css" />
<link rel="stylesheet" href="/styles/browsing.css" />
<link rel="stylesheet" href="/styles/process.css" />
<link rel="stylesheet" href="/styles/expression-preview-dialog.css" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
<script type="text/javascript" src="http://freebaselibs.com/static/suggest/1.0.3/suggest.min.js"></script>
<script type="text/javascript" src="externals/jquery-ui/jquery-ui-1.7.2.custom.min.js"></script>
<script type="text/javascript" src="scripts/util/misc.js"></script>
<script type="text/javascript" src="scripts/util/url.js"></script>
<script type="text/javascript" src="scripts/util/string.js"></script>
<script type="text/javascript" src="scripts/util/ajax.js"></script>
<script type="text/javascript" src="scripts/util/menu.js"></script>
<script type="text/javascript" src="scripts/util/dialog.js"></script>
<script type="text/javascript" src="scripts/project.js"></script>
<script type="text/javascript" src="scripts/project/list-facet.js"></script>
<script type="text/javascript" src="scripts/project/range-facet.js"></script>
<script type="text/javascript" src="scripts/project/text-search-facet.js"></script>
<script type="text/javascript" src="scripts/project/browsing-engine.js"></script>
<script type="text/javascript" src="scripts/project/data-table-view.js"></script>
<script type="text/javascript" src="scripts/project/history-widget.js"></script>
<script type="text/javascript" src="scripts/project/process-widget.js"></script>
<script type="text/javascript" src="scripts/project/recon-dialog.js"></script>
<script type="text/javascript" src="scripts/project/expression-preview-dialog.js"></script>
</head>
<body>
<div id="header">
<h1 id="title"><a href="./index.html">Gridworks</a> » </h1>
</div>
<div id="body">
Loading ...
</div>
</body>
</html>
|
@ -278,12 +278,7 @@ DataTableView.prototype._createMenuForColumnHeader = function(column, index, elm
|
||||
},
|
||||
{
|
||||
label: "Custom Text Facet ...",
|
||||
click: function() {
|
||||
var expression = window.prompt("Enter expression", 'value');
|
||||
if (expression != null) {
|
||||
self._doFilterByExpression(column, expression);
|
||||
}
|
||||
}
|
||||
click: function() { self._doFilterByExpressionPrompt(column); }
|
||||
},
|
||||
{},
|
||||
{
|
||||
@ -489,12 +484,7 @@ DataTableView.prototype._createMenuForColumnHeader = function(column, index, elm
|
||||
{},
|
||||
{
|
||||
label: "Custom Expression ...",
|
||||
click: function() {
|
||||
var expression = window.prompt("Enter expression", 'replace(value, "", "")');
|
||||
if (expression != null) {
|
||||
self._doTextTransform(column, expression);
|
||||
}
|
||||
}
|
||||
click: function() { self._doTextTransformPrompt(column); }
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -536,7 +526,13 @@ DataTableView.prototype._createMenuForColumnHeader = function(column, index, elm
|
||||
], elmt);
|
||||
};
|
||||
|
||||
DataTableView.prototype._doFilterByExpression = function(column, expression) {
|
||||
DataTableView.prototype._doFilterByExpressionPrompt = function(column, expression) {
|
||||
var self = this;
|
||||
DataTableView.promptExpressionOnVisibleRows(
|
||||
column,
|
||||
"Custom Filter on " + column.headerLabel,
|
||||
"value",
|
||||
function(expression) {
|
||||
ui.browsingEngine.addFacet(
|
||||
"list",
|
||||
{
|
||||
@ -545,6 +541,8 @@ DataTableView.prototype._doFilterByExpression = function(column, expression) {
|
||||
"expression" : expression
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
DataTableView.prototype._createUpdateFunction = function() {
|
||||
@ -576,6 +574,49 @@ DataTableView.prototype._doTextTransform = function(column, expression) {
|
||||
);
|
||||
};
|
||||
|
||||
DataTableView.prototype._doTextTransformPrompt = function(column) {
|
||||
var self = this;
|
||||
DataTableView.promptExpressionOnVisibleRows(
|
||||
column,
|
||||
"Custom Transform on " + column.headerLabel,
|
||||
"value",
|
||||
function(expression) {
|
||||
self._doTextTransform(column, expression);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
DataTableView.promptExpressionOnVisibleRows = function(column, title, expression, onDone) {
|
||||
var rowIndices = [];
|
||||
var values = [];
|
||||
|
||||
var rows = theProject.rowModel.rows;
|
||||
for (var r = 0; r < rows.length; r++) {
|
||||
var row = rows[r];
|
||||
|
||||
rowIndices.push(row.i);
|
||||
|
||||
var v = null;
|
||||
if (column.cellIndex < row.cells.length) {
|
||||
var cell = row.cells[column.cellIndex];
|
||||
if (cell != null) {
|
||||
v = cell.v;
|
||||
}
|
||||
}
|
||||
values.push(v);
|
||||
}
|
||||
|
||||
var self = this;
|
||||
new ExpressionPreviewDialog(
|
||||
title,
|
||||
column.cellIndex,
|
||||
rowIndices,
|
||||
values,
|
||||
expression,
|
||||
onDone
|
||||
);
|
||||
};
|
||||
|
||||
DataTableView.prototype._doDiscardReconResults = function(column) {
|
||||
this._doPostThenUpdate(
|
||||
"discard-reconcile",
|
||||
|
97
src/main/webapp/scripts/project/expression-preview-dialog.js
Normal file
97
src/main/webapp/scripts/project/expression-preview-dialog.js
Normal file
@ -0,0 +1,97 @@
|
||||
function ExpressionPreviewDialog(title, cellIndex, rowIndices, values, expression, onDone) {
|
||||
this._cellIndex = cellIndex;
|
||||
this._rowIndices = rowIndices;
|
||||
this._values = values;
|
||||
this._results = null;
|
||||
|
||||
this._expression = expression;
|
||||
this._onDone = onDone;
|
||||
|
||||
this._timerID = null;
|
||||
this._createDialog(title);
|
||||
}
|
||||
|
||||
ExpressionPreviewDialog.prototype._createDialog = function(title) {
|
||||
var self = this;
|
||||
var frame = DialogSystem.createDialog();
|
||||
frame.width("600px");
|
||||
|
||||
var header = $('<div></div>').addClass("dialog-header").text(title).appendTo(frame);
|
||||
var body = $('<div></div>').addClass("dialog-body").appendTo(frame);
|
||||
var footer = $('<div></div>').addClass("dialog-footer").appendTo(frame);
|
||||
|
||||
$('<p></p>').text("Expression:").appendTo(body);
|
||||
|
||||
this._input = $('<input />').width("400px").keypress(function(){
|
||||
self._scheduleUpdate();
|
||||
}).appendTo($('<p></p>').appendTo(body));
|
||||
this._preview = $('<div></div>').addClass("expression-preview-container").appendTo(body);
|
||||
|
||||
$('<button></button>').html(" OK ").click(function() {
|
||||
DialogSystem.dismissUntil(level - 1);
|
||||
self._onDone(self._expression);
|
||||
}).appendTo(footer);
|
||||
|
||||
$('<button></button>').text("Cancel").click(function() {
|
||||
DialogSystem.dismissUntil(level - 1);
|
||||
}).appendTo(footer);
|
||||
|
||||
var level = DialogSystem.showDialog(frame);
|
||||
|
||||
this._input[0].value = this._expression;
|
||||
this._input[0].focus();
|
||||
this._renderPreview(this._expression);
|
||||
};
|
||||
|
||||
ExpressionPreviewDialog.prototype._scheduleUpdate = function() {
|
||||
if (this._timerID != null) {
|
||||
window.clearTimeout(this._timerID);
|
||||
}
|
||||
var self = this;
|
||||
this._timerID = window.setTimeout(function() { self._update(); }, 300);
|
||||
};
|
||||
|
||||
ExpressionPreviewDialog.prototype._update = function() {
|
||||
var self = this;
|
||||
var expression = this._expression = $.trim(this._input[0].value);
|
||||
|
||||
$.post(
|
||||
"/command/preview-expression?" + $.param({ project: theProject.id, expression: expression, cellIndex: this._cellIndex }),
|
||||
{
|
||||
rowIndices: JSON.stringify(this._rowIndices)
|
||||
},
|
||||
function(data) {
|
||||
if (data.code != "error") {
|
||||
self._results = data.results;
|
||||
} else {
|
||||
self._results = null;
|
||||
}
|
||||
self._renderPreview(expression);
|
||||
},
|
||||
"json"
|
||||
);
|
||||
};
|
||||
|
||||
ExpressionPreviewDialog.prototype._renderPreview = function(expression) {
|
||||
var container = this._preview.empty();
|
||||
|
||||
var table = $('<table></table>').appendTo(container)[0];
|
||||
var tr = table.insertRow(0);
|
||||
$(tr.insertCell(0)).addClass("expression-preview-heading").text("value");
|
||||
$(tr.insertCell(1)).addClass("expression-preview-heading").text(expression);
|
||||
|
||||
for (var i = 0; i < this._values.length; i++) {
|
||||
var tr = table.insertRow(table.rows.length);
|
||||
|
||||
$(tr.insertCell(0)).html(this._values[i]);
|
||||
if (this._results != null) {
|
||||
var v = this._results[i];
|
||||
if (v != null) {
|
||||
if ($.isArray(v)) {
|
||||
v = JSON.stringify(v);
|
||||
}
|
||||
$(tr.insertCell(1)).html(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
17
src/main/webapp/styles/expression-preview-dialog.css
Normal file
17
src/main/webapp/styles/expression-preview-dialog.css
Normal file
@ -0,0 +1,17 @@
|
||||
.expression-preview-container {
|
||||
border: 1px solid #ccc;
|
||||
height: 300px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.expression-preview-container td {
|
||||
padding: 2px 5px;
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
td.expression-preview-heading {
|
||||
border-top: none;
|
||||
background: #ddd;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user