SchemaAlignmentDialog.UILink = function(dialog, link, table, options, parentUINode) { this._dialog = dialog; this._link = link; this._options = options; this._parentUINode = parentUINode; 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._options.expanded) { self._collapsedDetailDiv.hide(); self._expandedDetailDiv.show(); } else { self._collapsedDetailDiv.show(); self._expandedDetailDiv.hide(); } }; show(); $(this._tdToggle).html(" "); $('') .attr("src", this._options.expanded ? "images/expanded.png" : "images/collapsed.png") .appendTo(this._tdToggle) .click(function() { self._options.expanded = !self._options.expanded; $(this).attr("src", self._options.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; $('') .attr("title", "remove property") .attr("src", "images/close.png") .css("cursor", "pointer") .prependTo(this._tdMain) .click(function() { window.setTimeout(function() { self._parentUINode.removeLink(self); self._tr.parentNode.removeChild(self._tr); }, 100); }); var a = $('') .addClass("schema-alignment-link-tag") .html(label) .appendTo(this._tdMain) .click(function(evt) { self._startEditProperty(this); }); $('').attr("src", "images/arrow-start.png").prependTo(a); $('').attr("src", "images/arrow-end.png").appendTo(a); }; SchemaAlignmentDialog.UILink.prototype._renderDetails = function() { if (this._targetUI) { this._targetUI.dispose(); } if (this._tableDetails) { this._tableDetails.remove(); } this._tableDetails = $('
').addClass("schema-alignment-table-layout").appendTo(this._expandedDetailDiv); this._targetUI = new SchemaAlignmentDialog.UINode( this._dialog, this._link.target, this._tableDetails[0], { expanded: "links" in this._link.target && this._link.target.links.length > 0 }); }; SchemaAlignmentDialog.UILink.prototype._startEditProperty = function(elmt) { var sourceTypeID = this._parentUINode.getExpectedType(); var targetTypeID = "type" in this._link.target && this._link.target.type != null ? this._link.target.type.id : null; var targetTypeName = "columnName" in this._link.target ? this._link.target.columnName : null; if (sourceTypeID != null) { var self = this; var dismissBusy = DialogSystem.showBusy(); var instanceCount = 0; var outgoing = []; var incoming = []; function onDone() { dismissBusy(); var suggestions = SchemaAlignmentDialog.UILink._rankProperties(outgoing, incoming, sourceTypeID, targetTypeID, targetTypeName); self._showPropertySuggestPopup(elmt, suggestions); }; var cotypes = []; function doCoTypes() { if (cotypes.length === 0) { onDone(); } else { var cotype = cotypes.pop(); SchemaAlignmentDialog.UILink._getPropertiesOfType( cotype.t, outgoing, incoming, cotype.c / instanceCount, doCoTypes ); } }; SchemaAlignmentDialog.UILink._getPropertiesOfType( sourceTypeID, outgoing, incoming, 1, function(data) { if ("result" in data) { instanceCount = data.result.count; if ("cotypes" in data.result) { cotypes = data.result.cotypes.slice(0, 3); } } doCoTypes(); } ); } else { this._showPropertySuggestPopup(elmt, []); } }; SchemaAlignmentDialog.UILink._rankProperties = function(outgoing, incoming, sourceTypeID, targetTypeID, targetTypeName) { var nameScorer; if (targetTypeName === null) { nameScorer = function() { return 1; }; } else { var nameWords = targetTypeName.toLowerCase().replace(/\W/g, ' ').replace(/\s+/g, ' ').split(" "); var nameScoreString = function(score, s) { s = s.toLowerCase().replace(/\W/g, ' '); var n = 0; for (var i = 0; i < nameWords.length; i++) { if (s.indexOf(nameWords[i]) >= 0) { n++; } } return Math.max(score, n / nameWords.length); }; var nameScoreStrings = function(score, a) { $.each(a, function() { score = nameScoreString(score, this); }); return score; }; nameScorer = function(p) { var score = nameScoreString(0, p.name); score = nameScoreStrings(score, p.alias); if ("expects" in p && p.expects !== null) { score = nameScoreString(score, p.expects.name); score = nameScoreStrings(score, p.expects.alias); if ("plural_names" in p.expects) { score = nameScoreStrings(score, p.expects.plural_names); } if ("plural_aliases" in p.expects) { score = nameScoreStrings(score, p.expects.plural_aliases); } } return score; }; }; var typeScorer; if (targetTypeID === null) { typeScorer = function(p) { return p.weight; }; } else { typeScorer = function(p) { return p.expects.id == targetTypeID ? 1 : p.weight; }; } var suggestions = []; for (var i = 0; i < outgoing.length; i++) { var p = outgoing[i]; p.score = p.weight * (0.5 * nameScorer(p) + 0.5 * typeScorer(p)); if (p.score > 0) { suggestions.push(p); } } suggestions.sort(function(a, b) { return b.score - a.score; }); suggestions = suggestions.slice(0, 7); return suggestions; }; SchemaAlignmentDialog.UILink._getPropertiesOfType = function(typeID, outgoing, incoming, weight, onDone) { $.getJSON( "http://api.sandbox-freebase.com/api/trans/schema_index/-" + typeID + "?callback=?", null, function(data) { if ("result" in data) { var result = data.result; if ("outgoing" in result) { for (var i = 0; i < result.outgoing.length; i++) { var p = result.outgoing[i]; p.weight = weight; outgoing.push(p); } } if ("incoming" in result) { for (var i = 0; i < result.incoming.length; i++) { var p = result.incoming[i]; p.weight = weight; incoming.push(p); } } } onDone(data); }, "jsonp" ); }; SchemaAlignmentDialog.UILink.prototype._showPropertySuggestPopup = function(elmt, suggestions) { self = this; var menu = MenuSystem.createMenu().width("350px"); var commitProperty = function(p) { window.setTimeout(function() { MenuSystem.dismissAll(); }, 100); if ("plies" in p && p.plies.length > 1) { // self._targetUI.dispose(); self._link.property = { id: p.plies[0], name: p.name }; self._link.target = { nodeType: "anonymous", links: [{ property: { id: p.plies[1], name: p.name2 }, target: self._link.target }] }; self._renderDetails(); } else { self._link.property = { id: p.id, name: p.name }; } self._configureTarget(); }; if (suggestions.length > 0) { var divSearch = $('
').addClass("schema-alignment-link-menu-type-search2").html('
Search for a property or pick one below
').appendTo(menu); function createSuggestion(suggestion) { var menuItem = MenuSystem.createMenuItem().appendTo(menu); menuItem.html(suggestion.id).click(function() { commitProperty(suggestion); }); } for (var i = 0; i < suggestions.length; i++) { createSuggestion(suggestions[i]); } } else { var divSearch = $('
').addClass("schema-alignment-link-menu-type-search").html('
Search for a property
').appendTo(menu); } var input = $('').appendTo($('
').appendTo(divSearch)); MenuSystem.showMenu(menu, function(){}); MenuSystem.positionMenuAboveBelow(menu, $(elmt)); var suggestOptions = { type : '/type/property' }; if (this._link.target != null && "type" in this._link.target && this._link.target.type != null) { /* suggestOptions.mql_filter = [{ "/type/property/expected_type" : { id: this._link.target.type.id } }]; */ } else { var sourceTypeID = this._parentUINode.getExpectedType(); if (sourceTypeID != null) { suggestOptions.schema = sourceTypeID; } } input.suggestP(suggestOptions).bind("fb-select", function(e, data) { commitProperty(data); }); 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; }; SchemaAlignmentDialog.UILink.prototype._configureTarget = function() { var self = this; var dismissBusy = DialogSystem.showBusy(); $.getJSON( "http://api.freebase.com/api/service/mqlread?query=" + JSON.stringify({ query: { "id" : this._link.property.id, "type" : "/type/property", "expected_type" : { "id" : null, "name" : null, "/freebase/type_hints/mediator" : null } } }) + "&callback=?", null, function(o) { dismissBusy(); if ("result" in o) { var expected_type = o.result.expected_type; self._link.target.type = { id: expected_type.id, name: expected_type.name }; if (expected_type["/freebase/type_hints/mediator"] == true) { self._link.target.nodeType = "anonymous"; } else if (expected_type.id == "/type/key") { self._link.target.nodeType = "cell-as-key"; } else if (expected_type.id.match(/^\/type\//)) { self._link.target.nodeType = "cell-as-value"; } else if (!("topic" in self._link.target)) { self._link.target.nodeType = "cell-as-topic"; self._link.target.createForNoReconMatch = true; } self._targetUI.render(); } self._renderMain(); self._dialog.preview(); }, "jsonp" ); };