From 425140261f1e6778cfcbee1aa3617d35595a37f1 Mon Sep 17 00:00:00 2001 From: David Huynh Date: Fri, 12 Feb 2010 20:29:56 +0000 Subject: [PATCH] We're starting to be able to save protographs. git-svn-id: http://google-refine.googlecode.com/svn/trunk@91 7d457c2a-affb-35e4-300a-418c747d4874 --- .../gridworks/protograph/CellTopicNode.java | 15 +- .../protograph/FreebaseProperty.java | 9 +- .../gridworks/protograph/FreebaseTopic.java | 7 +- .../protograph/FreebaseTopicNode.java | 13 +- .../gridworks/protograph/FreebaseType.java | 5 +- .../gridworks/protograph/Protograph.java | 6 +- src/main/webapp/project.html | 2 +- src/main/webapp/scripts/project/menu-bar.js | 12 +- .../project/schema-alignment-ui-link.js | 109 +++ .../project/schema-alignment-ui-node.js | 634 ++++++++++++++++ .../scripts/project/schema-alignment.js | 687 +----------------- 11 files changed, 784 insertions(+), 715 deletions(-) create mode 100644 src/main/webapp/scripts/project/schema-alignment-ui-link.js create mode 100644 src/main/webapp/scripts/project/schema-alignment-ui-node.js diff --git a/src/main/java/com/metaweb/gridworks/protograph/CellTopicNode.java b/src/main/java/com/metaweb/gridworks/protograph/CellTopicNode.java index ab7869a76..747e21f50 100644 --- a/src/main/java/com/metaweb/gridworks/protograph/CellTopicNode.java +++ b/src/main/java/com/metaweb/gridworks/protograph/CellTopicNode.java @@ -31,14 +31,17 @@ public class CellTopicNode extends CellNode implements NodeWithLinks { writer.object(); writer.key("nodeType"); writer.value("cell-as-topic"); writer.key("columnName"); writer.value(columnName); - writer.key("type"); type.write(writer, options); writer.key("createUnlessRecon"); writer.value(createForNoReconMatch); - - writer.key("links"); writer.array(); - for (Link link : links) { - link.write(writer, options); + if (createForNoReconMatch && type != null) { + writer.key("type"); type.write(writer, options); + } + if (links != null) { + writer.key("links"); writer.array(); + for (Link link : links) { + link.write(writer, options); + } + writer.endArray(); } - writer.endArray(); writer.endObject(); } diff --git a/src/main/java/com/metaweb/gridworks/protograph/FreebaseProperty.java b/src/main/java/com/metaweb/gridworks/protograph/FreebaseProperty.java index 6e50544dc..59691a141 100644 --- a/src/main/java/com/metaweb/gridworks/protograph/FreebaseProperty.java +++ b/src/main/java/com/metaweb/gridworks/protograph/FreebaseProperty.java @@ -3,14 +3,9 @@ package com.metaweb.gridworks.protograph; public class FreebaseProperty extends FreebaseTopic { private static final long serialVersionUID = 7909539492956342421L; - final protected FreebaseType _expectedType; + //final protected FreebaseType _expectedType; - public FreebaseProperty(String id, String name, FreebaseType expectedType) { + public FreebaseProperty(String id, String name) { super(id, name); - _expectedType = expectedType; - } - - public FreebaseType getExpectedType() { - return _expectedType; } } diff --git a/src/main/java/com/metaweb/gridworks/protograph/FreebaseTopic.java b/src/main/java/com/metaweb/gridworks/protograph/FreebaseTopic.java index 4b510f155..9a01eaacb 100644 --- a/src/main/java/com/metaweb/gridworks/protograph/FreebaseTopic.java +++ b/src/main/java/com/metaweb/gridworks/protograph/FreebaseTopic.java @@ -21,8 +21,11 @@ public class FreebaseTopic implements Serializable, Jsonizable { public void write(JSONWriter writer, Properties options) throws JSONException { - // TODO Auto-generated method stub - + + writer.object(); + writer.key("id"); writer.value(id); + writer.key("name"); writer.value(name); + writer.endObject(); } } diff --git a/src/main/java/com/metaweb/gridworks/protograph/FreebaseTopicNode.java b/src/main/java/com/metaweb/gridworks/protograph/FreebaseTopicNode.java index 68cd4c605..c54c98dc9 100644 --- a/src/main/java/com/metaweb/gridworks/protograph/FreebaseTopicNode.java +++ b/src/main/java/com/metaweb/gridworks/protograph/FreebaseTopicNode.java @@ -23,13 +23,14 @@ public class FreebaseTopicNode implements Node, NodeWithLinks { writer.object(); writer.key("nodeType"); writer.value("topic"); writer.key("topic"); topic.write(writer, options); - - writer.key("links"); writer.array(); - for (Link link : links) { - link.write(writer, options); + if (links != null) { + writer.key("links"); writer.array(); + for (Link link : links) { + link.write(writer, options); + } + writer.endArray(); } - writer.endArray(); - + writer.endObject(); } diff --git a/src/main/java/com/metaweb/gridworks/protograph/FreebaseType.java b/src/main/java/com/metaweb/gridworks/protograph/FreebaseType.java index 89329e8ca..d3db01012 100644 --- a/src/main/java/com/metaweb/gridworks/protograph/FreebaseType.java +++ b/src/main/java/com/metaweb/gridworks/protograph/FreebaseType.java @@ -3,11 +3,8 @@ package com.metaweb.gridworks.protograph; public class FreebaseType extends FreebaseTopic { private static final long serialVersionUID = -3070300264980791404L; - final public boolean compoundValueType; - - public FreebaseType(String id, String name, boolean compoundValueType) { + public FreebaseType(String id, String name) { super(id, name); - this.compoundValueType = compoundValueType; } } diff --git a/src/main/java/com/metaweb/gridworks/protograph/Protograph.java b/src/main/java/com/metaweb/gridworks/protograph/Protograph.java index 70015534a..7b8cef3e9 100644 --- a/src/main/java/com/metaweb/gridworks/protograph/Protograph.java +++ b/src/main/java/com/metaweb/gridworks/protograph/Protograph.java @@ -95,16 +95,14 @@ public class Protograph implements Serializable, Jsonizable { static protected FreebaseProperty reconstructProperty(JSONObject o) throws JSONException { return new FreebaseProperty( o.getString("id"), - o.getString("name"), - reconstructType(o.getJSONObject("expected")) + o.getString("name") ); } static protected FreebaseType reconstructType(JSONObject o) throws JSONException { return new FreebaseType( o.getString("id"), - o.getString("name"), - o.getBoolean("cvt") + o.getString("name") ); } diff --git a/src/main/webapp/project.html b/src/main/webapp/project.html index 4d40f8cde..5fd3b6c51 100644 --- a/src/main/webapp/project.html +++ b/src/main/webapp/project.html @@ -1,2 +1,2 @@ Gridlock -
starting up ...
\ No newline at end of file +
starting up ...
\ No newline at end of file diff --git a/src/main/webapp/scripts/project/menu-bar.js b/src/main/webapp/scripts/project/menu-bar.js index 1b6375994..39de3aac1 100644 --- a/src/main/webapp/scripts/project/menu-bar.js +++ b/src/main/webapp/scripts/project/menu-bar.js @@ -137,17 +137,7 @@ MenuBar.prototype._doExportRows = function() { MenuBar.prototype._doAutoSchemaAlignment = function() { //SchemaAlignment.autoAlign(); - var protograph = theProject.protograph != null ? theProject.protograph : { - rootNodes: [ - { - nodeType: "cell-as-topic", - links: [ - ] - } - ] - }; - - new SchemaAlignmentDialog(protograph, function(newProtograph) { + new SchemaAlignmentDialog(theProject.protograph, function(newProtograph) { }); }; diff --git a/src/main/webapp/scripts/project/schema-alignment-ui-link.js b/src/main/webapp/scripts/project/schema-alignment-ui-link.js new file mode 100644 index 000000000..d6e2131e1 --- /dev/null +++ b/src/main/webapp/scripts/project/schema-alignment-ui-link.js @@ -0,0 +1,109 @@ +SchemaAlignmentDialog.UILink = function(link, table, expanded) { + this._link = link; + this._expanded = expanded; + + this._tr = table.insertRow(table.rows.length); + this._tdMain = this._tr.insertCell(0); + this._tdToggle = this._tr.insertCell(1); + this._tdDetails = this._tr.insertCell(2); + + $(this._tdMain).addClass("schema-alignment-link-main").attr("width", "250").addClass("padded"); + $(this._tdToggle).addClass("schema-alignment-link-toggle").attr("width", "1%").addClass("padded"); + $(this._tdDetails).addClass("schema-alignment-link-details").attr("width", "90%"); + + this._collapsedDetailDiv = $('
').appendTo(this._tdDetails).addClass("padded").html("..."); + this._expandedDetailDiv = $('
').appendTo(this._tdDetails).addClass("schema-alignment-detail-container"); + var self = this; + var show = function() { + if (self._expanded) { + self._collapsedDetailDiv.hide(); + self._expandedDetailDiv.show(); + } else { + self._collapsedDetailDiv.show(); + self._expandedDetailDiv.hide(); + } + }; + show(); + + $(this._tdToggle).html(" "); + $('') + .attr("src", this._expanded ? "images/expanded.png" : "images/collapsed.png") + .appendTo(this._tdToggle) + .click(function() { + self._expanded = !self._expanded; + + $(this).attr("src", self._expanded ? "images/expanded.png" : "images/collapsed.png"); + + show(); + }); + + this._renderMain(); + this._renderDetails(); +}; + +SchemaAlignmentDialog.UILink.prototype._renderMain = function() { + $(this._tdMain).empty() + + var label = this._link.property != null ? this._link.property.id : "property?"; + + var self = this; + + var a = $('') + .addClass("schema-alignment-link-tag") + .html(label) + .appendTo(this._tdMain) + .click(function(evt) { + self._showPropertySuggestPopup(this); + }); + + $('').attr("src", "images/arrow-start.png").prependTo(a); + $('').attr("src", "images/arrow-end.png").appendTo(a); +}; + +SchemaAlignmentDialog.UILink.prototype._renderDetails = function() { + var tableDetails = $('
').addClass("schema-alignment-table-layout").appendTo(this._expandedDetailDiv)[0]; + this._targetUI = new SchemaAlignmentDialog.UINode(this._link.target, tableDetails, true); +}; + +SchemaAlignmentDialog.UILink.prototype._showPropertySuggestPopup = function(elmt) { + self = this; + + var fakeMenu = MenuSystem.createMenu() + .width(300) + .height(100) + .css("background", "none") + .css("border", "none"); + + var input = $('').appendTo(fakeMenu); + + var level = MenuSystem.showMenu(fakeMenu, function(){}); + MenuSystem.positionMenuAboveBelow(fakeMenu, $(elmt)); + + input.suggest({ type : '/type/property' }).bind("fb-select", function(e, data) { + self._link.property = { + id: data.id, + name: data.name + }; + + window.setTimeout(function() { + MenuSystem.dismissAll(); + self._renderMain(); + }, 100); + }); + input[0].focus(); +}; + +SchemaAlignmentDialog.UILink.prototype.getJSON = function() { + if ("property" in this._link && this._link.property != null && + "target" in this._link && this._link.target != null) { + + var targetJSON = this._targetUI.getJSON(); + if (targetJSON != null) { + return { + property: cloneDeep(this._link.property), + target: targetJSON + }; + } + } + return null; +}; diff --git a/src/main/webapp/scripts/project/schema-alignment-ui-node.js b/src/main/webapp/scripts/project/schema-alignment-ui-node.js new file mode 100644 index 000000000..e23c29307 --- /dev/null +++ b/src/main/webapp/scripts/project/schema-alignment-ui-node.js @@ -0,0 +1,634 @@ +SchemaAlignmentDialog.UINode = function(node, table, options) { + this._node = node; + this._options = options; + + this._linkUIs = []; + this._detailsRendered = false; + + this._tr = table.insertRow(table.rows.length); + this._tdMain = this._tr.insertCell(0); + this._tdToggle = this._tr.insertCell(1); + this._tdDetails = this._tr.insertCell(2); + + $(this._tdMain).addClass("schema-alignment-node-main").attr("width", "250").addClass("padded"); + $(this._tdToggle).addClass("schema-alignment-node-toggle").attr("width", "1%").addClass("padded").hide(); + $(this._tdDetails).addClass("schema-alignment-node-details").attr("width", "90%").hide(); + + this._renderMain(); + + this._expanded = options.expanded; + if (this._isExpandable()) { + this._showExpandable(); + } +}; + +SchemaAlignmentDialog.UINode.prototype._isExpandable = function() { + return this._node.nodeType == "cell-as-topic"; +}; + +SchemaAlignmentDialog.UINode.prototype._renderMain = function() { + $(this._tdMain).empty(); + + var self = this; + var a = $('') + .addClass("schema-alignment-node-tag") + .appendTo(this._tdMain) + .click(function(evt) { + self._showNodeConfigDialog(); + }); + + if (this._node.nodeType == "cell-as-topic" || + this._node.nodeType == "cell-as-value" || + this._node.nodeType == "cell-as-key") { + + if ("columnName" in this._node) { + a.html(" cell"); + + $('') + .text(this._node.columnName) + .addClass("schema-alignment-node-column") + .prependTo(a); + } else { + a.html(this._options.mustBeCellTopic ? "Which column?" : "Configure..."); + } + } else if (this._node.nodeType == "topic") { + if ("topic" in this._node) { + a.html(this._node.topic.name); + } else if ("id" in this._node) { + a.html(this._node.topic.id); + } else { + a.html("Which topic?"); + } + } else if (this._node.nodeType == "value") { + if ("value" in this._node) { + a.html(this._node.value); + } else { + a.html("What value?"); + } + } else if (this._node.nodeType == "anonymous") { + a.html("(anonymous)"); + } + + $('').attr("src", "images/down-arrow.png").appendTo(a); +}; + +SchemaAlignmentDialog.UINode.prototype._showExpandable = function() { + $(this._tdToggle).show(); + $(this._tdDetails).show(); + + if (this._detailsRendered) { + return; + } + this._detailsRendered = true; + + this._collapsedDetailDiv = $('
').appendTo(this._tdDetails).addClass("padded").html("..."); + this._expandedDetailDiv = $('
').appendTo(this._tdDetails).addClass("schema-alignment-detail-container"); + + this._renderDetails(); + + var self = this; + var show = function() { + if (self._expanded) { + self._collapsedDetailDiv.hide(); + self._expandedDetailDiv.show(); + } else { + self._collapsedDetailDiv.show(); + self._expandedDetailDiv.hide(); + } + }; + show(); + + $(this._tdToggle).html(" "); + $('') + .attr("src", this._expanded ? "images/expanded.png" : "images/collapsed.png") + .appendTo(this._tdToggle) + .click(function() { + self._expanded = !self._expanded; + + $(this).attr("src", self._expanded ? "images/expanded.png" : "images/collapsed.png"); + + show(); + }); +}; + +SchemaAlignmentDialog.UINode.prototype._hideExpandable = function() { + $(this._tdToggle).hide(); + $(this._tdDetails).hide(); +}; + +SchemaAlignmentDialog.UINode.prototype._renderDetails = function() { + var self = this; + + this._tableLinks = $('
').addClass("schema-alignment-table-layout").appendTo(this._expandedDetailDiv)[0]; + + if ("links" in this._node && this._node.links != null) { + for (var i = 0; i < this._node.links.length; i++) { + this._linkUIs.push(new SchemaAlignmentDialog.UILink(this._node.links[i], this._tableLinks, true)); + } + } + + var divFooter = $('
').addClass("padded").appendTo(this._expandedDetailDiv); + + $('') + .addClass("action") + .text("add property") + .appendTo(divFooter) + .click(function() { + var newLink = { + property: null, + target: { + nodeType: "cell-as-value" + } + }; + self._linkUIs.push(new SchemaAlignmentDialog.UILink( + newLink, + self._tableLinks, + { + expanded: true, + mustBeCellTopic: false + } + )); + }); +}; + +SchemaAlignmentDialog.UINode.prototype._showColumnPopupMenu = function(elmt) { + self = this; + + var menu = []; + + if (!this._options.mustBeCellTopic) { + menu.push({ + label: "Anonymous Node", + click: function() { + self._node.nodeType = "anonymous"; + self._showExpandable(); + self._renderMain(); + } + }); + menu.push({ + label: "Freebase Topic", + click: function() { + self._node.nodeType = "topic"; + self._hideExpandable(); + self._renderMain(); + } + }); + menu.push({ + label: "Value", + click: function() { + self._node.nodeType = "value"; + self._hideExpandable(); + self._renderMain(); + } + }); + menu.push({}); // separator + } + + var columns = theProject.columnModel.columns; + var createColumnMenuItem = function(index) { + menu.push({ + label: columns[index].headerLabel, + click: function() { + self._node.nodeType = "cell-as-topic"; + self._node.columnName = columns[index].headerLabel; + self._showExpandable(); + self._renderMain(); + } + }); + }; + for (var i = 0; i < columns.length; i++) { + createColumnMenuItem(i); + } + + MenuSystem.createAndShowStandardMenu(menu, elmt); +}; + +SchemaAlignmentDialog.UINode.prototype._showNodeConfigDialog = function() { + var self = this; + var frame = DialogSystem.createDialog(); + + frame.width("800px"); + + var header = $('
').addClass("dialog-header").text("Protograph Node").appendTo(frame); + var body = $('
').addClass("dialog-body").appendTo(frame); + var footer = $('
').addClass("dialog-footer").appendTo(frame); + + /*-------------------------------------------------- + * Body + *-------------------------------------------------- + */ + var literalTypeSelectHtml = + '' + + '' + + '' + + '' + + '' + + ''; + + var html = $( + '' + + '' + + '' + + + '' + + '' + + '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
' + + '
' + + ' Generate an anonymous graph node' + + '
' + + '
Assign a type to the node 
' + + '
' + + ' Use one existing Freebase topic' + + '
' + + '
Topic
' + + '
' + + ' Use a literal value' + + '
' + + '
Value
Value type
Language
' + + '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
' + + '
' + + ' Set to Cell in Column' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '' + + '
' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
The cell\'s content is used ...
to specify a Freebase topic, as reconciled
If not reconciled, create new topic named by the cell\'s content, and assign it a type
Type:
as a literal value
Literal type
Language (for text)
as a key in a namespace
Namespace
' + + '
' + + '
' + + '
' + ).appendTo(body); + + var elmts = DOM.bind(html); + + var tableColumns = $('
') + .attr("cellspacing", "5") + .attr("cellpadding", "0") + .appendTo(elmts.divColumns)[0]; + + var makeColumnChoice = function(column, columnIndex) { + var tr = tableColumns.insertRow(tableColumns.rows.length); + + var radio = $('') + .attr("type", "radio") + .attr("value", column.headerLabel) + .attr("name", "schema-align-node-dialog-column") + .appendTo(tr.insertCell(0)) + .click(function() { + elmts.radioNodeTypeCellAs[0].checked = true; + }); + + if ((!("columnName" in self._node) || self._node.columnName == null) && columnIndex == 0) { + radio.attr("checked", "true"); + } else if (column.headerLabel == self._node.columnName) { + radio.attr("checked", "true"); + } + + $('').text(column.headerLabel).appendTo(tr.insertCell(1)); + }; + var columns = theProject.columnModel.columns; + for (var i = 0; i < columns.length; i++) { + makeColumnChoice(columns[i], i); + } + + elmts.anonymousNodeTypeInput + .bind("focus", function() { elmts.radioNodeTypeAnonymous[0].checked = true; }) + .suggest({ type: "/type/type" }); + + elmts.topicNodeTypeInput + .bind("focus", function() { elmts.radioNodeTypeTopic[0].checked = true; }) + .suggest({}); + + elmts.valueNodeTypeValueInput + .bind("focus", function() { elmts.radioNodeTypeValue[0].checked = true; }); + elmts.valueNodeTypeValueTypeSelect + .bind("focus", function() { elmts.radioNodeTypeValue[0].checked = true; }); + elmts.valueNodeTypeLanguageInput + .bind("focus", function() { elmts.radioNodeTypeValue[0].checked = true; }) + .suggest({ type: "/type/lang" }); + + + elmts.radioNodeTypeCellAsTopicCreate + .click(function() { + elmts.radioNodeTypeCellAs[0].checked = true; + elmts.radioNodeTypeCellAsTopic[0].checked = true; + }); + elmts.cellAsTopicNodeTypeInput + .bind("focus", function() { + elmts.radioNodeTypeCellAs[0].checked = true; + elmts.radioNodeTypeCellAsTopic[0].checked = true; + }) + .suggest({ type: "/type/type" }); + + elmts.cellAsValueTypeSelect + .bind("focus", function() { + elmts.radioNodeTypeCellAs[0].checked = true; + elmts.radioNodeTypeCellAsValue[0].checked = true; + }); + elmts.cellAsValueLanguageInput + .bind("focus", function() { + elmts.radioNodeTypeCellAs[0].checked = true; + elmts.radioNodeTypeCellAsValue[0].checked = true; + }) + .suggest({ type: "/type/lang" }); + + elmts.cellAsKeyInput + .bind("focus", function() { + elmts.radioNodeTypeCellAs[0].checked = true; + elmts.radioNodeTypeCellAsKey[0].checked = true; + }) + .suggest({ type: "/type/namespace" }); + + if (this._node.nodeType.match(/^cell-as-/)) { + elmts.radioNodeTypeCellAs[0].checked = true; + if (this._node.nodeType == "cell-as-topic") { + elmts.radioNodeTypeCellAsTopic[0].checked = true; + } else if (this._node.nodeType == "cell-as-value") { + elmts.radioNodeTypeCellAsValue[0].checked = true; + } else if (this._node.nodeType == "cell-as-key") { + elmts.radioNodeTypeCellAsKey[0].checked = true; + } + } else if (this._node.nodeType == "anonymous") { + elmts.radioNodeTypeAnonymous[0].checked = true; + } else if (this._node.nodeType == "topic") { + elmts.radioNodeTypeTopic[0].checked = true; + } else if (this._node.nodeType == "value") { + elmts.radioNodeTypeValue[0].checked = true; + } + + /*-------------------------------------------------- + * Footer + *-------------------------------------------------- + */ + + var getResultJSON = function() { + var node = { + nodeType: $("input[name='schema-align-node-dialog-node-type']:checked")[0].value + }; + if (node.nodeType == "cell-as") { + node.nodeType = $("input[name='schema-align-node-dialog-node-subtype']:checked")[0].value; + node.columnName = $("input[name='schema-align-node-dialog-column']:checked")[0].value; + + if (node.nodeType == "cell-as-topic") { + if (elmts.radioNodeTypeCellAsTopicCreate[0].checked) { + node.createForNoReconMatch = true; + + var t = elmts.cellAsTopicNodeTypeInput.data("data.suggest"); + if (!(t)) { + alert("For creating a new graph node, you need to specify a type for it."); + return null; + } + node.type = { + id: t.id, + name: t.name + }; + } else { + node.createForNoReconMatch = false; + } + } else if (node.nodeType == "cell-as-value") { + node.valueType = elmts.cellAsValueTypeSelect[0].value; + + var l = elmts.cellAsValueLanguageInput[0].data("data.suggest"); + node.lang = (l) ? l.id : "/type/text"; + } else if (node.nodeType == "cell-as-key") { + var t = elmts.cellAsKeyInput.data("data.suggest"); + if (!(t)) { + alert("Please specify the namespace."); + return null; + } + node.namespace = { + id: t.id, + name: t.name + }; + } + } else if (node.nodeType == "anonymous") { + var t = elmts.anonymousNodeTypeInput.data("data.suggest"); + if (!(t)) { + alert("For generating an anonymous graph node, you need to specify a type for it."); + return null; + } + node.type = { + id: t.id, + name: t.name + }; + } else if (node.nodeType == "topic") { + var t = elmts.topicNodeTypeInput.data("data.suggest"); + if (!(t)) { + alert("Please specify which existing Freebase topic to use."); + return null; + } + node.topic = { + id: t.id, + name: t.name + }; + } else if (node.nodeType == "value") { + node.value = $.trim(elmts.valueNodeTypeValueInput[0].value); + if (node.value.length == 0) { + alert("Please specify the value to use."); + return null; + } + node.valueType = elmts.valueNodeTypeValueTypeSelect[0].value; + + var l = elmts.valueNodeTypeLanguageInput[0].data("data.suggest"); + node.lang = (l) ? l.id : "/type/text"; + } + + return node; + }; + + $('').html("  OK  ").click(function() { + var node = getResultJSON(); + if (node != null) { + DialogSystem.dismissUntil(level - 1); + + self._node = node; + if (self._isExpandable()) { + self._showExpandable(); + } else { + self._hideExpandable(); + } + self._renderMain(); + } + }).appendTo(footer); + + $('').text("Cancel").click(function() { + DialogSystem.dismissUntil(level - 1); + }).appendTo(footer); + + var level = DialogSystem.showDialog(frame); +}; + +SchemaAlignmentDialog.UINode.prototype.getJSON = function() { + var result = null; + var getLinks = false; + + if (this._node.nodeType.match(/^cell-as-/)) { + if (!("columnName" in this._node) || this._node.columnName == null) { + return null; + } + + if (this._node.nodeType == "cell-as-topic") { + result = { + nodeType: this._node.nodeType, + columnName: this._node.columnName, + type: "type" in this._node ? cloneDeep(this._node.type) : { "id" : "/common/topic", "name" : "Topic", "cvt" : false }, + createForNoReconMatch: "createForNoReconMatch" in this._node ? this._node.createForNoReconMatch : true + }; + getLinks = true; + } else if (this._node.nodeType == "cell-as-value") { + result = { + nodeType: this._node.nodeType, + columnName: this._node.columnName, + valueType: "valueType" in this._node ? this._node.valueType : "/type/text", + lang: "lang" in this._node ? this._node.lang : "/lang/en" + }; + } else if (this._node.nodeType == "cell-as-key") { + if (!("namespace" in this._node) || this._node.namespace == null) { + return null; + } + result = { + nodeType: this._node.nodeType, + columnName: this._node.columnName, + type: cloneDeep(this._node.namespace) + }; + } + } else if (this._node.nodeType == "topic") { + if (!("topic" in this._node) || this._node.topic == null) { + return null; + } + result = { + nodeType: this._node.nodeType, + topic: cloneDeep(this._node.topic) + }; + getLinks = true; + } else if (this._node.nodeType == "value") { + if (!("value" in this._node) || this._node.value == null) { + return null; + } + result = { + nodeType: this._node.nodeType, + value: this._node.value, + valueType: "valueType" in this._node ? this._node.valueType : "/type/text", + lang: "lang" in this._node ? this._node.lang : "/lang/en" + }; + } else if (this._node.nodeType == "anonymous") { + if (!("type" in this._node) || this._node.type == null) { + return null; + } + result = { + nodeType: this._node.nodeType, + type: cloneDeep(this._node.type) + }; + getLinks = true; + } + + if (result == null) { + return null; + } + if (getLinks) { + var links = []; + for (var i = 0; i < this._linkUIs.length; i++) { + var link = this._linkUIs[i].getJSON(); + if (link != null) { + links.push(link); + } + } + result.links = links; + } + + return result; +}; + diff --git a/src/main/webapp/scripts/project/schema-alignment.js b/src/main/webapp/scripts/project/schema-alignment.js index c0d3d8fef..8229936ad 100644 --- a/src/main/webapp/scripts/project/schema-alignment.js +++ b/src/main/webapp/scripts/project/schema-alignment.js @@ -92,10 +92,18 @@ SchemaAlignment._cleanName = function(s) { function SchemaAlignmentDialog(protograph, onDone) { this._onDone = onDone; - this._originalProtograph = protograph; + this._originalProtograph = protograph || { rootNodes: [] }; this._protograph = cloneDeep(protograph); // this is what can be munched on - this._nodeUIs = []; + if (this._protograph.rootNodes.length == 0) { + this._protograph.rootNodes.push({ + nodeType: "cell-as-topic", + links: [ + ] + }); + } + + this._nodeUIs = []; this._createDialog(); }; @@ -135,7 +143,8 @@ SchemaAlignmentDialog.prototype._renderFooter = function(footer) { } DialogSystem.dismissUntil(self._level - 1); - self._onDone(prototgraph); + + self._onDone(protograph); }, "json" ); @@ -160,7 +169,7 @@ SchemaAlignmentDialog.prototype._renderBody = function(body) { this._canvas = $('
').addClass("schema-alignment-dialog-canvas").appendTo(body); this._nodeTable = $('
').addClass("schema-alignment-table-layout").appendTo(this._canvas)[0]; - for (var i = 0; i < this._originalProtograph.rootNodes.length; i++) { + for (var i = 0; i < this._protograph.rootNodes.length; i++) { this._nodeUIs.push(new SchemaAlignmentDialog.UINode( this._protograph.rootNodes[i], this._nodeTable, @@ -186,38 +195,6 @@ SchemaAlignmentDialog.prototype.getJSON = function() { }; }; -/*---------------------------------------------------------------------- - * UINode - *---------------------------------------------------------------------- - */ -SchemaAlignmentDialog.UINode = function(node, table, options) { - this._node = node; - this._options = options; - - this._linkUIs = []; - this._detailsRendered = false; - - this._tr = table.insertRow(table.rows.length); - this._tdMain = this._tr.insertCell(0); - this._tdToggle = this._tr.insertCell(1); - this._tdDetails = this._tr.insertCell(2); - - $(this._tdMain).addClass("schema-alignment-node-main").attr("width", "250").addClass("padded"); - $(this._tdToggle).addClass("schema-alignment-node-toggle").attr("width", "1%").addClass("padded").hide(); - $(this._tdDetails).addClass("schema-alignment-node-details").attr("width", "90%").hide(); - - this._renderMain(); - - this._expanded = options.expanded; - if (this._isExpandable()) { - this._showExpandable(); - } -}; - -SchemaAlignmentDialog.UINode.prototype._isExpandable = function() { - return this._node.nodeType == "cell-as-topic"; -}; - SchemaAlignmentDialog._findColumn = function(cellIndex) { var columns = theProject.columnModel.columns; for (var i = 0; i < columns.length; i++) { @@ -228,641 +205,3 @@ SchemaAlignmentDialog._findColumn = function(cellIndex) { } return null; }; - -SchemaAlignmentDialog.UINode.prototype._renderMain = function() { - $(this._tdMain).empty(); - - var self = this; - var a = $('') - .addClass("schema-alignment-node-tag") - .appendTo(this._tdMain) - .click(function(evt) { - if (self._options.mustBeCellTopic) { - self._showTagMenu(this); - } else { - self._showTagDialog(); - } - }); - - if (this._node.nodeType == "cell-as-topic" || - this._node.nodeType == "cell-as-value" || - this._node.nodeType == "cell-as-key") { - - if ("cellIndex" in this._node) { - a.html(" cell"); - - $('') - .text(SchemaAlignmentDialog._findColumn(this._node.cellIndex).headerLabel) - .addClass("schema-alignment-node-column") - .prependTo(a); - } else { - a.html(this._options.mustBeCellTopic ? "Which column?" : "Configure..."); - } - } else if (this._node.nodeType == "topic") { - if ("topic" in this._node) { - a.html(this._node.topic.name); - } else if ("id" in this._node) { - a.html(this._node.topic.id); - } else { - a.html("Which topic?"); - } - } else if (this._node.nodeType == "value") { - if ("value" in this._node) { - a.html(this._node.value); - } else { - a.html("What value?"); - } - } else if (this._node.nodeType == "anonymous") { - a.html("(anonymous)"); - } - - $('').attr("src", "images/down-arrow.png").appendTo(a); -}; - -SchemaAlignmentDialog.UINode.prototype._showExpandable = function() { - $(this._tdToggle).show(); - $(this._tdDetails).show(); - - if (this._detailsRendered) { - return; - } - this._detailsRendered = true; - - this._collapsedDetailDiv = $('
').appendTo(this._tdDetails).addClass("padded").html("..."); - this._expandedDetailDiv = $('
').appendTo(this._tdDetails).addClass("schema-alignment-detail-container"); - - this._renderDetails(); - - var self = this; - var show = function() { - if (self._expanded) { - self._collapsedDetailDiv.hide(); - self._expandedDetailDiv.show(); - } else { - self._collapsedDetailDiv.show(); - self._expandedDetailDiv.hide(); - } - }; - show(); - - $(this._tdToggle).html(" "); - $('') - .attr("src", this._expanded ? "images/expanded.png" : "images/collapsed.png") - .appendTo(this._tdToggle) - .click(function() { - self._expanded = !self._expanded; - - $(this).attr("src", self._expanded ? "images/expanded.png" : "images/collapsed.png"); - - show(); - }); -}; - -SchemaAlignmentDialog.UINode.prototype._hideExpandable = function() { - $(this._tdToggle).hide(); - $(this._tdDetails).hide(); -}; - -SchemaAlignmentDialog.UINode.prototype._renderDetails = function() { - var self = this; - - this._tableLinks = $('
').addClass("schema-alignment-table-layout").appendTo(this._expandedDetailDiv)[0]; - - if ("links" in this._node && this._node.links != null) { - for (var i = 0; i < this._node.links.length; i++) { - this._linkUIs.push(new SchemaAlignmentDialog.UILink(this._node.links[i], this._tableLinks, true)); - } - } - - var divFooter = $('
').addClass("padded").appendTo(this._expandedDetailDiv); - - $('') - .addClass("action") - .text("add property") - .appendTo(divFooter) - .click(function() { - var newLink = { - property: null, - target: { - nodeType: "cell-as-value" - } - }; - self._linkUIs.push(new SchemaAlignmentDialog.UILink( - newLink, - self._tableLinks, - { - expanded: true, - mustBeCellTopic: false - } - )); - }); -}; - -SchemaAlignmentDialog.UINode.prototype._showTagMenu = function(elmt) { - self = this; - - var menu = []; - - if (!this._options.mustBeCellTopic) { - menu.push({ - label: "Anonymous Node", - click: function() { - self._node.nodeType = "anonymous"; - self._showExpandable(); - self._renderMain(); - } - }); - menu.push({ - label: "Freebase Topic", - click: function() { - self._node.nodeType = "topic"; - self._hideExpandable(); - self._renderMain(); - } - }); - menu.push({ - label: "Value", - click: function() { - self._node.nodeType = "value"; - self._hideExpandable(); - self._renderMain(); - } - }); - menu.push({}); // separator - } - - var columns = theProject.columnModel.columns; - var createColumnMenuItem = function(index) { - menu.push({ - label: columns[index].headerLabel, - click: function() { - self._node.nodeType = "cell-as-topic"; - self._node.cellIndex = columns[index].cellIndex; - self._showExpandable(); - self._renderMain(); - } - }); - }; - for (var i = 0; i < columns.length; i++) { - createColumnMenuItem(i); - } - - MenuSystem.createAndShowStandardMenu(menu, elmt); -}; - -SchemaAlignmentDialog.UINode.prototype._showTagDialog = function() { - var self = this; - var frame = DialogSystem.createDialog(); - - frame.width("800px"); - - var header = $('
').addClass("dialog-header").text("Protograph Node").appendTo(frame); - var body = $('
').addClass("dialog-body").appendTo(frame); - var footer = $('
').addClass("dialog-footer").appendTo(frame); - - /*-------------------------------------------------- - * Body - *-------------------------------------------------- - */ - - var html = $( - '' + - '' + - '' + - - '' + - '' + - '
' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
' + - '
' + - ' Generate an anonymous graph node' + - '
' + - '
Assign a type to the node 
' + - '
' + - ' Use one existing Freebase topic' + - '
' + - '
Topic
' + - '
' + - ' Use a literal value' + - '
' + - '
Value
Value type
Language
' + - '
' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
' + - '
' + - ' Set to Cell in Column' + - '
' + - '
' + - '' + - '' + - '' + - '' + - '' + - '
' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
The cell\'s content is used ...
to specify a Freebase topic, as reconciled
If not reconciled, create new topic named by the cell\'s content, and assign it a type
Type:
as a literal value
Literal type
Language (for text)
as a key in a namespace
Namespace
' + - '
' + - '
' + - '
' - ).appendTo(body); - - var elmts = DOM.bind(html); - - var tableColumns = $('
') - .attr("cellspacing", "5") - .attr("cellpadding", "0") - .appendTo(elmts.divColumns)[0]; - - var makeColumnChoice = function(column, columnIndex) { - var tr = tableColumns.insertRow(tableColumns.rows.length); - - var radio = $('') - .attr("type", "radio") - .attr("value", column.cellIndex) - .attr("name", "schema-align-node-dialog-column") - .appendTo(tr.insertCell(0)) - .click(function() { - elmts.radioNodeTypeCellAs[0].checked = true; - }); - - if ((!("cellIndex" in self._node) || self._node.cellIndex == null) && columnIndex == 0) { - radio.attr("checked", "true"); - } else if (column.cellIndex == self._node.cellIndex) { - radio.attr("checked", "true"); - } - - $('').text(column.headerLabel).appendTo(tr.insertCell(1)); - }; - var columns = theProject.columnModel.columns; - for (var i = 0; i < columns.length; i++) { - makeColumnChoice(columns[i], i); - } - - elmts.anonymousNodeTypeInput - .bind("focus", function() { elmts.radioNodeTypeAnonymous[0].checked = true; }) - .suggest({ type: "/type/type" }); - - elmts.topicNodeTypeInput - .bind("focus", function() { elmts.radioNodeTypeTopic[0].checked = true; }) - .suggest({}); - - elmts.valueNodeTypeValueInput - .bind("focus", function() { elmts.radioNodeTypeValue[0].checked = true; }) - elmts.valueNodeTypeValueTypeInput - .bind("focus", function() { elmts.radioNodeTypeValue[0].checked = true; }) - elmts.valueNodeTypeLanguageInput - .bind("focus", function() { elmts.radioNodeTypeValue[0].checked = true; }) - - elmts.radioNodeTypeCellAsTopicCreate - .click(function() { - elmts.radioNodeTypeCellAs[0].checked = true; - elmts.radioNodeTypeCellAsTopic[0].checked = true; - }); - elmts.cellAsTopicNodeTypeInput - .bind("focus", function() { - elmts.radioNodeTypeCellAs[0].checked = true; - elmts.radioNodeTypeCellAsTopic[0].checked = true; - }) - .suggest({ type: "/type/type" }); - - elmts.cellAsValueTypeInput - .bind("focus", function() { - elmts.radioNodeTypeCellAs[0].checked = true; - elmts.radioNodeTypeCellAsValue[0].checked = true; - }) - elmts.cellAsValueLanguageInput - .bind("focus", function() { - elmts.radioNodeTypeCellAs[0].checked = true; - elmts.radioNodeTypeCellAsValue[0].checked = true; - }) - - elmts.cellAsKeyInput - .bind("focus", function() { - elmts.radioNodeTypeCellAs[0].checked = true; - elmts.radioNodeTypeCellAsKey[0].checked = true; - }) - .suggest({ type: "/type/namespace" }); - - if (this._node.nodeType.match(/^cell-as-/)) { - elmts.radioNodeTypeCellAs[0].checked = true; - if (this._node.nodeType == "cell-as-topic") { - elmts.radioNodeTypeCellAsTopic[0].checked = true; - } else if (this._node.nodeType == "cell-as-value") { - elmts.radioNodeTypeCellAsValue[0].checked = true; - } else if (this._node.nodeType == "cell-as-key") { - elmts.radioNodeTypeCellAsKey[0].checked = true; - } - } else if (this._node.nodeType == "anonymous") { - elmts.radioNodeTypeAnonymous[0].checked = true; - } else if (this._node.nodeType == "topic") { - elmts.radioNodeTypeTopic[0].checked = true; - } else if (this._node.nodeType == "value") { - elmts.radioNodeTypeValue[0].checked = true; - } - - /*-------------------------------------------------- - * Footer - *-------------------------------------------------- - */ - - var getResultJSON = function() { - }; - - $('').html("  OK  ").click(function() { - DialogSystem.dismissUntil(level - 1); - self._node = getResultJSON(); - if (self._isExpandable()) { - self._showExpandable(); - } else { - hide._showExpandable(); - } - self._renderMain(); - }).appendTo(footer); - - $('').text("Cancel").click(function() { - DialogSystem.dismissUntil(level - 1); - }).appendTo(footer); - - var level = DialogSystem.showDialog(frame); -}; - -SchemaAlignmentDialog.UINode.prototype.getJSON = function() { - var result = null; - var getLinks = false; - - if (this._node.nodeType.match(/^cell-as-/)) { - if (!("columnName" in this._node) || this._node.columnName == null) { - return null; - } - - if (this._node.nodeType == "cell-as-topic") { - result = { - nodeType: this._node.nodeType, - columnName: this._node.columnName, - type: "type" in this._node ? cloneNode(this._node.type) : { "id" : "/common/topic", "name" : "Topic", "cvt" : false }, - createForNoReconMatch: "createForNoReconMatch" in this._node ? this._node.createForNoReconMatch : true - }; - getLinks = true; - } else if (this._node.nodeType == "cell-as-value") { - result = { - nodeType: this._node.nodeType, - columnName: this._node.columnName, - valueType: "valueType" in this._node ? this._node.valueType : "/type/text", - lang: "lang" in this._node ? this._node.lang : "/lang/en" - }; - } else if (this._node.nodeType == "cell-as-key") { - if (!("namespace" in this._node) || this._node.namespace == null) { - return null; - } - result = { - nodeType: this._node.nodeType, - columnName: this._node.columnName, - type: cloneNode(this._node.namespace) - }; - } - } else if (this._node.nodeType == "topic") { - if (!("topic" in this._node) || this._node.topic == null) { - return null; - } - result = { - nodeType: this._node.nodeType, - topic: cloneNode(this._node.topic) - }; - getLinks = true; - } else if (this._node.nodeType == "value") { - if (!("value" in this._node) || this._node.value == null) { - return null; - } - result = { - nodeType: this._node.nodeType, - value: this._node.value, - valueType: "valueType" in this._node ? this._node.valueType : "/type/text", - lang: "lang" in this._node ? this._node.lang : "/lang/en" - }; - } else if (this._node.nodeType == "anonymous") { - if (!("type" in this._node) || this._node.type == null) { - return null; - } - result = { - nodeType: this._node.nodeType, - type: cloneNode(this._node.type) - }; - getLinks = true; - } - - if (result == null) { - return null; - } - if (getLinks) { - var links = []; - for (var i = 0; i < this._linkUIs.length; i++) { - var link = this._linkUIs[i].getJSON(); - if (link != null) { - links.push(link); - } - } - result.links = links; - } - - return result; -}; - -/*---------------------------------------------------------------------- - * UILink - *---------------------------------------------------------------------- - */ -SchemaAlignmentDialog.UILink = function(link, table, expanded) { - this._link = link; - this._expanded = expanded; - - this._tr = table.insertRow(table.rows.length); - this._tdMain = this._tr.insertCell(0); - this._tdToggle = this._tr.insertCell(1); - this._tdDetails = this._tr.insertCell(2); - - $(this._tdMain).addClass("schema-alignment-link-main").attr("width", "250").addClass("padded"); - $(this._tdToggle).addClass("schema-alignment-link-toggle").attr("width", "1%").addClass("padded"); - $(this._tdDetails).addClass("schema-alignment-link-details").attr("width", "90%"); - - this._collapsedDetailDiv = $('
').appendTo(this._tdDetails).addClass("padded").html("..."); - this._expandedDetailDiv = $('
').appendTo(this._tdDetails).addClass("schema-alignment-detail-container"); - var self = this; - var show = function() { - if (self._expanded) { - self._collapsedDetailDiv.hide(); - self._expandedDetailDiv.show(); - } else { - self._collapsedDetailDiv.show(); - self._expandedDetailDiv.hide(); - } - }; - show(); - - $(this._tdToggle).html(" "); - $('') - .attr("src", this._expanded ? "images/expanded.png" : "images/collapsed.png") - .appendTo(this._tdToggle) - .click(function() { - self._expanded = !self._expanded; - - $(this).attr("src", self._expanded ? "images/expanded.png" : "images/collapsed.png"); - - show(); - }); - - this._renderMain(); - this._renderDetails(); -}; - -SchemaAlignmentDialog.UILink.prototype._renderMain = function() { - $(this._tdMain).empty() - - var label = this._link.property != null ? this._link.property.id : "property?"; - - var self = this; - - var a = $('') - .addClass("schema-alignment-link-tag") - .html(label) - .appendTo(this._tdMain) - .click(function(evt) { - self._showTagSuggest(this); - }); - - $('').attr("src", "images/arrow-start.png").prependTo(a); - $('').attr("src", "images/arrow-end.png").appendTo(a); -}; - -SchemaAlignmentDialog.UILink.prototype._renderDetails = function() { - var tableDetails = $('
').addClass("schema-alignment-table-layout").appendTo(this._expandedDetailDiv)[0]; - this._targetUI = new SchemaAlignmentDialog.UINode(this._link.target, tableDetails, true); -}; - -SchemaAlignmentDialog.UILink.prototype._showTagSuggest = function(elmt) { - self = this; - - var fakeMenu = MenuSystem.createMenu() - .width(300) - .height(100) - .css("background", "none") - .css("border", "none"); - - var input = $('').appendTo(fakeMenu); - - var level = MenuSystem.showMenu(fakeMenu, function(){}); - MenuSystem.positionMenuAboveBelow(fakeMenu, $(elmt)); - - input.suggest({ type : '/type/property' }).bind("fb-select", function(e, data) { - self._link.property = { - id: data.id, - name: data.name - }; - - window.setTimeout(function() { - MenuSystem.dismissAll(); - self._renderMain(); - }, 100); - }); - input[0].focus(); -}; - -SchemaAlignmentDialog.UILink.prototype.getJSON = function() { - if ("property" in this._link && this._link.property != null && - "target" in this._link && this._link.target != null) { - - var targetJSON = this._targetUI.getJSON(); - if (targetJSON != null) { - return { - property: cloneNode(this._link.property), - target: targetJSON - }; - } - } - return null; -};