Added text search facet.

git-svn-id: http://google-refine.googlecode.com/svn/trunk@23 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
David Huynh 2010-02-02 19:16:09 +00:00
parent f3d9a7804e
commit ac46653aa3
10 changed files with 258 additions and 9 deletions

View File

@ -13,6 +13,7 @@ import com.metaweb.gridlock.Jsonizable;
import com.metaweb.gridlock.browsing.facets.Facet; import com.metaweb.gridlock.browsing.facets.Facet;
import com.metaweb.gridlock.browsing.facets.ListFacet; import com.metaweb.gridlock.browsing.facets.ListFacet;
import com.metaweb.gridlock.browsing.facets.RangeFacet; 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.browsing.filters.RowFilter;
import com.metaweb.gridlock.model.Project; import com.metaweb.gridlock.model.Project;
@ -54,6 +55,8 @@ public class Engine implements Jsonizable {
facet = new ListFacet(); facet = new ListFacet();
} else if ("range".equals(type)) { } else if ("range".equals(type)) {
facet = new RangeFacet(); facet = new RangeFacet();
} else if ("text".equals(type)) {
facet = new TextSearchFacet();
} }
if (facet != null) { if (facet != null) {

View File

@ -7,7 +7,7 @@ import org.json.JSONObject;
import org.json.JSONWriter; import org.json.JSONWriter;
import com.metaweb.gridlock.browsing.FilteredRows; 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.browsing.filters.RowFilter;
import com.metaweb.gridlock.expr.Evaluable; import com.metaweb.gridlock.expr.Evaluable;
import com.metaweb.gridlock.expr.Parser; import com.metaweb.gridlock.expr.Parser;
@ -69,19 +69,19 @@ public class RangeFacet implements Facet {
@Override @Override
public RowFilter getRowFilter() { public RowFilter getRowFilter() {
if ("min".equals(_mode)) { if ("min".equals(_mode)) {
return new ExpressionComparisonRowFilter(_eval, _cellIndex) { return new ExpressionNumberComparisonRowFilter(_eval, _cellIndex) {
protected boolean checkValue(double d) { protected boolean checkValue(double d) {
return d >= _min; return d >= _min;
}; };
}; };
} else if ("max".equals(_mode)) { } else if ("max".equals(_mode)) {
return new ExpressionComparisonRowFilter(_eval, _cellIndex) { return new ExpressionNumberComparisonRowFilter(_eval, _cellIndex) {
protected boolean checkValue(double d) { protected boolean checkValue(double d) {
return d <= _max; return d <= _max;
}; };
}; };
} else { } else {
return new ExpressionComparisonRowFilter(_eval, _cellIndex) { return new ExpressionNumberComparisonRowFilter(_eval, _cellIndex) {
protected boolean checkValue(double d) { protected boolean checkValue(double d) {
return d >= _min && d <= _max; return d >= _min && d <= _max;
}; };

View File

@ -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
}
}

View File

@ -7,11 +7,11 @@ import com.metaweb.gridlock.model.Cell;
import com.metaweb.gridlock.model.Project; import com.metaweb.gridlock.model.Project;
import com.metaweb.gridlock.model.Row; import com.metaweb.gridlock.model.Row;
abstract public class ExpressionComparisonRowFilter implements RowFilter { abstract public class ExpressionNumberComparisonRowFilter implements RowFilter {
final protected Evaluable _evaluable; final protected Evaluable _evaluable;
final protected int _cellIndex; final protected int _cellIndex;
public ExpressionComparisonRowFilter(Evaluable evaluable, int cellIndex) { public ExpressionNumberComparisonRowFilter(Evaluable evaluable, int cellIndex) {
_evaluable = evaluable; _evaluable = evaluable;
_cellIndex = cellIndex; _cellIndex = cellIndex;
} }

View File

@ -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);
}

View File

@ -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/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">Gridlock</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" /> <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">Gridlock</h1> </div> <div id="body"> Loading ... </div> </body> </html>

View File

@ -25,6 +25,9 @@ BrowsingEngine.prototype.addFacet = function(type, config, options) {
case "range": case "range":
facet = new RangeFacet(div, config, options); facet = new RangeFacet(div, config, options);
break; break;
case "text":
facet = new TextSearchFacet(div, config, options);
break;
default: default:
facet = new ListFacet(div, config, options); facet = new ListFacet(div, config, options);
} }

View File

@ -234,12 +234,37 @@ DataTableView.prototype._createMenuForColumnHeader = function(column, index, elm
); );
} }
}, },
{},
{ {
label: "By Simple Text Search", 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() { click: function() {
var expression = window.prompt("Enter expression", 'value'); var expression = window.prompt("Enter expression", 'value');
if (expression != null) { if (expression != null) {
@ -247,6 +272,7 @@ DataTableView.prototype._createMenuForColumnHeader = function(column, index, elm
} }
} }
}, },
{},
{ {
label: "By Reconciliation Features", label: "By Reconciliation Features",
submenu: [ submenu: [

View File

@ -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 = $('<div></div>').addClass("facet-title").appendTo(container);
$('<span></span>').text(this._config.name).appendTo(headerDiv);
var removeButton = $('<a href="javascript:{}"></a>').addClass("facet-choice-link").text("remove").click(function() {
self._remove();
}).prependTo(headerDiv);
var bodyDiv = $('<div></div>').addClass("facet-text-body").appendTo(container);
var input = $('<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);
};

View File

@ -77,3 +77,12 @@ a.facet-choice-link:hover {
margin: 5px 0px; margin: 5px 0px;
text-align: center; text-align: center;
} }
.facet-text-body {
border: 1px solid #ccc;
padding: 5px;
}
.facet-text-body input {
width: 98%;
}