Added a few more math functions.

Fixed expression preview dialog to use tabs.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@126 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-02-23 00:33:39 +00:00
parent 94fbd97bc4
commit 607fca04cb
11 changed files with 149 additions and 75 deletions

View File

@ -25,6 +25,10 @@ import com.metaweb.gridworks.expr.functions.IsNull;
import com.metaweb.gridworks.expr.functions.Join; import com.metaweb.gridworks.expr.functions.Join;
import com.metaweb.gridworks.expr.functions.LastIndexOf; import com.metaweb.gridworks.expr.functions.LastIndexOf;
import com.metaweb.gridworks.expr.functions.Length; import com.metaweb.gridworks.expr.functions.Length;
import com.metaweb.gridworks.expr.functions.Ln;
import com.metaweb.gridworks.expr.functions.Log;
import com.metaweb.gridworks.expr.functions.Max;
import com.metaweb.gridworks.expr.functions.Min;
import com.metaweb.gridworks.expr.functions.Mod; import com.metaweb.gridworks.expr.functions.Mod;
import com.metaweb.gridworks.expr.functions.Not; import com.metaweb.gridworks.expr.functions.Not;
import com.metaweb.gridworks.expr.functions.Or; import com.metaweb.gridworks.expr.functions.Or;
@ -72,6 +76,10 @@ public class Parser {
functionTable.put("floor", new Floor()); functionTable.put("floor", new Floor());
functionTable.put("ceil", new Ceil()); functionTable.put("ceil", new Ceil());
functionTable.put("mod", new Mod()); functionTable.put("mod", new Mod());
functionTable.put("max", new Max());
functionTable.put("min", new Min());
functionTable.put("log", new Log());
functionTable.put("ln", new Ln());
functionTable.put("and", new And()); functionTable.put("and", new And());
functionTable.put("or", new Or()); functionTable.put("or", new Or());

View File

@ -0,0 +1,16 @@
package com.metaweb.gridworks.expr.functions;
import java.util.Properties;
import com.metaweb.gridworks.expr.Function;
public class Ln implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] instanceof Number) {
return Math.log(((Number) args[0]).doubleValue());
}
return null;
}
}

View File

@ -0,0 +1,16 @@
package com.metaweb.gridworks.expr.functions;
import java.util.Properties;
import com.metaweb.gridworks.expr.Function;
public class Log implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 1 && args[0] instanceof Number) {
return Math.log10(((Number) args[0]).doubleValue());
}
return null;
}
}

View File

@ -0,0 +1,18 @@
package com.metaweb.gridworks.expr.functions;
import java.util.Properties;
import com.metaweb.gridworks.expr.Function;
public class Max implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 2 && args[0] instanceof Number && args[1] instanceof Number) {
return Math.max(
((Number) args[0]).doubleValue(),
((Number) args[1]).doubleValue());
}
return null;
}
}

View File

@ -0,0 +1,18 @@
package com.metaweb.gridworks.expr.functions;
import java.util.Properties;
import com.metaweb.gridworks.expr.Function;
public class Min implements Function {
public Object call(Properties bindings, Object[] args) {
if (args.length == 2 && args[0] instanceof Number && args[1] instanceof Number) {
return Math.min(
((Number) args[0]).doubleValue(),
((Number) args[1]).doubleValue());
}
return null;
}
}

View File

