From ac46653aa3c8a5d3a3252a0972778cd91f90668e Mon Sep 17 00:00:00 2001 From: David Huynh Date: Tue, 2 Feb 2010 19:16:09 +0000 Subject: [PATCH] Added text search facet. git-svn-id: http://google-refine.googlecode.com/svn/trunk@23 7d457c2a-affb-35e4-300a-418c747d4874 --- .../com/metaweb/gridlock/browsing/Engine.java | 3 + .../gridlock/browsing/facets/RangeFacet.java | 8 +- .../browsing/facets/TextSearchFacet.java | 77 ++++++++++++++++++ ... ExpressionNumberComparisonRowFilter.java} | 4 +- .../ExpressionStringComparisonRowFilter.java | 50 ++++++++++++ src/main/webapp/project.html | 2 +- .../webapp/scripts/project/browsing-engine.js | 3 + .../webapp/scripts/project/data-table-view.js | 30 ++++++- .../scripts/project/text-search-facet.js | 81 +++++++++++++++++++ src/main/webapp/styles/browsing.css | 9 +++ 10 files changed, 258 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/metaweb/gridlock/browsing/facets/TextSearchFacet.java rename src/main/java/com/metaweb/gridlock/browsing/filters/{ExpressionComparisonRowFilter.java => ExpressionNumberComparisonRowFilter.java} (84%) create mode 100644 src/main/java/com/metaweb/gridlock/browsing/filters/ExpressionStringComparisonRowFilter.java create mode 100644 src/main/webapp/scripts/project/text-search-facet.js diff --git a/src/main/java/com/metaweb/gridlock/browsing/Engine.java b/src/main/java/com/metaweb/gridlock/browsing/Engine.java index ff2ebee1b..88c3bc9f9 100644 --- a/src/main/java/com/metaweb/gridlock/browsing/Engine.java +++ b/src/main/java/com/metaweb/gridlock/browsing/Engine.java @@ -13,6 +13,7 @@ import com.metaweb.gridlock.Jsonizable; import com.metaweb.gridlock.browsing.facets.Facet; import com.metaweb.gridlock.browsing.facets.ListFacet; import com.metaweb.gridlock.browsing.facets.RangeFacet; +import com.metaweb.gridlock.browsing.facets.TextSearchFacet; import com.metaweb.gridlock.browsing.filters.RowFilter; import com.metaweb.gridlock.model.Project; @@ -54,6 +55,8 @@ public class Engine implements Jsonizable { facet = new ListFacet(); } else if ("range".equals(type)) { facet = new RangeFacet(); + } else if ("text".equals(type)) { + facet = new TextSearchFacet(); } if (facet != null) { diff --git a/src/main/java/com/metaweb/gridlock/browsing/facets/RangeFacet.java b/src/main/java/com/metaweb/gridlock/browsing/facets/RangeFacet.java index 851871b83..5fea5e4d0 100644 --- a/src/main/java/com/metaweb/gridlock/browsing/facets/RangeFacet.java +++ b/src/main/java/com/metaweb/gridlock/browsing/facets/RangeFacet.java @@ -7,7 +7,7 @@ import org.json.JSONObject; import org.json.JSONWriter; import com.metaweb.gridlock.browsing.FilteredRows; -import com.metaweb.gridlock.browsing.filters.ExpressionComparisonRowFilter; +import com.metaweb.gridlock.browsing.filters.ExpressionNumberComparisonRowFilter; import com.metaweb.gridlock.browsing.filters.RowFilter; import com.metaweb.gridlock.expr.Evaluable; import com.metaweb.gridlock.expr.Parser; @@ -69,19 +69,19 @@ public class RangeFacet implements Facet { @Override public RowFilter getRowFilter() { if ("min".equals(_mode)) { - return new ExpressionComparisonRowFilter(_eval, _cellIndex) { + return new ExpressionNumberComparisonRowFilter(_eval, _cellIndex) { protected boolean checkValue(double d) { return d >= _min; }; }; } else if ("max".equals(_mode)) { - return new ExpressionComparisonRowFilter(_eval, _cellIndex) { + return new ExpressionNumberComparisonRowFilter(_eval, _cellIndex) { protected boolean checkValue(double d) { return d <= _max; }; }; } else { - return new ExpressionComparisonRowFilter(_eval, _cellIndex) { + return new ExpressionNumberComparisonRowFilter(_eval, _cellIndex) { protected boolean checkValue(double d) { return d >= _min && d <= _max; }; diff --git a/src/main/java/com/metaweb/gridlock/browsing/facets/TextSearchFacet.java b/src/main/java/com/metaweb/gridlock/browsing/facets/TextSearchFacet.java new file mode 100644 index 000000000..9d1994cf5 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/facets/TextSearchFacet.java @@ -0,0 +1,77 @@ +package com.metaweb.gridlock.browsing.facets; + +import java.util.Properties; + +import org.json.JSONException; +import org.json.JSONObject; +import org.json.JSONWriter; + +import com.metaweb.gridlock.browsing.FilteredRows; +import com.metaweb.gridlock.browsing.filters.ExpressionNumberComparisonRowFilter; +import com.metaweb.gridlock.browsing.filters.ExpressionStringComparisonRowFilter; +import com.metaweb.gridlock.browsing.filters.RowFilter; +import com.metaweb.gridlock.expr.Evaluable; +import com.metaweb.gridlock.expr.Parser; +import com.metaweb.gridlock.expr.VariableExpr; +import com.metaweb.gridlock.model.Project; + +public class TextSearchFacet implements Facet { + protected String _name; + protected int _cellIndex; + protected String _query; + + protected String _mode; + protected boolean _caseSensitive; + + public TextSearchFacet() { + } + + @Override + public void write(JSONWriter writer, Properties options) + throws JSONException { + + writer.object(); + writer.key("name"); writer.value(_name); + writer.key("cellIndex"); writer.value(_cellIndex); + writer.key("query"); writer.value(_query); + writer.key("mode"); writer.value(_mode); + writer.key("caseSensitive"); writer.value(_caseSensitive); + writer.endObject(); + } + + @Override + public void initializeFromJSON(JSONObject o) throws Exception { + _name = o.getString("name"); + _cellIndex = o.getInt("cellIndex"); + _query = o.getString("query"); + _mode = o.getString("mode"); + _caseSensitive = o.getBoolean("caseSensitive"); + if (!_caseSensitive) { + _query = _query.toLowerCase(); + } + } + + @Override + public RowFilter getRowFilter() { + Evaluable eval = new VariableExpr("value"); + + if ("regex".equals(_mode)) { + return new ExpressionStringComparisonRowFilter(eval, _cellIndex) { + protected boolean checkValue(String s) { + return s.matches(_query); + }; + }; + } else { + return new ExpressionStringComparisonRowFilter(eval, _cellIndex) { + protected boolean checkValue(String s) { + return s.toLowerCase().contains(_query); + }; + }; + } + } + + @Override + public void computeChoices(Project project, FilteredRows filteredRows) { + // nothing to do + } +} diff --git a/src/main/java/com/metaweb/gridlock/browsing/filters/ExpressionComparisonRowFilter.java b/src/main/java/com/metaweb/gridlock/browsing/filters/ExpressionNumberComparisonRowFilter.java similarity index 84% rename from src/main/java/com/metaweb/gridlock/browsing/filters/ExpressionComparisonRowFilter.java rename to src/main/java/com/metaweb/gridlock/browsing/filters/ExpressionNumberComparisonRowFilter.java index 93744c0b0..7cc52a719 100644 --- a/src/main/java/com/metaweb/gridlock/browsing/filters/ExpressionComparisonRowFilter.java +++ b/src/main/java/com/metaweb/gridlock/browsing/filters/ExpressionNumberComparisonRowFilter.java @@ -7,11 +7,11 @@ import com.metaweb.gridlock.model.Cell; import com.metaweb.gridlock.model.Project; import com.metaweb.gridlock.model.Row; -abstract public class ExpressionComparisonRowFilter implements RowFilter { +abstract public class ExpressionNumberComparisonRowFilter implements RowFilter { final protected Evaluable _evaluable; final protected int _cellIndex; - public ExpressionComparisonRowFilter(Evaluable evaluable, int cellIndex) { + public ExpressionNumberComparisonRowFilter(Evaluable evaluable, int cellIndex) { _evaluable = evaluable; _cellIndex = cellIndex; } diff --git a/src/main/java/com/metaweb/gridlock/browsing/filters/ExpressionStringComparisonRowFilter.java b/src/main/java/com/metaweb/gridlock/browsing/filters/ExpressionStringComparisonRowFilter.java new file mode 100644 index 000000000..0038dba57 --- /dev/null +++ b/src/main/java/com/metaweb/gridlock/browsing/filters/ExpressionStringComparisonRowFilter.java @@ -0,0 +1,50 @@ +package com.metaweb.gridlock.browsing.filters; + +import java.util.Properties; + +import com.metaweb.gridlock.expr.Evaluable; +import com.metaweb.gridlock.model.Cell; +import com.metaweb.gridlock.model.Project; +import com.metaweb.gridlock.model.Row; + +abstract public class ExpressionStringComparisonRowFilter implements RowFilter { + final protected Evaluable _evaluable; + final protected int _cellIndex; + + public ExpressionStringComparisonRowFilter(Evaluable evaluable, int cellIndex) { + _evaluable = evaluable; + _cellIndex = cellIndex; + } + + @Override + public boolean filterRow(Project project, int rowIndex, Row row) { + if (_cellIndex < row.cells.size()) { + Cell cell = row.cells.get(_cellIndex); + if (cell != null) { + Properties bindings = new Properties(); + + bindings.put("cell", cell); + bindings.put("value", cell.value); + + Object value = _evaluable.evaluate(bindings); + if (value != null) { + if (value.getClass().isArray()) { + Object[] a = (Object[]) value; + for (Object v : a) { + if (checkValue(v instanceof String ? ((String) v) : v.toString())) { + return true; + } + } + } else { + if (checkValue(value instanceof String ? ((String) value) : value.toString())) { + return true; + } + } + } + } + } + return false; + } + + abstract protected boolean checkValue(String s); +} diff --git a/src/main/webapp/project.html b/src/main/webapp/project.html index b5d3437b5..b6e401997 100644 --- a/src/main/webapp/project.html +++ b/src/main/webapp/project.html @@ -1 +1 @@ - Gridlock
Loading ...
\ No newline at end of file + Gridlock
Loading ...
\ No newline at end of file diff --git a/src/main/webapp/scripts/project/browsing-engine.js b/src/main/webapp/scripts/project/browsing-engine.js index 599919e2f..f3f82c5cb 100644 --- a/src/main/webapp/scripts/project/browsing-engine.js +++ b/src/main/webapp/scripts/project/browsing-engine.js @@ -25,6 +25,9 @@ BrowsingEngine.prototype.addFacet = function(type, config, options) { case "range": facet = new RangeFacet(div, config, options); break; + case "text": + facet = new TextSearchFacet(div, config, options); + break; default: facet = new ListFacet(div, config, options); } diff --git a/src/main/webapp/scripts/project/data-table-view.js b/src/main/webapp/scripts/project/data-table-view.js index 10a98ff38..9c20e7047 100644 --- a/src/main/webapp/scripts/project/data-table-view.js +++ b/src/main/webapp/scripts/project/data-table-view.js @@ -234,12 +234,37 @@ DataTableView.prototype._createMenuForColumnHeader = function(column, index, elm ); } }, + {}, { label: "By Simple Text Search", - click: function() {} + click: function() { + ui.browsingEngine.addFacet( + "text", + { + "name" : column.headerLabel, + "cellIndex" : column.cellIndex, + "mode" : "text", + "caseSensitive" : false + } + ); + } }, { - label: "By Custom Expression", + label: "By Regular Expression", + click: function() { + ui.browsingEngine.addFacet( + "text", + { + "name" : column.headerLabel, + "cellIndex" : column.cellIndex, + "mode" : "regex", + "caseSensitive" : true + } + ); + } + }, + { + label: "By Custom Expression ...", click: function() { var expression = window.prompt("Enter expression", 'value'); if (expression != null) { @@ -247,6 +272,7 @@ DataTableView.prototype._createMenuForColumnHeader = function(column, index, elm } } }, + {}, { label: "By Reconciliation Features", submenu: [ diff --git a/src/main/webapp/scripts/project/text-search-facet.js b/src/main/webapp/scripts/project/text-search-facet.js new file mode 100644 index 000000000..21d5d9abe --- /dev/null +++ b/src/main/webapp/scripts/project/text-search-facet.js @@ -0,0 +1,81 @@ +function TextSearchFacet(div, config, options) { + this._div = div; + this._config = config; + this._options = options; + + this._setDefaults(); + this._timerID = null; + + this._initializeUI(); +} + +TextSearchFacet.prototype._setDefaults = function() { + this._query = null; +}; + +TextSearchFacet.prototype.getJSON = function() { + var o = cloneDeep(this._config); + o.type = "text"; + o.query = this._query; + return o; +}; + +TextSearchFacet.prototype.hasSelection = function() { + return this._query != null; +}; + +TextSearchFacet.prototype._initializeUI = function() { + var self = this; + var container = this._div.empty(); + + var headerDiv = $('
').addClass("facet-title").appendTo(container); + $('').text(this._config.name).appendTo(headerDiv); + + var removeButton = $('').addClass("facet-choice-link").text("remove").click(function() { + self._remove(); + }).prependTo(headerDiv); + + var bodyDiv = $('
').addClass("facet-text-body").appendTo(container); + + var input = $('').appendTo(bodyDiv); + input.keypress(function(evt) { + self._query = this.value; + self._scheduleUpdate(); + }); + input[0].focus(); +}; + +TextSearchFacet.prototype.updateState = function(data) { +}; + +TextSearchFacet.prototype.render = function() { + this._setRangeIndicators(); +}; + +TextSearchFacet.prototype._reset = function() { + this._setDefaults(); + this._updateRest(); +}; + +TextSearchFacet.prototype._remove = function() { + ui.browsingEngine.removeFacet(this); + + this._div = null; + this._config = null; + this._options = null; +}; + +TextSearchFacet.prototype._scheduleUpdate = function() { + if (this._timerID == null) { + var self = this; + this._timerID = window.setTimeout(function() { + self._timerID = null; + self._updateRest(); + }, 500); + } +}; + +TextSearchFacet.prototype._updateRest = function() { + ui.browsingEngine.update(); + ui.dataTableView.update(true); +}; diff --git a/src/main/webapp/styles/browsing.css b/src/main/webapp/styles/browsing.css index 198a8ecef..372dfd971 100644 --- a/src/main/webapp/styles/browsing.css +++ b/src/main/webapp/styles/browsing.css @@ -77,3 +77,12 @@ a.facet-choice-link:hover { margin: 5px 0px; text-align: center; } + +.facet-text-body { + border: 1px solid #ccc; + padding: 5px; +} + +.facet-text-body input { + width: 98%; +}