From e38aeb7ba5edfa30c9bf0338d97be6404d05d320 Mon Sep 17 00:00:00 2001 From: Antonin Delpeuch Date: Thu, 31 Aug 2017 09:11:00 +0100 Subject: [PATCH] JSON serialization of schema to model --- .../wikidata/module/MOD-INF/controller.js | 5 + .../dialogs/schema-alignment-dialog.js | 167 +++++++++++++----- .../dialogs/schema-alignment-dialog.less | 24 ++- .../commands/SaveWikibaseSchemaCommand.java | 46 +++++ 4 files changed, 196 insertions(+), 46 deletions(-) create mode 100644 extensions/wikidata/src/org/openrefine/wikidata/commands/SaveWikibaseSchemaCommand.java diff --git a/extensions/wikidata/module/MOD-INF/controller.js b/extensions/wikidata/module/MOD-INF/controller.js index 8288b1fd6..4ced8750f 100644 --- a/extensions/wikidata/module/MOD-INF/controller.js +++ b/extensions/wikidata/module/MOD-INF/controller.js @@ -45,6 +45,11 @@ function init() { ExporterRegistry.registerExporter("qsv2", new QSV2()); */ + + /* + * Commands + */ + RefineServlet.registerCommand(module, "save-wikibase-schema", new SaveWikibaseSchemaCommand()); /* * Resources diff --git a/extensions/wikidata/module/scripts/dialogs/schema-alignment-dialog.js b/extensions/wikidata/module/scripts/dialogs/schema-alignment-dialog.js index 589357365..48126f715 100644 --- a/extensions/wikidata/module/scripts/dialogs/schema-alignment-dialog.js +++ b/extensions/wikidata/module/scripts/dialogs/schema-alignment-dialog.js @@ -202,17 +202,18 @@ SchemaAlignmentDialog._reset = function(protograph, initial) { SchemaAlignmentDialog._save = function(onDone) { var self = this; - var protograph = this.getJSON(); + var schema = this.getJSON(); + console.log(schema); Refine.postProcess( - "freebase", - "save-protograph", + "wikidata", + "save-wikibase-schema", {}, - { protograph: JSON.stringify(protograph) }, + { schema: JSON.stringify(schema) }, {}, { onDone: function() { - theProject.overlayModels.freebaseProtograph = protograph; + theProject.overlayModels.wikibaseSchema = schema; self._elmts.statusIndicator.hide(); self._hasUnsavedChanges = false; @@ -229,19 +230,35 @@ SchemaAlignmentDialog._createDialog = function() { var elmts = this._elmts = DOM.bind(frame); this._level = DialogSystem.showDialog(frame); + this._wikibasePrefix = "http://www.wikidata.org/entity/"; // hardcoded for now // Init the column area var columns = theProject.columnModel.columns; this._columnArea = $(".schema-alignment-dialog-columns-area"); for (var i = 0; i < columns.length; i++) { - var cell = $("
").addClass('schema-alignment-draggable-column').text(columns[i].name); + var column = columns[i]; + var reconConfig = column.reconConfig; + var cell = $("
").addClass('wbs-draggable-column').text(columns[i].name); + console.log(column.reconStats); + if (reconConfig && reconConfig.identifierSpace === this._wikibasePrefix && column.reconStats) { + cell.addClass('wbs-reconciled-column'); + } else { + cell.addClass('wbs-unreconciled-column'); + } this._columnArea.append(cell); } - $('.schema-alignment-draggable-column').draggable({ + + $('.wbs-reconciled-column').draggable({ helper: "clone", - revert: true, - revertDuration: 200, + cursor: "crosshair", + snap: ".wbs-item-input input, .wbs-target-input input", }); + $('.wbs-unreconciled-column').draggable({ + helper: "clone", + cursor: "crosshair", + snap: ".wbs-target-input input", + }); + var dismiss = function() { DialogSystem.dismissUntil(self._level - 1); @@ -270,29 +287,40 @@ SchemaAlignmentDialog._createDialog = function() { this._canvas = $(".schema-alignment-dialog-canvas"); this._nodeTable = $('
').addClass("schema-alignment-table-layout").appendTo(this._canvas)[0]; - SchemaAlignmentDialog._reconService = ReconciliationManager.ensureDefaultServicePresent(); - console.log(SchemaAlignmentDialog._reconService); + var url = ReconciliationManager.ensureDefaultServicePresent(); + SchemaAlignmentDialog._reconService = ReconciliationManager.getServiceFromUrl(url); }; SchemaAlignmentDialog._addItem = function() { var item = $('
').addClass('wbs-item'); - var input = $('
').addClass('wbs-item-input').appendTo(item); - SchemaAlignmentDialog._initField(input); + var inputContainer = $('
').addClass('wbs-item-input').appendTo(item); + SchemaAlignmentDialog._initField(inputContainer, "item"); var right = $('
').addClass('wbs-right').appendTo(item); $('
').addClass('wbs-statement-group-container').appendTo(right); var toolbar = $('
').addClass('wbs-toolbar').appendTo(right); $('').addClass('wbs-add-statement-group').text('add statement').click(function() { SchemaAlignmentDialog._addStatementGroup(item); }).appendTo(toolbar); + SchemaAlignmentDialog._addStatementGroup(item); $('#schema-alignment-statements-container').append(item); } +SchemaAlignmentDialog._itemToJSON = function (item) { + var lst = new Array(); + item.find('.wbs-statement-group').each(function () { + lst.push(SchemaAlignmentDialog._statementGroupToJSON($(this))); + }); + var inputContainer = item.find(".wbs-item-input").first(); + return {item: SchemaAlignmentDialog._inputContainerToJSON(inputContainer), + values: lst}; +}; + SchemaAlignmentDialog._addStatementGroup = function(item) { var container = item.find('.wbs-statement-group-container').first(); var statementGroup = $('
').addClass('wbs-statement-group'); - var input = $('
').addClass('wbs-prop-input').appendTo(statementGroup); - SchemaAlignmentDialog._initField(input); + var inputContainer = $('
').addClass('wbs-prop-input').appendTo(statementGroup); + SchemaAlignmentDialog._initField(inputContainer, "property"); var right = $('
').addClass('wbs-right').appendTo(statementGroup); $('
').addClass('wbs-statement-container').appendTo(right); var toolbar = $('
').addClass('wbs-toolbar').appendTo(right); @@ -303,15 +331,26 @@ SchemaAlignmentDialog._addStatementGroup = function(item) { SchemaAlignmentDialog._addStatement(statementGroup); } +SchemaAlignmentDialog._statementGroupToJSON = function (statementGroup) { + var lst = new Array(); + statementGroup.find('.wbs-statement').each(function () { + lst.push(SchemaAlignmentDialog._statementToJSON($(this))); + }); + var inputContainer = statementGroup.find(".wbs-prop-input").first(); + return {prop: SchemaAlignmentDialog._inputContainerToJSON(inputContainer), + values: lst}; +}; + + SchemaAlignmentDialog._addStatement = function(statementGroup) { var container = statementGroup.find('.wbs-statement-container').first(); var statement = $('
').addClass('wbs-statement'); var toolbar1 = $('
').addClass('wbs-toolbar').appendTo(statement); - $('').addClass('wbs-remove-statement').text('x').click(function() { + $('').attr('alt', 'remove statement').click(function() { SchemaAlignmentDialog._removeStatement(statement); }).appendTo(toolbar1); - var input = $('
').addClass('wbs-target-input').appendTo(statement); - SchemaAlignmentDialog._initField(input); + var inputContainer = $('
').addClass('wbs-target-input').appendTo(statement); + SchemaAlignmentDialog._initField(inputContainer, "target"); var right = $('
').addClass('wbs-right').appendTo(statement); $('
').addClass('wbs-qualifier-container').appendTo(right); var toolbar2 = $('
').addClass('wbs-toolbar').appendTo(right); @@ -319,25 +358,70 @@ SchemaAlignmentDialog._addStatement = function(statementGroup) { container.append(statement); } -SchemaAlignmentDialog._initField = function(input) { - input.droppable({ - accept: ".schema-alignment-draggable-column" - }).on("drop", function (evt, ui) { - input.text(ui.draggable.text()); - }); - var suggestConfig = $.extend({}, this._reconService.suggest.property); - suggestConfig.key = null; - suggestConfig.query_param_name = "prefix"; +SchemaAlignmentDialog._statementToJSON = function (statement) { + var inputContainer = statement.find(".wbs-target-input").first(); + return SchemaAlignmentDialog._inputContainerToJSON(inputContainer); +}; - input.suggestP(suggestConfig).bind("fb-select", function(evt, data) { - console.log(data); /* - self._addProperty({ - id : data.id, - name: data.name, - }); */ - }); +SchemaAlignmentDialog._initField = function(inputContainer, mode) { + var input = $('').appendTo(inputContainer); + + if (this._reconService !== null) { + var endpoint = null; + if (mode === "item" || mode === "target") { + endpoint = this._reconService.suggest.entity; + } else if (mode == "property") { + endpoint = this._reconService.suggest.property; + } + var suggestConfig = $.extend({}, endpoint); + suggestConfig.key = null; + suggestConfig.query_param_name = "prefix"; + + input.suggestP(suggestConfig).bind("fb-select", function(evt, data) { + inputContainer.data("jsonValue", { + type : "wbitemconstant", + id : data.id, + name: data.name, + }); + }); + } + + // If it isn't a property, make it droppable + if (mode !== "property") { + var acceptClass = ".wbs-draggable-column"; + if (mode === "item") { + acceptClass = ".wbs-reconciled-column"; + } + + inputContainer.droppable({ + accept: acceptClass, + }).on("drop", function (evt, ui) { + input.hide(); + var columnDiv = $('
').appendTo(inputContainer); + var column = ui.draggable.clone().appendTo(columnDiv); + var deleteButton = $(' ').addClass('wbs-delete-column-button').appendTo(column); + deleteButton.attr('alt', 'remove column'); + deleteButton.click(function () { + columnDiv.remove(); + input.show(); + }); + inputContainer.data("jsonValue", { + type : "wbitemvariable", + name: ui.draggable.text(), + }); + return true; + }).on("dropactivate", function(evt, ui) { + input.addClass("wbs-accepting-input"); + }).on("dropdeactivate", function(evt, ui) { + input.removeClass("wbs-accepting-input"); + }); + } } +SchemaAlignmentDialog._inputContainerToJSON = function (inputContainer) { + return inputContainer.data().jsonValue; +}; + SchemaAlignmentDialog._removeStatement = function(statement) { var statementGroup = statement.parents('.wbs-statement-group').first(); statement.remove(); @@ -359,16 +443,13 @@ SchemaAlignmentDialog._addStatement = function() { */ SchemaAlignmentDialog.getJSON = function() { - var rootNodes = []; - for (var i = 0; i < this._nodeUIs.length; i++) { - var node = this._nodeUIs[i].getJSON(); - if (node !== null) { - rootNodes.push(node); - } - } - + var list = new Array(); + $('.wbs-item').each(function () { + list.push(SchemaAlignmentDialog._itemToJSON($(this))); + }); return { - rootNodes: rootNodes + 'items': list, + 'wikibasePrefix': this._wikibasePrefix, }; }; diff --git a/extensions/wikidata/module/styles/dialogs/schema-alignment-dialog.less b/extensions/wikidata/module/styles/dialogs/schema-alignment-dialog.less index b57f958ab..ee86352c0 100644 --- a/extensions/wikidata/module/styles/dialogs/schema-alignment-dialog.less +++ b/extensions/wikidata/module/styles/dialogs/schema-alignment-dialog.less @@ -51,20 +51,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. padding: 5px; } -.schema-alignment-draggable-column { +.wbs-draggable-column { border: 1px solid #aaa; padding: 2px; margin: 2px; background-color: #eee; display: inline-block; + padding-bottom: 3px; +} + +.wbs-reconciled-column { + border-bottom: 3px solid #282; + padding-bottom: 1px; +} + +.wbs-accepting-input { + box-shadow: inset 0 0 10px #a7cdff; } .wbs-item-input, .wbs-prop-input, .wbs-target-input { width: 160px; height: 20px; - border: 1px solid #a2a9b1; + /* border: 1px solid #a2a9b1; */ display: inline-block; - background: white; + /* background: white; */ margin: 5px; } @@ -72,6 +82,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. width: 120px; } +.wbs-item-input input, .wbs-prop-input input, .wbs-target-input input { + width: 100%; +} + +.wbs-draggable-column img { + float: right; +} + .wbs-toolbar { float: right; width: 100px; diff --git a/extensions/wikidata/src/org/openrefine/wikidata/commands/SaveWikibaseSchemaCommand.java b/extensions/wikidata/src/org/openrefine/wikidata/commands/SaveWikibaseSchemaCommand.java new file mode 100644 index 000000000..e2a664983 --- /dev/null +++ b/extensions/wikidata/src/org/openrefine/wikidata/commands/SaveWikibaseSchemaCommand.java @@ -0,0 +1,46 @@ +package org.openrefine.wikidata.commands; + +import java.io.IOException; +import java.util.Properties; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.openrefine.wikidata.operations.SaveWikibaseSchemaOperation; +import org.openrefine.wikidata.schema.WikibaseSchema; +import org.json.JSONObject; + +import com.google.refine.commands.Command; +import com.google.refine.model.AbstractOperation; +import com.google.refine.model.Project; +import com.google.refine.process.Process; +import com.google.refine.util.ParsingUtilities; + +public class SaveWikibaseSchemaCommand extends Command { + + public SaveWikibaseSchemaCommand() { + super(); + } + + @Override + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + try { + Project project = getProject(request); + + String jsonString = request.getParameter("schema"); + JSONObject json = ParsingUtilities.evaluateJsonStringToObject(jsonString); + WikibaseSchema schema = WikibaseSchema.reconstruct(json); + + AbstractOperation op = new SaveWikibaseSchemaOperation(schema); + Process process = op.createProcess(project, new Properties()); + + performProcessAndRespond(request, response, project, process); + + } catch (Exception e) { + respondException(response, e); + } + } +}