@ -7,7 +7,7 @@ import com.metaweb.gridworks.expr.Function;
public class ToNumber implements Function { public class ToNumber implements Function {
public Object call(Properties bindings, Object[] args) { public Object call(Properties bindings, Object[] args) {
if (args.length == 1) { if (args.length == 1 && args[0] != null) {
return args[0] instanceof Number ? args[0] : Double.parseDouble(args[0].toString()); return args[0] instanceof Number ? args[0] : Double.parseDouble(args[0].toString());
} }
return null; return null;

View File

@ -357,7 +357,7 @@ DataTableColumnHeaderUI.prototype._doFilterByExpressionPrompt = function(express
var self = this; var self = this;
DataTableView.promptExpressionOnVisibleRows( DataTableView.promptExpressionOnVisibleRows(
this._column, this._column,
"Custom Filter on " + this._column.headerLabel, (type == "list" ? "Custom Facet on column " : "Custom Numeric Facet on column") + this._column.headerLabel,
expression, expression,
function(expression) { function(expression) {
var config = { var config = {

View File

@ -20,23 +20,25 @@ ExpressionPreviewDialog.prototype._createDialog = function(title) {
var body = $('<div></div>').addClass("dialog-body").appendTo(frame); var body = $('<div></div>').addClass("dialog-body").appendTo(frame);
var footer = $('<div></div>').addClass("dialog-footer").appendTo(frame); var footer = $('<div></div>').addClass("dialog-footer").appendTo(frame);
var layoutTable = $('<table cellspacing="0" cellpadding="0" width="100%"><tr><td></td><td></td></tr></table>').appendTo(body); var html = $(
var mainColumn = layoutTable[0].rows[0].cells[0]; '<div class="dialog-body">' +
var helpColumn = layoutTable[0].rows[0].cells[1]; '<p>Expression: <input bind="expressionInput" /></p>' +
'<div id="expression-preview-tabs">' +
this._renderFooter($(footer)); '<ul>' +
this._renderMainColumn($(mainColumn)); '<li><a href="#expression-preview-tabs-preview">Preview</a></li>' +
this._renderHelpColumn($(helpColumn)); '<li><a href="#expression-preview-tabs-help">Help</a></li>' +
'</ul>' +
this._level = DialogSystem.showDialog(frame); '<div id="expression-preview-tabs-preview">' +
'<div class="expression-preview-container" bind="previewContainer"></div>' +
this._input[0].value = this._expression; '</div>' +
this._input[0].focus(); '<div id="expression-preview-tabs-help" style="display: none;">' +
this._update(); '<div class="expression-preview-help-container" bind="helpTabBody"></div>' +
}; '</div>' +
'</div>' +
'</div>'
).appendTo(body);
ExpressionPreviewDialog.prototype._renderFooter = function(footer) { this._elmts = DOM.bind(html);
var self = this;
$('<button></button>').html("&nbsp;&nbsp;OK&nbsp;&nbsp;").click(function() { $('<button></button>').html("&nbsp;&nbsp;OK&nbsp;&nbsp;").click(function() {
DialogSystem.dismissUntil(self._level - 1); DialogSystem.dismissUntil(self._level - 1);
@ -46,27 +48,38 @@ ExpressionPreviewDialog.prototype._renderFooter = function(footer) {
$('<button></button>').text("Cancel").click(function() { $('<button></button>').text("Cancel").click(function() {
DialogSystem.dismissUntil(self._level - 1); DialogSystem.dismissUntil(self._level - 1);
}).appendTo(footer); }).appendTo(footer);
this._elmts.expressionInput
.width("400px")
.attr("value", this._expression)
.keyup(function(){
self._scheduleUpdate();
})
.focus();
this._level = DialogSystem.showDialog(frame);
$("#expression-preview-tabs").tabs();
$("#expression-preview-tabs-preview").css("display", "");
$("#expression-preview-tabs-help").css("display", "");
this._update();
this._renderHelpTab();
}; };
ExpressionPreviewDialog.prototype._renderHelpColumn = function(helpColumn) { ExpressionPreviewDialog.prototype._renderHelpTab = function() {
helpColumn.addClass("expression-preview-help-column").attr("width", "250").attr("height", "100%");
var outer = $('<div></div>').addClass("expression-preview-help-outer").appendTo(helpColumn);
var inner = $('<div></div>').addClass("expression-preview-help-inner").text("Loading expression language help info ...").appendTo(outer);
var self = this; var self = this;
$.getJSON( $.getJSON(
"/command/get-expression-language-info", "/command/get-expression-language-info",
null, null,
function(data) { function(data) {
self._renderHelp(inner, data); self._renderHelp(data);
}, },
"json" "json"
); );
}; };
ExpressionPreviewDialog.prototype._renderHelp = function(elmt, data) { ExpressionPreviewDialog.prototype._renderHelp = function(data) {
elmt.empty(); var elmt = this._elmts.helpTabBody.empty();
$('<h3></h3>').text("Functions").appendTo(elmt); $('<h3></h3>').text("Functions").appendTo(elmt);
@ -83,17 +96,6 @@ ExpressionPreviewDialog.prototype._renderHelp = function(elmt, data) {
} }
}; };
ExpressionPreviewDialog.prototype._renderMainColumn = function(mainColumn) {
var self = this;
var p = $('<p></p>').text("Expression: ").appendTo(mainColumn);
this._input = $('<input />').width("400px").keypress(function(){
self._scheduleUpdate();
}).appendTo(p);
this._preview = $('<div></div>').addClass("expression-preview-container").appendTo(mainColumn);
};
ExpressionPreviewDialog.prototype._scheduleUpdate = function() { ExpressionPreviewDialog.prototype._scheduleUpdate = function() {
if (this._timerID != null) { if (this._timerID != null) {
window.clearTimeout(this._timerID); window.clearTimeout(this._timerID);
@ -104,7 +106,7 @@ ExpressionPreviewDialog.prototype._scheduleUpdate = function() {
ExpressionPreviewDialog.prototype._update = function() { ExpressionPreviewDialog.prototype._update = function() {
var self = this; var self = this;
var expression = this._expression = $.trim(this._input[0].value); var expression = this._expression = $.trim(this._elmts.expressionInput[0].value);
$.post( $.post(
"/command/preview-expression?" + $.param({ project: theProject.id, expression: expression, cellIndex: this._cellIndex }), "/command/preview-expression?" + $.param({ project: theProject.id, expression: expression, cellIndex: this._cellIndex }),
@ -124,8 +126,7 @@ ExpressionPreviewDialog.prototype._update = function() {
}; };
ExpressionPreviewDialog.prototype._renderPreview = function(expression) { ExpressionPreviewDialog.prototype._renderPreview = function(expression) {
var container = this._preview.empty(); var container = this._elmts.previewContainer.empty();
var table = $('<table width="100%"></table>').appendTo(container)[0]; var table = $('<table width="100%"></table>').appendTo(container)[0];
var tr = table.insertRow(0); var tr = table.insertRow(0);

View File

@ -272,7 +272,7 @@ SchemaAlignmentDialog.UINode.prototype._showNodeConfigDialog = function() {
'<tr>' + '<tr>' +
'<td>' + '<td>' +
'<div class="schema-align-node-dialog-node-type">' + '<div class="schema-align-node-dialog-node-type">' +
'<input type="radio" name="schema-align-node-dialog-node-type" value="cell-as" id="radioNodeTypeCellAs" /> Set to Cell in Column' + '<input type="radio" name="schema-align-node-dialog-node-type" value="cell-as" bind="radioNodeTypeCellAs" /> Set to Cell in Column' +
'</div>' + '</div>' +
'</td>' + '</td>' +
'</tr>' + '</tr>' +
@ -280,51 +280,51 @@ SchemaAlignmentDialog.UINode.prototype._showNodeConfigDialog = function() {
'<td>' + '<td>' +
'<table class="schema-align-node-dialog-layout2">' + '<table class="schema-align-node-dialog-layout2">' +
'<tr>' + '<tr>' +
'<td><div class="schema-alignment-node-dialog-column-list" id="divColumns"></div></td>' + '<td><div class="schema-alignment-node-dialog-column-list" bind="divColumns"></div></td>' +
'<td>' + '<td>' +
'<table class="schema-align-node-dialog-layout2" cols="4">' + '<table class="schema-align-node-dialog-layout2" cols="4">' +
'<tr>' + '<tr>' +
'<td colspan="4">The cell\'s content is used ...</td>' + '<td colspan="4">The cell\'s content is used ...</td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td><input type="radio" name="schema-align-node-dialog-node-subtype" value="cell-as-topic" id="radioNodeTypeCellAsTopic" /></td>' + '<td><input type="radio" name="schema-align-node-dialog-node-subtype" value="cell-as-topic" bind="radioNodeTypeCellAsTopic" /></td>' +
'<td colspan="3">to specify a Freebase topic, as reconciled</td>' + '<td colspan="3">to specify a Freebase topic, as reconciled</td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td></td>' + '<td></td>' +
'<td colspan="1" width="1%"><input type="checkbox" id="radioNodeTypeCellAsTopicCreate" /></td>' + '<td colspan="1" width="1%"><input type="checkbox" bind="radioNodeTypeCellAsTopicCreate" /></td>' +
'<td colspan="2">If not reconciled, create new topic named by the cell\'s content, and assign it a type</td>' + '<td colspan="2">If not reconciled, create new topic named by the cell\'s content, and assign it a type</td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td></td>' + '<td></td>' +
'<td></td>' + '<td></td>' +
'<td colspan="1">Type:</td>' + '<td colspan="1">Type:</td>' +
'<td colspan="1"><input id="cellAsTopicNodeTypeInput" /></td>' + '<td colspan="1"><input bind="cellAsTopicNodeTypeInput" /></td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td><input type="radio" name="schema-align-node-dialog-node-subtype" value="cell-as-value" id="radioNodeTypeCellAsValue" /></td>' + '<td><input type="radio" name="schema-align-node-dialog-node-subtype" value="cell-as-value" bind="radioNodeTypeCellAsValue" /></td>' +
'<td colspan="3">as a literal value</td>' + '<td colspan="3">as a literal value</td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td></td>' + '<td></td>' +
'<td colspan="2">Literal type</td>' + '<td colspan="2">Literal type</td>' +
'<td colspan="1"><select id="cellAsValueTypeSelect">' + literalTypeSelectHtml + '</select></td>' + '<td colspan="1"><select bind="cellAsValueTypeSelect">' + literalTypeSelectHtml + '</select></td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td></td>' + '<td></td>' +
'<td colspan="2">Language (for text)</td>' + '<td colspan="2">Language (for text)</td>' +
'<td colspan="1"><input id="cellAsValueLanguageInput" /></td>' + '<td colspan="1"><input bind="cellAsValueLanguageInput" /></td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td><input type="radio" name="schema-align-node-dialog-node-subtype" value="cell-as-key" id="radioNodeTypeCellAsKey" /></td>' + '<td><input type="radio" name="schema-align-node-dialog-node-subtype" value="cell-as-key" bind="radioNodeTypeCellAsKey" /></td>' +
'<td colspan="3">as a key in a namespace</td>' + '<td colspan="3">as a key in a namespace</td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td></td>' + '<td></td>' +
'<td colspan="2">Namespace</td>' + '<td colspan="2">Namespace</td>' +
'<td colspan="1"><input id="cellAsKeyInput" /></td>' + '<td colspan="1"><input bind="cellAsKeyInput" /></td>' +
'</tr>' + '</tr>' +
'</table>' + '</table>' +
'</td>' + '</td>' +
@ -340,50 +340,50 @@ SchemaAlignmentDialog.UINode.prototype._showNodeConfigDialog = function() {
'<tr>' + '<tr>' +
'<td colspan="3">' + '<td colspan="3">' +
'<div class="schema-align-node-dialog-node-type">' + '<div class="schema-align-node-dialog-node-type">' +
'<input type="radio" name="schema-align-node-dialog-node-type" value="anonymous" id="radioNodeTypeAnonymous" /> Generate an anonymous graph node' + '<input type="radio" name="schema-align-node-dialog-node-type" value="anonymous" bind="radioNodeTypeAnonymous" /> Generate an anonymous graph node' +
'</div>' + '</div>' +
'</td>' + '</td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td></td>' + '<td></td>' +
'<td>Assign a type to the node</td>' + '<td>Assign a type to the node</td>' +
'<td>&nbsp;<input id="anonymousNodeTypeInput" /></td>' + '<td>&nbsp;<input bind="anonymousNodeTypeInput" /></td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td colspan="3">' + '<td colspan="3">' +
'<div class="schema-align-node-dialog-node-type">' + '<div class="schema-align-node-dialog-node-type">' +
'<input type="radio" name="schema-align-node-dialog-node-type" value="topic" id="radioNodeTypeTopic" /> Use one existing Freebase topic' + '<input type="radio" name="schema-align-node-dialog-node-type" value="topic" bind="radioNodeTypeTopic" /> Use one existing Freebase topic' +
'</div>' + '</div>' +
'</td>' + '</td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td></td>' + '<td></td>' +
'<td>Topic</td>' + '<td>Topic</td>' +
'<td><input id="topicNodeTypeInput" /></td>' + '<td><input bind="topicNodeTypeInput" /></td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td colspan="3">' + '<td colspan="3">' +
'<div class="schema-align-node-dialog-node-type">' + '<div class="schema-align-node-dialog-node-type">' +
'<input type="radio" name="schema-align-node-dialog-node-type" value="value" id="radioNodeTypeValue" /> Use a literal value' + '<input type="radio" name="schema-align-node-dialog-node-type" value="value" bind="radioNodeTypeValue" /> Use a literal value' +
'</div>' + '</div>' +
'</td>' + '</td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td></td>' + '<td></td>' +
'<td>Value</td>' + '<td>Value</td>' +
'<td><input id="valueNodeTypeValueInput" /></td>' + '<td><input bind="valueNodeTypeValueInput" /></td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td></td>' + '<td></td>' +
'<td>Value type</td>' + '<td>Value type</td>' +
'<td><select id="valueNodeTypeValueTypeSelect">' + literalTypeSelectHtml + '</select></td>' + '<td><select bind="valueNodeTypeValueTypeSelect">' + literalTypeSelectHtml + '</select></td>' +
'</tr>' + '</tr>' +
'<tr>' + '<tr>' +
'<td></td>' + '<td></td>' +
'<td>Language</td>' + '<td>Language</td>' +
'<td><input id="valueNodeTypeLanguageInput" /></td>' + '<td><input bind="valueNodeTypeLanguageInput" /></td>' +
'</tr>' + '</tr>' +
'</table>' + '</table>' +
'</td>' + '</td>' +

View File

@ -9,10 +9,10 @@ DOM.bind = function(elmt) {
}; };
DOM._bindDOMElement = function(elmt, map) { DOM._bindDOMElement = function(elmt, map) {
var id = elmt.id; var bind = elmt.getAttribute("bind");
if (id != null && id.length > 0) { if (bind != null && bind.length > 0) {
map[id] = $(elmt); map[bind] = $(elmt);
elmt.removeAttribute("id"); elmt.removeAttribute("bind");
} }
if (elmt.hasChildNodes()) { if (elmt.hasChildNodes()) {

View File

@ -1,18 +1,15 @@
td.expression-preview-help-column { #expression-preview-tabs-preview, #expression-preview-tabs-help {
padding-left: 10px; padding: 7px;
}
.expression-preview-help-outer {
border: 1px solid #ccc;
height: 300px;
overflow: auto;
}
.expression-preview-help-inner {
padding: 10px;
} }
.expression-preview-container { .expression-preview-help-container {
border: 1px solid #ccc;
height: 300px; height: 300px;
padding: 5px;
overflow: auto;
}
.expression-preview-container {
height: 300px;
padding: 5px;
overflow: auto; overflow: auto;
} }