function DataTableColumnHeaderUI(dataTableView, column, columnIndex, td) { this._dataTableView = dataTableView; this._column = column; this._columnIndex = columnIndex; this._td = td; this._render(); } DataTableColumnHeaderUI.prototype._render = function() { var self = this; var html = $( '' + '' + '' + '' + '' + '
' + ' ' + '
' + '
' ).appendTo(this._td); var elmts = DOM.bind(html); 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 = $('
') .addClass("column-header-recon-stats-bar") .attr("title", title) .appendTo(elmts.reconStatsContainer.show()); $('
') .addClass("column-header-recon-stats-blanks") .width(Math.round((stats.newTopics + stats.matchedTopics) * 100 / stats.nonBlanks) + "%") .appendTo(whole); $('
') .addClass("column-header-recon-stats-matched") .width(Math.round(stats.matchedTopics * 100 / stats.nonBlanks) + "%") .appendTo(whole); } } }; DataTableColumnHeaderUI.prototype._createMenuForColumnHeader = function(elmt) { self = this; MenuSystem.createAndShowStandardMenu([ { label: "Filter", tooltip: "Filter rows by this column's cell content or characteristics", submenu: [ { label: "Text Facet", click: function() { ui.browsingEngine.addFacet( "list", { "name" : self._column.name, "columnName" : self._column.name, "expression" : "value" } ); } }, { label: "Custom Text Facet ...", click: function() { self._doFilterByExpressionPrompt("value", "list"); } }, { label: "Common Text Facets", submenu: [ { label: "Word Facet", click: function() { ui.browsingEngine.addFacet( "list", { "name" : self._column.name + " value.split(' ')", "columnName" : self._column.name, "expression" : "value.split(' ')" } ); } } ] }, {}, { label: "Numeric Facet", click: function() { ui.browsingEngine.addFacet( "range", { "name" : self._column.name, "columnName" : self._column.name, "expression" : "value", "mode" : "range" } ); } }, { label: "Custom Numeric Facet ...", click: function() { self._doFilterByExpressionPrompt("value", "range"); } }, { label: "Common Numeric Facets", submenu: [ { label: "Text Length Facet", click: function() { ui.browsingEngine.addFacet( "range", { "name" : self._column.name + ": value.length()", "columnName" : self._column.name, "expression" : "value.length()", "mode" : "range" } ); } }, { label: "Log of Text Length Facet", click: function() { ui.browsingEngine.addFacet( "range", { "name" : self._column.name + ": value.length().log()", "columnName" : self._column.name, "expression" : "value.length().log()", "mode" : "range" } ); } }, { label: "Unicode Char-code Facet", click: function() { ui.browsingEngine.addFacet( "range", { "name" : self._column.name + ": value.unicode()", "columnName" : self._column.name, "expression" : "value.unicode()", "mode" : "range" } ); } } ] }, {}, { label: "Text Search", click: function() { ui.browsingEngine.addFacet( "text", { "name" : self._column.name, "columnName" : self._column.name, "mode" : "text", "caseSensitive" : false } ); } }, { label: "Regular Expression Search", click: function() { ui.browsingEngine.addFacet( "text", { "name" : self._column.name + " (regex)", "columnName" : self._column.name, "mode" : "regex", "caseSensitive" : true } ); } }, {}, { label: "By Error", click: function() { ui.browsingEngine.addFacet( "list", { "name" : self._column.name + ": Error?", "columnName" : self._column.name, "expression" : "isError(value)" } ); } }, { label: "By Blank", click: function() { ui.browsingEngine.addFacet( "list", { "name" : self._column.name + ": Blank?", "columnName" : self._column.name, "expression" : "isBlank(value)" } ); } } ] }, {}, { label: "Edit Cells", submenu: [ { label: "Transform ...", click: function() { self._doTextTransformPrompt(); } }, { label: "Common Transforms", submenu: [ { label: "Unescape HTML entities", click: function() { self._doTextTransform("value.unescape('html')", "store-blank", true, 10); } }, { label: "Collapse whitespace", click: function() { self._doTextTransform("value.replaceRegexp('\\s+', ' ')", "store-blank", false, ""); } }, {}, { label: "To Titlecase", click: function() { self._doTextTransform("toTitlecase(value)", "store-blank", false, ""); } }, { label: "To Uppercase", click: function() { self._doTextTransform("toUppercase(value)", "store-blank", false, ""); } }, { label: "To Lowercase", click: function() { self._doTextTransform("toLowercase(value)", "store-blank", false, ""); } } ] }, {}, { label: "Split Multi-Valued Cells ...", click: function() { self._doSplitMultiValueCells(); } }, { label: "Join Multi-Valued Cells ...", click: function() { self._doJoinMultiValueCells(); } }, {}, { label: "Cluster & Edit ...", click: function() { new ClusteringDialog(self._column.name, "value"); } } ] }, { label: "Edit Column", submenu: [ { label: "Add Column Based on This Column ...", click: function() { self._doAddColumn("value"); } }, { label: "Add Columns From Freebase ...", click: function() { self._doAddColumnFromFreebase(); } }, {}, { label: "Remove This Column", click: function() { self._doRemoveColumn(); } }, ] }, {}, { 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(); } } ] }, {}, { label: "Reconcile", tooltip: "Match this column's cells to topics on Freebase", submenu: [ { label: "Start Reconciling ...", tooltip: "Reconcile text in this column with topics on Freebase", click: function() { self._doReconcile(); } }, {}, { 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: function() { self._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() { self._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() { self._doReconMarkNewTopics(true); } }, { label: "Discard Reconciliation Judgments", tooltip: "Discard reconciliaton results in this column for all current filtered rows", click: function() { self._doReconDiscardJudgments(); } }, {}, { label: "Match Filtered Cells to ...", tooltip: "Search for a topic to match all filtered cells to", click: function() { self._doSearchToMatch(); } } ] }, { label: "Reconcile Filter", tooltip: "Match this column's cells to topics on Freebase", submenu: [ { label: "By Judgment", click: function() { ui.browsingEngine.addFacet( "list", { "name" : self._column.name + ": judgment", "columnName" : self._column.name, "expression" : "cell.recon.judgment", "omitError" : true }, { "scroll" : false } ); } }, {}, { label: "Best Candidate's Relevance Score", click: function() { ui.browsingEngine.addFacet( "range", { "name" : self._column.name + ": best candidate's score", "columnName" : self._column.name, "expression" : "cell.recon.best.score", "mode" : "range" }, { } ); } }, { label: "Best Candidate's Type Match", click: function() { ui.browsingEngine.addFacet( "list", { "name" : self._column.name + ": best candidate's type match", "columnName" : self._column.name, "expression" : "cell.recon.features.typeMatch", "omitError" : true }, { "scroll" : false } ); } }, { label: "Best Candidate's Name Match", click: function() { ui.browsingEngine.addFacet( "list", { "name" : self._column.name + ": best candidate's name match", "columnName" : self._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" : self._column.name + ": best candidate's name edit distance", "columnName" : self._column.name, "expression" : "cell.recon.features.nameLevenshtein", "mode" : "range" }, { } ); } }, { label: "Best Candidate's Name Word Similarity", click: function() { ui.browsingEngine.addFacet( "range", { "name" : self._column.name + ": best candidate's name word similarity", "columnName" : self._column.name, "expression" : "cell.recon.features.nameWordDistance", "mode" : "range" }, { } ); } }, {}, { label: "Best Candidate's Types", click: function() { ui.browsingEngine.addFacet( "list", { "name" : self._column.name + ": best candidate's types", "columnName" : self._column.name, "expression" : "cell.recon.best.type", "omitError" : true } ); } } ] } ], elmt, { width: "120px", horizontal: false }); }; DataTableColumnHeaderUI.prototype._doFilterByExpressionPrompt = function(expression, type) { var self = this; DataTableView.promptExpressionOnVisibleRows( this._column, (type == "list" ? "Custom Facet on column " : "Custom Numeric Facet on column") + this._column.name, expression, function(expression) { var config = { "name" : self._column.name + ": " + expression, "columnName" : self._column.name, "expression" : expression }; if (type == "range") { config.mode = "range"; } ui.browsingEngine.addFacet(type, config); } ); }; DataTableColumnHeaderUI.prototype._doTextTransform = function(expression, onError, repeat, repeatCount) { Gridworks.postProcess( "text-transform", { columnName: this._column.name, expression: expression, onError: onError, repeat: repeat, repeatCount: repeatCount }, null, { cellsChanged: true } ); }; DataTableColumnHeaderUI.prototype._doTextTransformPrompt = function() { var self = this; var frame = DialogSystem.createDialog(); frame.width("700px"); var header = $('
').addClass("dialog-header").text("Custom text transform on column " + this._column.name).appendTo(frame); var body = $('
').addClass("dialog-body").appendTo(frame); var footer = $('
').addClass("dialog-footer").appendTo(frame); body.html( '
' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
' + ExpressionPreviewDialog.generateWidgetHtml() + '
' + 'On error' + '' + ' set to blank
' + ' store error
' + ' keep original' + '
' + '' + '' + 'Re-transform until no change
' + 'up to times' + '
' ); var bodyElmts = DOM.bind(body); footer.html( '' + '' ); var footerElmts = DOM.bind(footer); var level = DialogSystem.showDialog(frame); var dismiss = function() { DialogSystem.dismissUntil(level - 1); }; footerElmts.okButton.click(function() { self._doTextTransform( previewWidget.getExpression(true), $('input[name="text-transform-dialog-onerror-choice"]:checked')[0].value, bodyElmts.repeatCheckbox[0].checked, bodyElmts.repeatCountInput[0].value ); dismiss(); }) footerElmts.cancelButton.click(dismiss); var o = DataTableView.sampleVisibleRows(this._column); var previewWidget = new ExpressionPreviewDialog.Widget( bodyElmts, this._column.cellIndex, o.rowIndices, o.values, "value" ); previewWidget._prepareUpdate = function(params) { params.repeat = bodyElmts.repeatCheckbox[0].checked; params.repeatCount = bodyElmts.repeatCountInput[0].value; }; bodyElmts.repeatCheckbox.click(function() { previewWidget.update(); }); }; DataTableColumnHeaderUI.prototype._doReconcile = function() { var self = this; var dismissBusy = DialogSystem.showBusy(); $.post( "/command/guess-types-of-column?" + $.param({ project: theProject.id, columnName: this._column.name }), null, function(data) { if (data.code != "ok") { dismissBusy(); new ReconDialog(self._column, []); } else { data.types = data.types.slice(0, 20); var ids = $.map(data.types, function(elmt) { return elmt.id; }); if (ids.length == 0) { dismissBusy(); new ReconDialog(self._column, []); } else { var query = [{ "id|=" : ids, "id" : null, "/freebase/type_profile/kind" : [] }]; $.getJSON( "http://api.freebase.com/api/service/mqlread?" + $.param({ "query" : JSON.stringify({ "query" : query }) }) + "&callback=?", null, function(o) { dismissBusy(); var kindMap = {}; $.each(o.result, function() { var m = kindMap[this.id] = {}; $.each(this["/freebase/type_profile/kind"], function() { m[this] = true; }); }); new ReconDialog(self._column, $.map(data.types, function(type) { if (type.id in kindMap) { var m = kindMap[type.id]; if (!("Role" in m) && !("Annotation" in m)) { return type; } } return null; })); }, "jsonp" ); } } }, "json" ); }; DataTableColumnHeaderUI.prototype._doReconDiscardJudgments = function() { Gridworks.postProcess( "recon-discard-judgments", { columnName: this._column.name }, null, { cellsChanged: true, columnStatsChanged: true } ); }; DataTableColumnHeaderUI.prototype._doReconMatchBestCandidates = function() { Gridworks.postProcess( "recon-match-best-candidates", { columnName: this._column.name }, null, { cellsChanged: true, columnStatsChanged: true } ); }; DataTableColumnHeaderUI.prototype._doReconMarkNewTopics = function(shareNewTopics) { Gridworks.postProcess( "recon-mark-new-topics", { columnName: this._column.name, shareNewTopics: shareNewTopics }, null, { cellsChanged: true, columnStatsChanged: true } ); }; DataTableColumnHeaderUI.prototype._doSearchToMatch = function() { var self = this; var frame = DialogSystem.createDialog(); frame.width("400px"); var header = $('
').addClass("dialog-header").text("Search for Match").appendTo(frame); var body = $('
').addClass("dialog-body").appendTo(frame); var footer = $('
').addClass("dialog-footer").appendTo(frame); $('

').text("Search Freebase for a topic to match all filtered cells:").appendTo(body); var input = $('').appendTo($('

').appendTo(body)); input.suggest({}).bind("fb-select", function(e, data) { Gridworks.postProcess( "recon-match-specific-topic-to-cells", { columnName: self._column.name, topicID: data.id, topicGUID: data.guid, topicName: data.name, types: $.map(data.type, function(elmt) { return elmt.id; }).join(",") }, null, { cellsChanged: true, columnStatsChanged: true } ); DialogSystem.dismissUntil(level - 1); }); $('').text("Cancel").click(function() { DialogSystem.dismissUntil(level - 1); }).appendTo(footer); var level = DialogSystem.showDialog(frame); input.focus().data("suggest").textchange(); }; DataTableColumnHeaderUI.prototype._doAddColumn = function(initialExpression) { var self = this; var frame = DialogSystem.createDialog(); frame.width("700px"); var header = $('
').addClass("dialog-header").text("Add Column Based on Column " + this._column.name).appendTo(frame); var body = $('
').addClass("dialog-body").appendTo(frame); var footer = $('
').addClass("dialog-footer").appendTo(frame); body.html( '
' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
' + 'New column name' + '' + '' + '
' + 'On error' + '' + ' set to blank ' + ' store error ' + ' keep original' + '
' + ExpressionPreviewDialog.generateWidgetHtml() + '
' ); var bodyElmts = DOM.bind(body); footer.html( '' + '' ); var footerElmts = DOM.bind(footer); var level = DialogSystem.showDialog(frame); var dismiss = function() { DialogSystem.dismissUntil(level - 1); }; footerElmts.okButton.click(function() { var columnName = $.trim(bodyElmts.columnNameInput[0].value); if (columnName.length == 0) { alert("You must enter a column name."); return; } Gridworks.postProcess( "add-column", { baseColumnName: self._column.name, expression: previewWidget.getExpression(true), newColumnName: columnName, columnInsertIndex: self._columnIndex + 1, onError: $('input[name="create-column-dialog-onerror-choice"]:checked')[0].value }, null, { modelsChanged: true } ); dismiss(); }) footerElmts.cancelButton.click(dismiss); var o = DataTableView.sampleVisibleRows(this._column); var previewWidget = new ExpressionPreviewDialog.Widget( bodyElmts, this._column.cellIndex, o.rowIndices, o.values, "value" ); }; DataTableColumnHeaderUI.prototype._doAddColumnFromFreebase = function() { if ("reconConfig" in this._column && "type" in this._column.reconConfig) { var o = DataTableView.sampleVisibleRows(this._column); var self = this; new ExtendDataPreviewDialog( this._column, this._columnIndex, o.rowIndices, function(extension) { Gridworks.postProcess( "extend-data", { baseColumnName: self._column.name, columnInsertIndex: self._columnIndex + 1 }, { extension: JSON.stringify(extension) }, { rowsChanged: true, modelsChanged: true } ); } ); } else { alert("This column has not been reconciled yet."); } }; DataTableColumnHeaderUI.prototype._doRemoveColumn = function() { Gridworks.postProcess( "remove-column", { columnName: this._column.name }, null, { modelsChanged: true } ); }; DataTableColumnHeaderUI.prototype._doJoinMultiValueCells = function() { var separator = window.prompt("Enter separator to use between values", ", "); if (separator != null) { Gridworks.postProcess( "join-multi-value-cells", { columnName: this._column.name, keyColumnName: theProject.columnModel.keyColumnName, separator: separator }, null, { rowsChanged: true } ); } }; DataTableColumnHeaderUI.prototype._doSplitMultiValueCells = function() { var separator = window.prompt("What separator currently separates the values?", ","); if (separator != null) { Gridworks.postProcess( "split-multi-value-cells", { columnName: this._column.name, keyColumnName: theProject.columnModel.keyColumnName, separator: separator, mode: "plain" }, null, { rowsChanged: true } ); } };