diff --git a/extensions/build.xml b/extensions/build.xml index 67839a2bd..2b39b8b9b 100644 --- a/extensions/build.xml +++ b/extensions/build.xml @@ -15,6 +15,7 @@ + @@ -25,6 +26,7 @@ + diff --git a/extensions/wikidata/module/MOD-INF/controller.js b/extensions/wikidata/module/MOD-INF/controller.js new file mode 100644 index 000000000..8288b1fd6 --- /dev/null +++ b/extensions/wikidata/module/MOD-INF/controller.js @@ -0,0 +1,137 @@ + +importPackage(org.openrefine.wikidata.commands); + +/* + * Function invoked to initialize the extension. + */ +function init() { + var RefineServlet = Packages.com.google.refine.RefineServlet; + RefineServlet.registerClassMapping( + "org.openrefine.wikidata.operations.SaveWikibaseSchemaOperation$WikibaseSchemaChange", + "org.openrefine.wikidata.operations.SaveWikibaseSchemaOperation$WikibaseSchemaChange"); + + RefineServlet.cacheClass(Packages.org.openrefine.wikidata.operations.SaveWikibaseSchemaOperation$WikibaseSchemaChange); + + /* + * Context Initialization. This is mainly to allow testability. a simple attempt to mimic dependency injection + */ + + /* + var initializer = new Packages.org.deri.grefine.rdf.app.InitilizationCommand(); + RefineServlet.registerCommand(module, "initialize", initializer); + var ctxt = new Packages.org.deri.grefine.rdf.app.ApplicationContext(); + initializer.initRdfExportApplicationContext(ctxt); + */ + + /* + * Attach a Wikibase schema to each project. + */ + Packages.com.google.refine.model.Project.registerOverlayModel( + "wikibaseSchema", + Packages.org.openrefine.wikidata.schema.WikibaseSchema); + + /* + * Operations + */ + Packages.com.google.refine.operations.OperationRegistry.registerOperation( + module, "save-wikibase-schema", Packages.org.openrefine.wikidata.operations.SaveWikibaseSchemaOperation); + + /* + * Exporters + */ + /* + var ExporterRegistry = Packages.com.google.refine.exporters.ExporterRegistry; + var QSV2Exporter = Packages.org.openrefine.wikidata.exporters.QuickStatements2Exporter; + + ExporterRegistry.registerExporter("qsv2", new QSV2()); + */ + + /* + * Resources + */ + ClientSideResourceManager.addPaths( + "project/scripts", + module, + [ + "scripts/menu-bar-extension.js", + "scripts/dialogs/schema-alignment-dialog.js", + ]); + + ClientSideResourceManager.addPaths( + "project/styles", + module, + [ + "styles/dialogs/schema-alignment-dialog.less", + ]); + +} + +function process(path, request, response) { + // Analyze path and handle this request yourself. + /* + var loggerFactory = Packages.org.slf4j.LoggerFactory; + var logger = loggerFactory.getLogger("rdf_extension"); + var method = request.getMethod(); + + logger.info('receiving request for ' + path); + if(rdfReconcileExtension.isKnownRequestUrl(path)){ + var command = rdfReconcileExtension.getCommand(path, request); + logger.info('command is ' + command); + var serviceName = rdfReconcileExtension.getServiceName(path); + logger.info('command is ' + command + ', while service name is ' + serviceName); + if(command && command !== 'unknown'){ + var jsonResponse; + if(command==='metadata'){ + jsonResponse = GRefineServiceManager.singleton.metadata(serviceName,request); + }else if(command==='multi-reconcile'){ + jsonResponse = GRefineServiceManager.singleton.multiReconcile(serviceName,request); + }else if (command==='suggest-type'){ + jsonResponse = GRefineServiceManager.singleton.suggestType(serviceName,request); + }else if (command==='flyout-type'){ + jsonResponse = GRefineServiceManager.singleton.previewType(serviceName,request); + }else if (command==='suggest-property'){ + jsonResponse = GRefineServiceManager.singleton.suggestProperty(serviceName,request); + }else if (command==='flyout-property'){ + jsonResponse = GRefineServiceManager.singleton.previewProperty(serviceName,request); + }else if (command==='suggest-entity'){ + jsonResponse = GRefineServiceManager.singleton.suggestEntity(serviceName,request); + }else if (command==='flyout-entity'){ + jsonResponse = GRefineServiceManager.singleton.previewEntity(serviceName,request); + }else if (command==='preview-resource-template'){ + var htmlResponse = GRefineServiceManager.singleton.getHtmlOfResourcePreviewTemplate(serviceName,request); + if(htmlResponse){ + butterfly.sendString(request, response, htmlResponse ,"UTF-8", "text/html"); + }else{ + butterfly.sendError(request, response, 404, "unknown service"); + } + return; + }else if (command==='view-resource'){ + var id = request.getParameter('id'); + butterfly.redirect(request,response,id); + return; + }else if (command ==='preview-resource'){ + logger.info("id is " + request.getParameter("id")); + var htmlResponse = GRefineServiceManager.singleton.previewResource(serviceName,request); + if(htmlResponse){ + butterfly.sendString(request, response, htmlResponse ,"UTF-8", "text/html"); + }else{ + butterfly.sendError(request, response, 404, "unknown service"); + } + return; + } + + if(jsonResponse){ + logger.info(jsonResponse); + butterfly.sendString(request, response, jsonResponse ,"UTF-8", "text/javascript"); + return; + }else{ + butterfly.sendError(request, response, 404, "unknown service"); + } + } + //else it is an unknown command... do nothing + } + + if (path == "/" || path == "") { + butterfly.redirect(request, response, "index.html"); + } */ +} diff --git a/extensions/wikidata/module/MOD-INF/module.properties b/extensions/wikidata/module/MOD-INF/module.properties new file mode 100644 index 000000000..a158dbdeb --- /dev/null +++ b/extensions/wikidata/module/MOD-INF/module.properties @@ -0,0 +1,3 @@ +name = wikidata +description = OpenRefine Wikidata export +requires = core diff --git a/extensions/wikidata/module/scripts/dialogs/schema-alignment-dialog.html b/extensions/wikidata/module/scripts/dialogs/schema-alignment-dialog.html new file mode 100644 index 000000000..9cd431c2e --- /dev/null +++ b/extensions/wikidata/module/scripts/dialogs/schema-alignment-dialog.html @@ -0,0 +1,45 @@ +
+
Align to Wikibase
+
+

+ The schema alignment skeleton below specifies how your tabular data will be + transformed into Wikibase statements. You can drag and drop columns in statements: + they will be replaced by their values once you export the statements. +

+
+ +
+
+

Columns:

+
+
+
+
+
+ +
+
+
+ +
+
+ +
diff --git a/extensions/wikidata/module/scripts/dialogs/schema-alignment-dialog.js b/extensions/wikidata/module/scripts/dialogs/schema-alignment-dialog.js new file mode 100644 index 000000000..589357365 --- /dev/null +++ b/extensions/wikidata/module/scripts/dialogs/schema-alignment-dialog.js @@ -0,0 +1,409 @@ +/* + +Copyright 2010, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + */ + +var SchemaAlignment = {}; + +SchemaAlignment.autoAlign = function() { + var protograph = {}; + + var columns = theProject.columnModel.columns; + + var typedCandidates = []; + var candidates = []; + + for (var c = 0; c < columns.length; c++) { + var column = columns[c]; + var typed = (column.reconConfig) && + ReconciliationManager.isFreebaseIdOrMid(column.reconConfig.identifierSpace) && + ReconciliationManager.isFreebaseId(column.reconConfig.schemaSpace); + + var candidate = { + status: "unbound", + typed: typed, + index: c, + column: column + }; + + candidates.push(candidate); + if (typed) { + typedCandidates.push(candidate); + } + } + + if (typedCandidates.length > 0) { + + } else { + var queries = {}; + for (var i = 0; i < candidates.length; i++) { + var candidate = candidates[i]; + var name = SchemaAlignment._cleanName(candidate.column.name); + var key = "t" + i + ":search"; + queries[key] = { + "query" : name, + "limit" : 10, + "type" : "/type/type,/type/property", + "type_strict" : "any" + }; + } + + SchemaAlignment._batchSearch(queries, function(result) { + console.log(result); + }); + } +}; + +SchemaAlignment._batchSearch = function(queries, onDone) { + var keys = []; + for (var n in queries) { + if (queries.hasOwnProperty(n)) { + keys.push(n); + } + } + + var result = {}; + var args = []; + var makeBatch = function(keyBatch) { + var batch = {}; + for (var k = 0; k < keyBatch.length; k++) { + var key = keyBatch[k]; + batch[key] = queries[key]; + } + + args.push("http://api.freebase.com/api/service/search?" + + $.param({ "queries" : JSON.stringify(batch) }) + "&callback=?"); + + args.push(null); // no data + args.push(function(data) { + for (var k = 0; k < keyBatch.length; k++) { + var key = keyBatch[k]; + result[key] = data[key]; + } + }); + }; + + for (var i = 0; i < keys.length; i += 10) { + makeBatch(keys.slice(i, i + 10)); + } + + args.push(function() { + onDone(result); + }); + + Ajax.chainGetJSON.apply(null, args); +}; + +SchemaAlignment._cleanName = function(s) { + return s.replace(/\W/g, " ").replace(/\s+/g, " ").toLowerCase(); +}; + +SchemaAlignment.createNewRootNode = function() { + var rootNode = null; + var links = []; + var columns = theProject.columnModel.columns; + for (var i = 0; i < columns.length; i++) { + var column = columns[i]; + var target = { + nodeType: "cell-as-topic", + columnName: column.name, + createForNoReconMatch: true + }; + if ((column.reconConfig) && + ReconciliationManager.isFreebaseIdOrMid(column.reconConfig.identifierSpace) && + ReconciliationManager.isFreebaseId(column.reconConfig.schemaSpace) && + (column.reconConfig.type)) { + + target.type = { + id: column.reconConfig.type.id, + name: column.reconConfig.type.name + }; + } + + if (column.name == theProject.columnModel.keyColumnName) { + rootNode = target; + } else { + links.push({ + property: null, + target: target + }); + } + } + + rootNode = rootNode || { nodeType: "cell-as-topic" }; + rootNode.links = links; + + return rootNode; +}; + +var SchemaAlignmentDialog = {}; + +SchemaAlignmentDialog.launch = function(onDone) { + this._onDone = onDone; + this._hasUnsavedChanges = false; + + this._createDialog(); + // this._reset(schema, true); +} + +SchemaAlignmentDialog._reset = function(protograph, initial) { + this._originalProtograph = protograph || { rootNodes: [] }; + this._protograph = cloneDeep(this._originalProtograph); // this is what can be munched on + + if (!this._protograph.rootNodes.length) { + this._protograph.rootNodes.push(SchemaAlignment.createNewRootNode()); + } + + $(this._nodeTable).empty(); + + this._nodeUIs = []; + for (var i = 0; i < this._protograph.rootNodes.length; i++) { + this._nodeUIs.push(new SchemaAlignmentDialog.UINode( + this, + this._protograph.rootNodes[i], + this._nodeTable, + { + expanded: true, + mustBeCellTopic: true + } + )); + } + + this.preview(initial); +}; + +SchemaAlignmentDialog._save = function(onDone) { + var self = this; + var protograph = this.getJSON(); + + Refine.postProcess( + "freebase", + "save-protograph", + {}, + { protograph: JSON.stringify(protograph) }, + {}, + { + onDone: function() { + theProject.overlayModels.freebaseProtograph = protograph; + + self._elmts.statusIndicator.hide(); + self._hasUnsavedChanges = false; + + if (onDone) onDone(); + } + } + ); +}; + +SchemaAlignmentDialog._createDialog = function() { + var self = this; + var frame = $(DOM.loadHTML("wikidata", "scripts/dialogs/schema-alignment-dialog.html")); + var elmts = this._elmts = DOM.bind(frame); + + this._level = DialogSystem.showDialog(frame); + + // 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); + this._columnArea.append(cell); + } + $('.schema-alignment-draggable-column').draggable({ + helper: "clone", + revert: true, + revertDuration: 200, + }); + + var dismiss = function() { + DialogSystem.dismissUntil(self._level - 1); + }; + + elmts.saveButton.click(function() { + self._save(); + }); + elmts.resetButton.click(function() { + self._reset(null); + }); + elmts.closeButton.click(function() { + if (!self._hasUnsavedChanges || window.confirm("There are unsaved changes. Close anyway?")) { + dismiss(); + } + }); + + elmts.addItemButton.click(function() { + self._addItem(); + }); + + $("#schema-alignment-tabs").tabs(); + + this._previewPanes = $(".schema-alignment-dialog-preview"); + + 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); +}; + +SchemaAlignmentDialog._addItem = function() { + var item = $('
').addClass('wbs-item'); + var input = $('
').addClass('wbs-item-input').appendTo(item); + SchemaAlignmentDialog._initField(input); + 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._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 right = $('
').addClass('wbs-right').appendTo(statementGroup); + $('
').addClass('wbs-statement-container').appendTo(right); + var toolbar = $('
').addClass('wbs-toolbar').appendTo(right); + $('').addClass('wbs-add-statement').text('add value').click(function() { + SchemaAlignmentDialog._addStatement(statementGroup); + }).appendTo(toolbar); + container.append(statementGroup); + SchemaAlignmentDialog._addStatement(statementGroup); +} + +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() { + SchemaAlignmentDialog._removeStatement(statement); + }).appendTo(toolbar1); + var input = $('
').addClass('wbs-target-input').appendTo(statement); + SchemaAlignmentDialog._initField(input); + var right = $('
').addClass('wbs-right').appendTo(statement); + $('
').addClass('wbs-qualifier-container').appendTo(right); + var toolbar2 = $('
').addClass('wbs-toolbar').appendTo(right); + $('').addClass('wbs-add-qualifier').text('add qualifier').appendTo(toolbar2); + 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"; + + input.suggestP(suggestConfig).bind("fb-select", function(evt, data) { + console.log(data); /* + self._addProperty({ + id : data.id, + name: data.name, + }); */ + }); +} + +SchemaAlignmentDialog._removeStatement = function(statement) { + var statementGroup = statement.parents('.wbs-statement-group').first(); + statement.remove(); + var remainingStatements = statementGroup.find('.wbs-statement').length; + if (remainingStatements === 0) { + statementGroup.remove(); + } +} +/* +SchemaAlignmentDialog._addStatement = function() { + var newStatement = $('
').addClass('schema-alignment-statement'); + var subject = $('
').addClass('schema-alignment-subject').appendTo(newStatement); + var prop = $('
').addClass('schema-alignment-prop').appendTo(newStatement); + var target = $('
').addClass('schema-alignment-target').appendTo(newStatement); + var qualifiersArea = $('
').addClass('schema-alignment-qualifiers').appendTo(newStatement); + var addQualifier = $('

').addClass('schema-alignment-add-qualifier').text('Add qualifier').appendTo(newStatement); + $('#schema-alignment-statements-container').append(newStatement); +} +*/ + +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); + } + } + + return { + rootNodes: rootNodes + }; +}; + +SchemaAlignmentDialog.preview = function(initial) { + var self = this; + + this._previewPanes.empty(); + if (!(initial)) { + this._elmts.statusIndicator.show().text("There are unsaved changes."); + this._hasUnsavedChanges = true; + } + + var protograph = this.getJSON(); + $.post( + "command/freebase/preview-protograph?" + $.param({ project: theProject.id }), + { protograph: JSON.stringify(protograph), engine: JSON.stringify(ui.browsingEngine.getJSON()) }, + function(data) { + if ("mqllike" in data) { + $(self._previewPanes[0]).text(JSON.stringify(data.mqllike, null, 2)); + } + if ("tripleloader" in data) { + $(self._previewPanes[1]).text(data.tripleloader); + } + }, + "json" + ); +}; + +SchemaAlignmentDialog._findColumn = function(cellIndex) { + var columns = theProject.columnModel.columns; + for (var i = 0; i < columns.length; i++) { + var column = columns[i]; + if (column.cellIndex == cellIndex) { + return column; + } + } + return null; +}; diff --git a/extensions/wikidata/module/styles/dialogs/schema-alignment-dialog.less b/extensions/wikidata/module/styles/dialogs/schema-alignment-dialog.less new file mode 100644 index 000000000..b57f958ab --- /dev/null +++ b/extensions/wikidata/module/styles/dialogs/schema-alignment-dialog.less @@ -0,0 +1,220 @@ +/* + +Copyright 2010, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +@import-less url("../theme.less"); + +.schema-alignment-dialog-canvas { + height: 400px; + overflow: auto; + padding: 0px + margin-top: 3px; + background: white; + } + +.schema-alignment-dialog-statements-area { + padding: 10px; + min-height: 200px; +} + +.schema-alignment-dialog-columns-area { + border: 1px solid #bcf; + padding: 5px; +} + +.schema-alignment-draggable-column { + border: 1px solid #aaa; + padding: 2px; + margin: 2px; + background-color: #eee; + display: inline-block; +} + +.wbs-item-input, .wbs-prop-input, .wbs-target-input { + width: 160px; + height: 20px; + border: 1px solid #a2a9b1; + display: inline-block; + background: white; + margin: 5px; +} + +.wbs-prop-input { + width: 120px; +} + +.wbs-toolbar { + float: right; + width: 100px; + padding: 2px; +} + +.wbs-add-item, .wbs-add-statement-group, .wbs-add-statement, .wbs-add-qualifier { + color: #0645ad !important; + font-size: 0.9em; +} + +.wbs-statement-group-container, .wbs-statement-container, .wbs-qualifier-container { + width: 100%; + display: block; + overflow: auto; +} + +.wbs-item, .wbs-statement-group, .wbs-statement { + display: block; + overflow: auto; +} + +.wbs-statement-group { + background: #eaecf0; + margin-bottom: 5px; +} + +.wbs-statement { + background: white; +} + +.wbs-right { + float: right; + width: 70%; +} + +.schema-alignment-columns-header { + margin-bottom: 0.3em; +} + +table.schema-alignment-table-layout { + border-collapse: collapse; + margin: 0px; + padding: 0px; + margin-bottom: 1em; + } + +table.schema-alignment-table-layout .padded { + padding: 3px 6px; + } + +div.schema-alignment-detail-container { + border-left: 3px solid #eee; + } + +td.schema-alignment-node-main, td.schema-alignment-link-main { + white-space: pre; + width: 300px; + } + +td.schema-alignment-node-toggle, td.schema-alignment-link-toggle { + white-space: pre; + width: 1%; + } + +td.schema-alignment-node-toggle img, td.schema-alignment-link-toggle img { + cursor: pointer; + vertical-align: middle; + padding: 2px; + } + +td.schema-alignment-node-details, td.schema-alignment-link-details { + width: 90%; + } + +a.schema-alignment-node-tag { + padding: 3px 6px; + background: #ddd; + text-decoration: none; + color: black; + -moz-border-radius: 10px; + } +a.schema-alignment-node-tag:hover { + background: #888; + color: white; + } +.schema-alignment-node-column { + font-weight: bold; + } + +a.schema-alignment-link-tag { + padding: 3px 6px; + text-decoration: none; + color: black; + } +a.schema-alignment-link-tag:hover { + color: #88f; + } + +div.schema-alignment-dialog-preview { + height: 400px; + overflow: auto; + background: white; + padding: 10px; + margin-top: 3px; + white-space: pre; + font-family: monospace; + font-size: 9pt; + } + +.schema-alignment-status-indicator { + color: #red; + } + +/*-------------------------------------------------- + * Node dialog + *-------------------------------------------------- + */ + +.schema-align-node-dialog-node-type { + padding: 0.25em; + background: #ddf; + } +.schema-align-node-dialog-node-type input { + vertical-align: text-bottom; + } +.schema-alignment-node-dialog-column-list { + height: 300px; + width: 200px; + overflow: auto; + border: 1px solid #ddd; + } + +/*-------------------------------------------------- + * Link dialog + *-------------------------------------------------- + */ + +.schema-alignment-link-menu-section { + padding: 8px; + border-bottom: 1px solid #ddd; + } + +.schema-alignment-link-menu-section-last { + padding: 8px; + }