Made column header popup menu extensible and split it up into several files so they are easier to manage.
git-svn-id: http://google-refine.googlecode.com/svn/trunk@1150 7d457c2a-affb-35e4-300a-418c747d4874
This commit is contained in:
parent
1a80aa74ff
commit
3d18b425c4
@ -55,8 +55,12 @@ function init() {
|
|||||||
"scripts/facets/text-search-facet.js",
|
"scripts/facets/text-search-facet.js",
|
||||||
|
|
||||||
"scripts/views/data-table/data-table-view.js",
|
"scripts/views/data-table/data-table-view.js",
|
||||||
"scripts/views/data-table/data-table-cell-ui.js",
|
"scripts/views/data-table/cell-ui.js",
|
||||||
"scripts/views/data-table/data-table-column-header-ui.js",
|
"scripts/views/data-table/column-header-ui.js",
|
||||||
|
"scripts/views/data-table/menu-facets.js",
|
||||||
|
"scripts/views/data-table/menu-edit-cells.js",
|
||||||
|
"scripts/views/data-table/menu-edit-column.js",
|
||||||
|
"scripts/views/data-table/menu-reconcile.js",
|
||||||
|
|
||||||
"scripts/reconciliation/recon-manager.js",
|
"scripts/reconciliation/recon-manager.js",
|
||||||
"scripts/reconciliation/recon-dialog.js",
|
"scripts/reconciliation/recon-dialog.js",
|
||||||
|
@ -105,89 +105,16 @@ MenuBar.MenuItems = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
MenuBar._find = function(path, levels) {
|
|
||||||
var menuItems = MenuBar.MenuItems;
|
|
||||||
for (var p = 0; p < path.length && p < levels; p++) {
|
|
||||||
var segment = path[p];
|
|
||||||
var subMenuItems;
|
|
||||||
|
|
||||||
for (var i = 0; i < menuItems.length; i++) {
|
|
||||||
var menuItem = menuItems[i];
|
|
||||||
if (menuItem.id == segment) {
|
|
||||||
if ("submenu" in menuItem) {
|
|
||||||
subMenuItems = menuItem.submenu;
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subMenuItems) {
|
|
||||||
menuItems = subMenuItems;
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return menuItems;
|
|
||||||
};
|
|
||||||
|
|
||||||
MenuBar.appendTo = function(path, what) {
|
MenuBar.appendTo = function(path, what) {
|
||||||
var menuItems = MenuBar._find(path, path.length);
|
MenuBar.appendTo(MenuBar.MenuItems, path, what);
|
||||||
if (menuItems) {
|
|
||||||
if (what instanceof Array) {
|
|
||||||
$.merge(menuItems, what);
|
|
||||||
} else {
|
|
||||||
menuItems.push(what);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MenuBar.insertBefore = function(path, what) {
|
MenuBar.insertBefore = function(path, what) {
|
||||||
var menuItems = MenuBar._find(path, path.length - 1);
|
MenuSystem.insertBefore(MenuBar.MenuItems, path, what);
|
||||||
if ((menuItems) && path.length > 0) {
|
|
||||||
var spliceArgs = [ 0, 0 ];
|
|
||||||
if (what instanceof Array) {
|
|
||||||
$.merge(spliceArgs, what);
|
|
||||||
} else {
|
|
||||||
spliceArgs.push(what);
|
|
||||||
}
|
|
||||||
|
|
||||||
var segment = path[path.length - 1];
|
|
||||||
for (var i = 0; i < menuItems.length; i++) {
|
|
||||||
var menuItem = menuItems[i];
|
|
||||||
if (menuItem.id == segment) {
|
|
||||||
spliceArgs[0] = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Array.prototype.splice.apply(menuItems, spliceArgs);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MenuBar.insertAfter = function(path, what) {
|
MenuBar.insertAfter = function(path, what) {
|
||||||
var menuItems = MenuBar._find(path, path.length - 1);
|
MenuSystem.insertAfter(MenuBar.MenuItems, path, what);
|
||||||
if ((menuItems) && path.length > 0) {
|
|
||||||
var spliceArgs = [ menuItems.length, 0 ];
|
|
||||||
if (what instanceof Array) {
|
|
||||||
$.merge(spliceArgs, what);
|
|
||||||
} else {
|
|
||||||
spliceArgs.push(what);
|
|
||||||
}
|
|
||||||
|
|
||||||
var segment = path[path.length - 1];
|
|
||||||
for (var i = 0; i < menuItems.length; i++) {
|
|
||||||
var menuItem = menuItems[i];
|
|
||||||
if (menuItem.id == segment) {
|
|
||||||
spliceArgs[0] = i + 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Array.prototype.splice.apply(menuItems, spliceArgs);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
MenuBar.handlers = {};
|
MenuBar.handlers = {};
|
||||||
|
@ -153,3 +153,88 @@ MenuSystem.createAndShowStandardMenu = function(items, elmt, options) {
|
|||||||
|
|
||||||
return level;
|
return level;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MenuSystem.find = function(rootItems, path, levels) {
|
||||||
|
var menuItems = rootItems;
|
||||||
|
for (var p = 0; p < path.length && p < levels; p++) {
|
||||||
|
var segment = path[p];
|
||||||
|
var subMenuItems;
|
||||||
|
|
||||||
|
for (var i = 0; i < menuItems.length; i++) {
|
||||||
|
var menuItem = menuItems[i];
|
||||||
|
if (menuItem.id == segment) {
|
||||||
|
if ("submenu" in menuItem) {
|
||||||
|
subMenuItems = menuItem.submenu;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subMenuItems) {
|
||||||
|
menuItems = subMenuItems;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return menuItems;
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuSystem.appendTo = function(rootItems, path, what) {
|
||||||
|
var menuItems = MenuSystem.find(rootItems, path, path.length);
|
||||||
|
if (menuItems) {
|
||||||
|
if (what instanceof Array) {
|
||||||
|
$.merge(menuItems, what);
|
||||||
|
} else {
|
||||||
|
menuItems.push(what);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuSystem.insertBefore = function(rootItems, path, what) {
|
||||||
|
var menuItems = MenuSystem.find(rootItems, path, path.length - 1);
|
||||||
|
if ((menuItems) && path.length > 0) {
|
||||||
|
var spliceArgs = [ 0, 0 ];
|
||||||
|
if (what instanceof Array) {
|
||||||
|
$.merge(spliceArgs, what);
|
||||||
|
} else {
|
||||||
|
spliceArgs.push(what);
|
||||||
|
}
|
||||||
|
|
||||||
|
var segment = path[path.length - 1];
|
||||||
|
for (var i = 0; i < menuItems.length; i++) {
|
||||||
|
var menuItem = menuItems[i];
|
||||||
|
if (menuItem.id == segment) {
|
||||||
|
spliceArgs[0] = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.prototype.splice.apply(menuItems, spliceArgs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuSystem.insertAfter = function(rootItems, path, what) {
|
||||||
|
var menuItems = MenuSystem.find(rootItems, path, path.length - 1);
|
||||||
|
if ((menuItems) && path.length > 0) {
|
||||||
|
var spliceArgs = [ menuItems.length, 0 ];
|
||||||
|
if (what instanceof Array) {
|
||||||
|
$.merge(spliceArgs, what);
|
||||||
|
} else {
|
||||||
|
spliceArgs.push(what);
|
||||||
|
}
|
||||||
|
|
||||||
|
var segment = path[path.length - 1];
|
||||||
|
for (var i = 0; i < menuItems.length; i++) {
|
||||||
|
var menuItem = menuItems[i];
|
||||||
|
if (menuItem.id == segment) {
|
||||||
|
spliceArgs[0] = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.prototype.splice.apply(menuItems, spliceArgs);
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,306 @@
|
|||||||
|
function DataTableColumnHeaderUI(dataTableView, column, columnIndex, td) {
|
||||||
|
this._dataTableView = dataTableView;
|
||||||
|
this._column = column;
|
||||||
|
this._columnIndex = columnIndex;
|
||||||
|
this._td = td;
|
||||||
|
|
||||||
|
this._render();
|
||||||
|
}
|
||||||
|
|
||||||
|
DataTableColumnHeaderUI._extenders = [];
|
||||||
|
|
||||||
|
DataTableColumnHeaderUI.extendMenu = function(extender) {
|
||||||
|
DataTableColumnHeaderUI._extenders.push(extender);
|
||||||
|
};
|
||||||
|
|
||||||
|
DataTableColumnHeaderUI.prototype.getColumn = function() {
|
||||||
|
return this._column;
|
||||||
|
};
|
||||||
|
|
||||||
|
DataTableColumnHeaderUI.prototype._render = function() {
|
||||||
|
var self = this;
|
||||||
|
var td = $(this._td);
|
||||||
|
|
||||||
|
td.html(DOM.loadHTML("core", "scripts/views/data-table/column-header.html"));
|
||||||
|
var elmts = DOM.bind(td);
|
||||||
|
|
||||||
|
elmts.nameContainer.text(this._column.name);
|
||||||
|
elmts.dropdownMenu.click(function() {
|
||||||
|
self._createMenuForColumnHeader(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
if ("reconStats" in this._column) {
|
||||||
|
var stats = this._column.reconStats;
|
||||||
|
if (stats.nonBlanks > 0) {
|
||||||
|
var newPercent = Math.ceil(100 * stats.newTopics / stats.nonBlanks);
|
||||||
|
var matchPercent = Math.ceil(100 * stats.matchedTopics / stats.nonBlanks);
|
||||||
|
var unreconciledPercent = Math.ceil(100 * (stats.nonBlanks - stats.matchedTopics - stats.newTopics) / stats.nonBlanks);
|
||||||
|
var title = matchPercent + "% matched, " + newPercent + "% new, " + unreconciledPercent + "% to be reconciled";
|
||||||
|
|
||||||
|
var whole = $('<div>')
|
||||||
|
.addClass("column-header-recon-stats-bar")
|
||||||
|
.attr("title", title)
|
||||||
|
.appendTo(elmts.reconStatsContainer.show());
|
||||||
|
|
||||||
|
$('<div>')
|
||||||
|
.addClass("column-header-recon-stats-blanks")
|
||||||
|
.width(Math.round((stats.newTopics + stats.matchedTopics) * 100 / stats.nonBlanks) + "%")
|
||||||
|
.appendTo(whole);
|
||||||
|
|
||||||
|
$('<div>')
|
||||||
|
.addClass("column-header-recon-stats-matched")
|
||||||
|
.width(Math.round(stats.matchedTopics * 100 / stats.nonBlanks) + "%")
|
||||||
|
.appendTo(whole);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DataTableColumnHeaderUI.prototype._createMenuForColumnHeader = function(elmt) {
|
||||||
|
var self = this;
|
||||||
|
var menu = [
|
||||||
|
{
|
||||||
|
id: "core/facet",
|
||||||
|
label: "Facet",
|
||||||
|
submenu: []
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
id: "core/edit-cells",
|
||||||
|
label: "Edit Cells",
|
||||||
|
submenu: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/edit-column",
|
||||||
|
label: "Edit Column",
|
||||||
|
submenu: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/transpose",
|
||||||
|
label: "Transpose",
|
||||||
|
submenu: []
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
(
|
||||||
|
this._dataTableView._getSortingCriterionForColumn(this._column.name) == null ?
|
||||||
|
{
|
||||||
|
id: "core/sort",
|
||||||
|
"label": "Sort ...",
|
||||||
|
"click": function() {
|
||||||
|
self._showSortingCriterion(null, self._dataTableView._getSortingCriteriaCount() > 0)
|
||||||
|
}
|
||||||
|
} :
|
||||||
|
{
|
||||||
|
id: "core/sort",
|
||||||
|
label: "Sort",
|
||||||
|
submenu: this.createSortingMenu()
|
||||||
|
}
|
||||||
|
),
|
||||||
|
{
|
||||||
|
id: "core/view",
|
||||||
|
label: "View",
|
||||||
|
tooltip: "Collapse/expand columns to make viewing the data more convenient",
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: "Collapse This Column",
|
||||||
|
click: function() {
|
||||||
|
self._dataTableView._collapsedColumnNames[self._column.name] = true;
|
||||||
|
self._dataTableView.render();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Collapse All Other Columns",
|
||||||
|
click: function() {
|
||||||
|
var collapsedColumnNames = {};
|
||||||
|
for (var i = 0; i < theProject.columnModel.columns.length; i++) {
|
||||||
|
if (i != self._columnIndex) {
|
||||||
|
collapsedColumnNames[theProject.columnModel.columns[i].name] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self._dataTableView._collapsedColumnNames = collapsedColumnNames;
|
||||||
|
self._dataTableView.render();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Collapse All Columns To Left",
|
||||||
|
click: function() {
|
||||||
|
for (var i = 0; i < self._columnIndex; i++) {
|
||||||
|
self._dataTableView._collapsedColumnNames[theProject.columnModel.columns[i].name] = true;
|
||||||
|
}
|
||||||
|
self._dataTableView.render();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Collapse All Columns To Right",
|
||||||
|
click: function() {
|
||||||
|
for (var i = self._columnIndex + 1; i < theProject.columnModel.columns.length; i++) {
|
||||||
|
self._dataTableView._collapsedColumnNames[theProject.columnModel.columns[i].name] = true;
|
||||||
|
}
|
||||||
|
self._dataTableView.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
id: "core/reconcile",
|
||||||
|
label: "Reconcile",
|
||||||
|
tooltip: "Match this column's cells to topics on Freebase",
|
||||||
|
submenu: []
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
for (var i = 0; i < DataTableColumnHeaderUI._extenders.length; i++) {
|
||||||
|
DataTableColumnHeaderUI._extenders[i].call(null, this._column, this, menu);
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuSystem.createAndShowStandardMenu(menu, elmt, { width: "120px", horizontal: false });
|
||||||
|
};
|
||||||
|
|
||||||
|
DataTableColumnHeaderUI.prototype.createSortingMenu = function() {
|
||||||
|
var self = this;
|
||||||
|
var criterion = this._dataTableView._getSortingCriterionForColumn(this._column.name);
|
||||||
|
var criteriaCount = this._dataTableView._getSortingCriteriaCount();
|
||||||
|
var hasOtherCriteria = criterion == null ? (criteriaCount > 0) : criteriaCount > 1;
|
||||||
|
|
||||||
|
var items = [
|
||||||
|
{
|
||||||
|
"label": "Sort ...",
|
||||||
|
"click": function() {
|
||||||
|
self._showSortingCriterion(criterion, hasOtherCriteria)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
if (criterion != null) {
|
||||||
|
items.push({
|
||||||
|
"label": "Reverse",
|
||||||
|
"click": function() {
|
||||||
|
criterion.reverse = !criterion.reverse;
|
||||||
|
self._dataTableView._addSortingCriterion(criterion);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
items.push({
|
||||||
|
"label": "Un-sort",
|
||||||
|
"click": function() {
|
||||||
|
self._dataTableView._removeSortingCriterionOfColumn(criterion.column);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
};
|
||||||
|
|
||||||
|
DataTableColumnHeaderUI.prototype._showSortingCriterion = function(criterion, hasOtherCriteria) {
|
||||||
|
criterion = criterion || {
|
||||||
|
column: this._column.name,
|
||||||
|
valueType: "string",
|
||||||
|
caseSensitive: false,
|
||||||
|
errorPosition: 1,
|
||||||
|
blankPosition: 2
|
||||||
|
};
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var frame = $(DOM.loadHTML("core", "scripts/views/data-table/sorting-criterion-dialog.html"));
|
||||||
|
var elmts = DOM.bind(frame);
|
||||||
|
|
||||||
|
elmts.dialogHeader.text('Sort by ' + this._column.name);
|
||||||
|
|
||||||
|
elmts.valueTypeOptions
|
||||||
|
.find("input[type='radio'][value='" + criterion.valueType + "']")
|
||||||
|
.attr("checked", "checked");
|
||||||
|
|
||||||
|
var setValueType = function(valueType) {
|
||||||
|
var forward = elmts.directionForwardLabel;
|
||||||
|
var reverse = elmts.directionReverseLabel;
|
||||||
|
if (valueType == "string") {
|
||||||
|
forward.html("a - z");
|
||||||
|
reverse.html("z - a");
|
||||||
|
} else if (valueType == "number") {
|
||||||
|
forward.html("smallest first");
|
||||||
|
reverse.html("largest first");
|
||||||
|
} else if (valueType == "date") {
|
||||||
|
forward.html("earliest first");
|
||||||
|
reverse.html("latest first");
|
||||||
|
} else if (valueType == "boolean") {
|
||||||
|
forward.html("false then true");
|
||||||
|
reverse.html("true then false");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
elmts.valueTypeOptions
|
||||||
|
.find("input[type='radio']")
|
||||||
|
.change(function() {
|
||||||
|
setValueType(this.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (criterion.valueType == "string" && criterion.caseSensitive) {
|
||||||
|
elmts.caseSensitiveCheckbox.attr("checked", "checked");
|
||||||
|
}
|
||||||
|
|
||||||
|
elmts.directionOptions
|
||||||
|
.find("input[type='radio'][value='" + (criterion.reverse ? "reverse" : "forward") + "']")
|
||||||
|
.attr("checked", "checked");
|
||||||
|
|
||||||
|
if (hasOtherCriteria) {
|
||||||
|
elmts.sortAloneContainer.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
var validValuesHtml = '<li kind="value">Valid Values</li>';
|
||||||
|
var blankValuesHtml = '<li kind="blank">Blanks</li>';
|
||||||
|
var errorValuesHtml = '<li kind="error">Errors</li>';
|
||||||
|
var positionsHtml;
|
||||||
|
if (criterion.blankPosition < 0) {
|
||||||
|
if (criterion.errorPosition > 0) {
|
||||||
|
positionsHtml = [ blankValuesHtml, validValuesHtml, errorValuesHtml ];
|
||||||
|
} else if (criterion.errorPosition < criterion.blankPosition) {
|
||||||
|
positionsHtml = [ errorValuesHtml, blankValuesHtml, validValuesHtml ];
|
||||||
|
} else {
|
||||||
|
positionsHtml = [ blankValuesHtml, errorValuesHtml, validValuesHtml ];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (criterion.errorPosition < 0) {
|
||||||
|
positionsHtml = [ errorValuesHtml, validValuesHtml, blankValuesHtml ];
|
||||||
|
} else if (criterion.errorPosition < criterion.blankPosition) {
|
||||||
|
positionsHtml = [ validValuesHtml, errorValuesHtml, blankValuesHtml ];
|
||||||
|
} else {
|
||||||
|
positionsHtml = [ validValuesHtml, blankValuesHtml, errorValuesHtml ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elmts.blankErrorPositions.html(positionsHtml.join("")).sortable().disableSelection();
|
||||||
|
|
||||||
|
var level = DialogSystem.showDialog(frame);
|
||||||
|
var dismiss = function() { DialogSystem.dismissUntil(level - 1); };
|
||||||
|
|
||||||
|
setValueType(criterion.valueType);
|
||||||
|
|
||||||
|
elmts.cancelButton.click(dismiss);
|
||||||
|
elmts.okButton.click(function() {
|
||||||
|
var criterion2 = {
|
||||||
|
column: self._column.name,
|
||||||
|
valueType: elmts.valueTypeOptions.find("input[type='radio']:checked")[0].value,
|
||||||
|
reverse: elmts.directionOptions.find("input[type='radio']:checked")[0].value == "reverse"
|
||||||
|
};
|
||||||
|
|
||||||
|
var valuePosition, blankPosition, errorPosition;
|
||||||
|
elmts.blankErrorPositions.find("li").each(function(index, elmt) {
|
||||||
|
var kind = this.getAttribute("kind");
|
||||||
|
if (kind == "value") {
|
||||||
|
valuePosition = index;
|
||||||
|
} else if (kind == "blank") {
|
||||||
|
blankPosition = index;
|
||||||
|
} else if (kind == "error") {
|
||||||
|
errorPosition = index;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
criterion2.blankPosition = blankPosition - valuePosition;
|
||||||
|
criterion2.errorPosition = errorPosition - valuePosition;
|
||||||
|
|
||||||
|
if (criterion2.valueType == "string") {
|
||||||
|
criterion2.caseSensitive = elmts.caseSensitiveCheckbox[0].checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
self._dataTableView._addSortingCriterion(
|
||||||
|
criterion2, elmts.sortAloneContainer.find("input")[0].checked);
|
||||||
|
|
||||||
|
dismiss();
|
||||||
|
});
|
||||||
|
};
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,277 @@
|
|||||||
|
DataTableColumnHeaderUI.extendMenu(function(column, columnHeaderUI, menu) {
|
||||||
|
var doTextTransform = function(expression, onError, repeat, repeatCount) {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"text-transform",
|
||||||
|
{
|
||||||
|
columnName: column.name,
|
||||||
|
expression: expression,
|
||||||
|
onError: onError,
|
||||||
|
repeat: repeat,
|
||||||
|
repeatCount: repeatCount
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ cellsChanged: true }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doTextTransformPrompt = function() {
|
||||||
|
var frame = $(
|
||||||
|
DOM.loadHTML("core", "scripts/views/data-table/text-transform-dialog.html")
|
||||||
|
.replace("$EXPRESSION_PREVIEW_WIDGET$", ExpressionPreviewDialog.generateWidgetHtml()));
|
||||||
|
|
||||||
|
var elmts = DOM.bind(frame);
|
||||||
|
elmts.dialogHeader.text("Custom text transform on column " + column.name);
|
||||||
|
|
||||||
|
var level = DialogSystem.showDialog(frame);
|
||||||
|
var dismiss = function() { DialogSystem.dismissUntil(level - 1); };
|
||||||
|
|
||||||
|
elmts.cancelButton.click(dismiss);
|
||||||
|
elmts.okButton.click(function() {
|
||||||
|
doTextTransform(
|
||||||
|
previewWidget.getExpression(true),
|
||||||
|
$('input[name="text-transform-dialog-onerror-choice"]:checked')[0].value,
|
||||||
|
elmts.repeatCheckbox[0].checked,
|
||||||
|
elmts.repeatCountInput[0].value
|
||||||
|
);
|
||||||
|
dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
var o = DataTableView.sampleVisibleRows(column);
|
||||||
|
var previewWidget = new ExpressionPreviewDialog.Widget(
|
||||||
|
elmts,
|
||||||
|
column.cellIndex,
|
||||||
|
o.rowIndices,
|
||||||
|
o.values,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
previewWidget._prepareUpdate = function(params) {
|
||||||
|
params.repeat = elmts.repeatCheckbox[0].checked;
|
||||||
|
params.repeatCount = elmts.repeatCountInput[0].value;
|
||||||
|
};
|
||||||
|
elmts.repeatCheckbox.click(function() {
|
||||||
|
previewWidget.update();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var doFillDown = function() {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"fill-down",
|
||||||
|
{
|
||||||
|
columnName: column.name
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ modelsChanged: true }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doBlankDown = function() {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"blank-down",
|
||||||
|
{
|
||||||
|
columnName: column.name
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ modelsChanged: true }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doJoinMultiValueCells = function() {
|
||||||
|
var separator = window.prompt("Enter separator to use between values", ", ");
|
||||||
|
if (separator !== null) {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"join-multi-value-cells",
|
||||||
|
{
|
||||||
|
columnName: column.name,
|
||||||
|
keyColumnName: theProject.columnModel.keyColumnName,
|
||||||
|
separator: separator
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ rowsChanged: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var doSplitMultiValueCells = function() {
|
||||||
|
var separator = window.prompt("What separator currently separates the values?", ",");
|
||||||
|
if (separator !== null) {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"split-multi-value-cells",
|
||||||
|
{
|
||||||
|
columnName: column.name,
|
||||||
|
keyColumnName: theProject.columnModel.keyColumnName,
|
||||||
|
separator: separator,
|
||||||
|
mode: "plain"
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ rowsChanged: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuSystem.appendTo(menu, [ "core/edit-cells" ], [
|
||||||
|
{
|
||||||
|
id: "core/text-transform",
|
||||||
|
label: "Transform ...",
|
||||||
|
click: function() { doTextTransformPrompt(); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/common-transforms",
|
||||||
|
label: "Common Transforms",
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: "Unescape HTML entities",
|
||||||
|
click: function() { doTextTransform("value.unescape('html')", "store-blank", true, 10); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Collapse whitespace",
|
||||||
|
click: function() { doTextTransform("value.replaceRegexp('\\s+', ' ')", "store-blank", false, ""); }
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "To Titlecase",
|
||||||
|
click: function() { doTextTransform("toTitlecase(value)", "store-blank", false, ""); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "To Uppercase",
|
||||||
|
click: function() { doTextTransform("toUppercase(value)", "store-blank", false, ""); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "To Lowercase",
|
||||||
|
click: function() { doTextTransform("toLowercase(value)", "store-blank", false, ""); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "To Blank",
|
||||||
|
click: function() { doTextTransform("null", "store-blank", false, ""); }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Fill Down",
|
||||||
|
click: doFillDown
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Blank Down",
|
||||||
|
click: doBlankDown
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Split Multi-Valued Cells ...",
|
||||||
|
click: doSplitMultiValueCells
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Join Multi-Valued Cells ...",
|
||||||
|
click: doJoinMultiValueCells
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Cluster & Edit ...",
|
||||||
|
click: function() { new ClusteringDialog(column.name, "value"); }
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
var doTransposeColumnsIntoRows = function() {
|
||||||
|
var dialog = $(DOM.loadHTML("core", "scripts/views/data-table/transpose-columns-into-rows.html"));
|
||||||
|
|
||||||
|
var elmts = DOM.bind(dialog);
|
||||||
|
elmts.dialogHeader.text('Transpose Cells Across Columns into Rows');
|
||||||
|
|
||||||
|
var level = DialogSystem.showDialog(dialog);
|
||||||
|
var dismiss = function() {
|
||||||
|
DialogSystem.dismissUntil(level - 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
var columns = theProject.columnModel.columns;
|
||||||
|
|
||||||
|
elmts.cancelButton.click(function() { dismiss(); });
|
||||||
|
elmts.okButton.click(function() {
|
||||||
|
var config = {
|
||||||
|
startColumnName: elmts.fromColumnSelect[0].value,
|
||||||
|
columnCount: elmts.toColumnSelect[0].value,
|
||||||
|
combinedColumnName: $.trim(elmts.combinedColumnNameInput[0].value),
|
||||||
|
prependColumnName: elmts.prependColumnNameCheckbox[0].checked,
|
||||||
|
separator: elmts.separatorInput[0].value,
|
||||||
|
ignoreBlankCells: elmts.ignoreBlankCellsCheckbox[0].checked
|
||||||
|
};
|
||||||
|
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"transpose-columns-into-rows",
|
||||||
|
config,
|
||||||
|
null,
|
||||||
|
{ modelsChanged: true }
|
||||||
|
);
|
||||||
|
dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var i = 0; i < columns.length; i++) {
|
||||||
|
var column2 = columns[i];
|
||||||
|
var option = $('<option>').attr("value", column2.name).text(column2.name).appendTo(elmts.fromColumnSelect);
|
||||||
|
if (column2.name == column.name) {
|
||||||
|
option.attr("selected", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var populateToColumn = function() {
|
||||||
|
elmts.toColumnSelect.empty();
|
||||||
|
|
||||||
|
var toColumnName = elmts.fromColumnSelect[0].value;
|
||||||
|
|
||||||
|
var j = 0;
|
||||||
|
for (; j < columns.length; j++) {
|
||||||
|
var column2 = columns[j];
|
||||||
|
if (column2.name == toColumnName) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var k = j + 1; k < columns.length; k++) {
|
||||||
|
var column2 = columns[k];
|
||||||
|
var option = $('<option>').attr("value", k - j + 1).text(column2.name).appendTo(elmts.toColumnSelect);
|
||||||
|
if (k == columns.length - 1) {
|
||||||
|
option.attr("selected", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
populateToColumn();
|
||||||
|
|
||||||
|
elmts.fromColumnSelect.bind("change", populateToColumn);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doTransposeRowsIntoColumns = function() {
|
||||||
|
var rowCount = window.prompt("How many rows to transpose?", "2");
|
||||||
|
if (rowCount != null) {
|
||||||
|
try {
|
||||||
|
rowCount = parseInt(rowCount);
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(rowCount) || rowCount < 2) {
|
||||||
|
alert("Expected an integer at least 2.");
|
||||||
|
} else {
|
||||||
|
var config = {
|
||||||
|
columnName: column.name,
|
||||||
|
rowCount: rowCount
|
||||||
|
};
|
||||||
|
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"transpose-rows-into-columns",
|
||||||
|
config,
|
||||||
|
null,
|
||||||
|
{ modelsChanged: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuSystem.appendTo(menu, [ "core/transpose" ], [
|
||||||
|
{
|
||||||
|
label: "Cells Across Columns into Rows",
|
||||||
|
click: doTransposeColumnsIntoRows
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Cells in Rows into Columns",
|
||||||
|
click: doTransposeRowsIntoColumns
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
@ -0,0 +1,221 @@
|
|||||||
|
DataTableColumnHeaderUI.extendMenu(function(column, columnHeaderUI, menu) {
|
||||||
|
var doAddColumn = function() {
|
||||||
|
var frame = $(
|
||||||
|
DOM.loadHTML("core", "scripts/views/data-table/add-column-dialog.html")
|
||||||
|
.replace("$EXPRESSION_PREVIEW_WIDGET$", ExpressionPreviewDialog.generateWidgetHtml()));
|
||||||
|
|
||||||
|
var elmts = DOM.bind(frame);
|
||||||
|
elmts.dialogHeader.text("Add column based on column " + column.name);
|
||||||
|
|
||||||
|
var level = DialogSystem.showDialog(frame);
|
||||||
|
var dismiss = function() { DialogSystem.dismissUntil(level - 1); };
|
||||||
|
|
||||||
|
elmts.cancelButton.click(dismiss);
|
||||||
|
elmts.okButton.click(function() {
|
||||||
|
var columnName = $.trim(elmts.columnNameInput[0].value);
|
||||||
|
if (!columnName.length) {
|
||||||
|
alert("You must enter a column name.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"add-column",
|
||||||
|
{
|
||||||
|
baseColumnName: column.name,
|
||||||
|
expression: previewWidget.getExpression(true),
|
||||||
|
newColumnName: columnName,
|
||||||
|
columnInsertIndex: columnIndex + 1,
|
||||||
|
onError: $('input[name="create-column-dialog-onerror-choice"]:checked')[0].value
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ modelsChanged: true }
|
||||||
|
);
|
||||||
|
dismiss();
|
||||||
|
});
|
||||||
|
|
||||||
|
var o = DataTableView.sampleVisibleRows(column);
|
||||||
|
var previewWidget = new ExpressionPreviewDialog.Widget(
|
||||||
|
elmts,
|
||||||
|
column.cellIndex,
|
||||||
|
o.rowIndices,
|
||||||
|
o.values,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doAddColumnFromFreebase = function() {
|
||||||
|
var o = DataTableView.sampleVisibleRows(column);
|
||||||
|
new ExtendDataPreviewDialog(
|
||||||
|
column,
|
||||||
|
columnIndex,
|
||||||
|
o.rowIndices,
|
||||||
|
function(extension) {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"extend-data",
|
||||||
|
{
|
||||||
|
baseColumnName: column.name,
|
||||||
|
columnInsertIndex: columnIndex + 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
extension: JSON.stringify(extension)
|
||||||
|
},
|
||||||
|
{ rowsChanged: true, modelsChanged: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doRemoveColumn = function() {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"remove-column",
|
||||||
|
{
|
||||||
|
columnName: column.name
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ modelsChanged: true }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doRenameColumn = function() {
|
||||||
|
var newColumnName = window.prompt("Enter new column name", column.name);
|
||||||
|
if (newColumnName !== null) {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"rename-column",
|
||||||
|
{
|
||||||
|
oldColumnName: column.name,
|
||||||
|
newColumnName: newColumnName
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ modelsChanged: true }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var doMoveColumnTo = function(index) {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"move-column",
|
||||||
|
{
|
||||||
|
columnName: column.name,
|
||||||
|
index: index
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ modelsChanged: true }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doMoveColumnBy = function(change) {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"move-column",
|
||||||
|
{
|
||||||
|
columnName: column.name,
|
||||||
|
index: Gridworks.columnNameToColumnIndex(column.name) + change
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ modelsChanged: true }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doSplitColumn = function() {
|
||||||
|
var frame = $(DOM.loadHTML("core", "scripts/views/data-table/split-column-dialog.html"));
|
||||||
|
var elmts = DOM.bind(frame);
|
||||||
|
elmts.dialogHeader.text("Split column " + column.name + " into several columns");
|
||||||
|
|
||||||
|
var level = DialogSystem.showDialog(frame);
|
||||||
|
var dismiss = function() { DialogSystem.dismissUntil(level - 1); };
|
||||||
|
|
||||||
|
elmts.cancelButton.click(dismiss);
|
||||||
|
elmts.okButton.click(function() {
|
||||||
|
var mode = $("input[name='split-by-mode']:checked")[0].value;
|
||||||
|
var config = {
|
||||||
|
columnName: column.name,
|
||||||
|
mode: mode,
|
||||||
|
guessCellType: elmts.guessCellTypeInput[0].checked,
|
||||||
|
removeOriginalColumn: elmts.removeColumnInput[0].checked
|
||||||
|
};
|
||||||
|
if (mode == "separator") {
|
||||||
|
config.separator = elmts.separatorInput[0].value;
|
||||||
|
if (!(config.separator)) {
|
||||||
|
alert("Please specify a separator.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.regex = elmts.regexInput[0].checked;
|
||||||
|
|
||||||
|
var s = elmts.maxColumnsInput[0].value;
|
||||||
|
if (s) {
|
||||||
|
var n = parseInt(s,10);
|
||||||
|
if (!isNaN(n)) {
|
||||||
|
config.maxColumns = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var s = "[" + elmts.lengthsTextarea[0].value + "]";
|
||||||
|
try {
|
||||||
|
var a = JSON.parse(s);
|
||||||
|
} catch (e) {
|
||||||
|
alert("The given field lengths are not properly formatted.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var lengths = [];
|
||||||
|
$.each(a, function(i,n) { if (typeof n == "number") lengths.push(n); });
|
||||||
|
|
||||||
|
if (lengths.length === 0) {
|
||||||
|
alert("No field length is specified.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
config.fieldLengths = JSON.stringify(lengths);
|
||||||
|
}
|
||||||
|
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"split-column",
|
||||||
|
config,
|
||||||
|
null,
|
||||||
|
{ modelsChanged: true }
|
||||||
|
);
|
||||||
|
dismiss();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuSystem.appendTo(menu, [ "core/edit-column" ], [
|
||||||
|
{
|
||||||
|
label: "Split into Several Columns ...",
|
||||||
|
click: doSplitColumn
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Add Column Based on This Column ...",
|
||||||
|
click: doAddColumn
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Add Columns From Freebase ...",
|
||||||
|
click: doAddColumnFromFreebase
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Rename This Column",
|
||||||
|
click: doRenameColumn
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Remove This Column",
|
||||||
|
click: doRemoveColumn
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Move Column to Beginning",
|
||||||
|
click: function() { doMoveColumnTo(0); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Move Column to End",
|
||||||
|
click: function() { doMoveColumnTo(theProject.columnModel.columns.length - 1); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Move Column Left",
|
||||||
|
click: function() { doMoveColumnBy(-1); }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Move Column Right",
|
||||||
|
click: function() { doMoveColumnBy(1); }
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
218
main/webapp/modules/core/scripts/views/data-table/menu-facets.js
Normal file
218
main/webapp/modules/core/scripts/views/data-table/menu-facets.js
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
DataTableColumnHeaderUI.extendMenu(function(column, columnHeaderUI, menu) {
|
||||||
|
var doFilterByExpressionPrompt = function(expression, type) {
|
||||||
|
DataTableView.promptExpressionOnVisibleRows(
|
||||||
|
column,
|
||||||
|
(type == "list" ? "Custom Facet on column " : "Custom Numeric Facet on column") + column.name,
|
||||||
|
expression,
|
||||||
|
function(expression) {
|
||||||
|
var config = {
|
||||||
|
"name" : column.name,
|
||||||
|
"columnName" : column.name,
|
||||||
|
"expression" : expression
|
||||||
|
};
|
||||||
|
if (type == "range") {
|
||||||
|
config.mode = "range";
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.browsingEngine.addFacet(type, config);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuSystem.appendTo(menu, [ "core/facet" ], [
|
||||||
|
{
|
||||||
|
id: "core/text-facet",
|
||||||
|
label: "Text Facet",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"list",
|
||||||
|
{
|
||||||
|
"name": column.name,
|
||||||
|
"columnName": column.name,
|
||||||
|
"expression": "value"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/numeric-facet",
|
||||||
|
label: "Numeric Facet",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"range",
|
||||||
|
{
|
||||||
|
"name": column.name,
|
||||||
|
"columnName": column.name,
|
||||||
|
"expression": "value",
|
||||||
|
"mode": "range"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/scatterplot-facet",
|
||||||
|
label: "Scatterplot Facet",
|
||||||
|
click: function() {
|
||||||
|
new ScatterplotDialog(column.name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
id: "core/custom-text-facet",
|
||||||
|
label: "Custom Text Facet ...",
|
||||||
|
click: function() {
|
||||||
|
doFilterByExpressionPrompt(null, "list");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/custom-numeric-facet",
|
||||||
|
label: "Custom Numeric Facet ...",
|
||||||
|
click: function() {
|
||||||
|
doFilterByExpressionPrompt(null, "range");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/customized-facets",
|
||||||
|
label: "Customized Facets",
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
id: "core/word-facet",
|
||||||
|
label: "Word Facet",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"list",
|
||||||
|
{
|
||||||
|
"name": column.name,
|
||||||
|
"columnName": column.name,
|
||||||
|
"expression": "value.split(' ')"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
id: "core/numeric-log-facet",
|
||||||
|
label: "Numeric Log Facet",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"range",
|
||||||
|
{
|
||||||
|
"name": column.name,
|
||||||
|
"columnName": column.name,
|
||||||
|
"expression": "value.log()",
|
||||||
|
"mode": "range"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/bounded-numeric-log-facet",
|
||||||
|
label: "1-bounded Numeric Log Facet",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"range",
|
||||||
|
{
|
||||||
|
"name": column.name,
|
||||||
|
"columnName": column.name,
|
||||||
|
"expression": "log(max(1, value))",
|
||||||
|
"mode": "range"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
id: "core/text-length-facet",
|
||||||
|
label: "Text Length Facet",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"range",
|
||||||
|
{
|
||||||
|
"name": column.name,
|
||||||
|
"columnName": column.name,
|
||||||
|
"expression": "value.length()",
|
||||||
|
"mode": "range"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/log-text-length-facet",
|
||||||
|
label: "Log of Text Length Facet",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"range",
|
||||||
|
{
|
||||||
|
"name": column.name,
|
||||||
|
"columnName": column.name,
|
||||||
|
"expression": "value.length().log()",
|
||||||
|
"mode": "range"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/unicode-charcode-facet",
|
||||||
|
label: "Unicode Char-code Facet",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"range",
|
||||||
|
{
|
||||||
|
"name": column.name,
|
||||||
|
"columnName": column.name,
|
||||||
|
"expression": "value.unicode()",
|
||||||
|
"mode": "range"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
id: "core/error-facet",
|
||||||
|
label: "Facet by Error",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"list",
|
||||||
|
{
|
||||||
|
"name": column.name,
|
||||||
|
"columnName": column.name,
|
||||||
|
"expression": "isError(value)"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "core/blank-facet",
|
||||||
|
label: "Facet by Blank",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"list",
|
||||||
|
{
|
||||||
|
"name": column.name,
|
||||||
|
"columnName": column.name,
|
||||||
|
"expression": "isBlank(value)"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
MenuSystem.insertAfter(menu, [ "core/facet" ], [
|
||||||
|
{
|
||||||
|
label: "Text Filter",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"text",
|
||||||
|
{
|
||||||
|
"name" : column.name,
|
||||||
|
"columnName" : column.name,
|
||||||
|
"mode" : "text",
|
||||||
|
"caseSensitive" : false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
@ -0,0 +1,250 @@
|
|||||||
|
DataTableColumnHeaderUI.extendMenu(function(column, columnHeaderUI, menu) {
|
||||||
|
var doReconcile = function() {
|
||||||
|
new ReconDialog(column);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doReconDiscardJudgments = function() {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"recon-discard-judgments",
|
||||||
|
{ columnName: column.name },
|
||||||
|
null,
|
||||||
|
{ cellsChanged: true, columnStatsChanged: true }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doReconMatchBestCandidates = function() {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"recon-match-best-candidates",
|
||||||
|
{ columnName: column.name },
|
||||||
|
null,
|
||||||
|
{ cellsChanged: true, columnStatsChanged: true }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doReconMarkNewTopics = function(shareNewTopics) {
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"recon-mark-new-topics",
|
||||||
|
{ columnName: column.name, shareNewTopics: shareNewTopics },
|
||||||
|
null,
|
||||||
|
{ cellsChanged: true, columnStatsChanged: true }
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
var doSearchToMatch = function() {
|
||||||
|
var frame = DialogSystem.createDialog();
|
||||||
|
frame.width("400px");
|
||||||
|
|
||||||
|
var header = $('<div></div>').addClass("dialog-header").text("Search for Match").appendTo(frame);
|
||||||
|
var body = $('<div></div>').addClass("dialog-body").appendTo(frame);
|
||||||
|
var footer = $('<div></div>').addClass("dialog-footer").appendTo(frame);
|
||||||
|
|
||||||
|
$('<p></p>').text("Search Freebase for a topic to match all filtered cells:").appendTo(body);
|
||||||
|
|
||||||
|
var input = $('<input />').appendTo($('<p></p>').appendTo(body));
|
||||||
|
|
||||||
|
input.suggest({}).bind("fb-select", function(e, data) {
|
||||||
|
var query = {
|
||||||
|
"id" : data.id,
|
||||||
|
"type" : []
|
||||||
|
};
|
||||||
|
var baseUrl = "http://api.freebase.com/api/service/mqlread";
|
||||||
|
var url = baseUrl + "?" + $.param({ query: JSON.stringify({ query: query }) }) + "&callback=?";
|
||||||
|
|
||||||
|
$.getJSON(
|
||||||
|
url,
|
||||||
|
null,
|
||||||
|
function(o) {
|
||||||
|
var types = "result" in o ? o.result.type : [];
|
||||||
|
|
||||||
|
Gridworks.postProcess(
|
||||||
|
"recon-match-specific-topic-to-cells",
|
||||||
|
{
|
||||||
|
columnName: column.name,
|
||||||
|
topicID: data.id,
|
||||||
|
topicGUID: data.guid,
|
||||||
|
topicName: data.name,
|
||||||
|
types: types.join(",")
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
{ cellsChanged: true, columnStatsChanged: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
DialogSystem.dismissUntil(level - 1);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('<button></button>').text("Cancel").click(function() {
|
||||||
|
DialogSystem.dismissUntil(level - 1);
|
||||||
|
}).appendTo(footer);
|
||||||
|
|
||||||
|
var level = DialogSystem.showDialog(frame);
|
||||||
|
input.focus().data("suggest").textchange();
|
||||||
|
};
|
||||||
|
|
||||||
|
MenuSystem.appendTo(menu, [ "core/reconcile" ], [
|
||||||
|
{
|
||||||
|
label: "Start Reconciling ...",
|
||||||
|
tooltip: "Reconcile text in this column with topics on Freebase",
|
||||||
|
click: doReconcile
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Facets",
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: "By Judgment",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"list",
|
||||||
|
{
|
||||||
|
"name" : column.name,
|
||||||
|
"columnName" : column.name,
|
||||||
|
"expression" : "cell.recon.judgment",
|
||||||
|
"omitError" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"scroll" : false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Best Candidate's Relevance Score",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"range",
|
||||||
|
{
|
||||||
|
"name" : column.name,
|
||||||
|
"columnName" : column.name,
|
||||||
|
"expression" : "cell.recon.best.score",
|
||||||
|
"mode" : "range"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Best Candidate's Type Match",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"list",
|
||||||
|
{
|
||||||
|
"name" : column.name,
|
||||||
|
"columnName" : column.name,
|
||||||
|
"expression" : "cell.recon.features.typeMatch",
|
||||||
|
"omitError" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"scroll" : false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Best Candidate's Name Match",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"list",
|
||||||
|
{
|
||||||
|
"name" : column.name,
|
||||||
|
"columnName" : column.name,
|
||||||
|
"expression" : "cell.recon.features.nameMatch",
|
||||||
|
"omitError" : true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"scroll" : false
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Best Candidate's Name Edit Distance",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"range",
|
||||||
|
{
|
||||||
|
"name" : column.name,
|
||||||
|
"columnName" : column.name,
|
||||||
|
"expression" : "cell.recon.features.nameLevenshtein",
|
||||||
|
"mode" : "range"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Best Candidate's Name Word Similarity",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"range",
|
||||||
|
{
|
||||||
|
"name" : column.name,
|
||||||
|
"columnName" : column.name,
|
||||||
|
"expression" : "cell.recon.features.nameWordDistance",
|
||||||
|
"mode" : "range"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Best Candidate's Types",
|
||||||
|
click: function() {
|
||||||
|
ui.browsingEngine.addFacet(
|
||||||
|
"list",
|
||||||
|
{
|
||||||
|
"name" : column.name,
|
||||||
|
"columnName" : column.name,
|
||||||
|
"expression" : "cell.recon.best.type",
|
||||||
|
"omitError" : true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Actions",
|
||||||
|
submenu: [
|
||||||
|
{
|
||||||
|
label: "Match Each Cell to Its Best Candidate",
|
||||||
|
tooltip: "Match each cell to its best candidate in this column for all current filtered rows",
|
||||||
|
click: doReconMatchBestCandidates
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Create a New Topic for Each Cell",
|
||||||
|
tooltip: "Mark to create one new topic for each cell in this column for all current filtered rows",
|
||||||
|
click: function() {
|
||||||
|
doReconMarkNewTopics(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Create One New Topic for Similar Cells",
|
||||||
|
tooltip: "Mark to create one new topic for each group of similar cells in this column for all current filtered rows",
|
||||||
|
click: function() {
|
||||||
|
doReconMarkNewTopics(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Match All Filtered Cells to ...",
|
||||||
|
tooltip: "Search for a topic to match all filtered cells to",
|
||||||
|
click: doSearchToMatch
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
label: "Discard Reconciliation Judgments",
|
||||||
|
tooltip: "Discard reconciliaton judgments in this column for all current filtered rows",
|
||||||
|
click: doReconDiscardJudgments
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user