/**
* Contains the logic for the sidebar.
* @param graph the graph that belongs to these controls
* @returns {{}}
*/
module.exports = function ( graph ){
var sidebar = {},
languageTools = webvowl.util.languageTools(),
elementTools = webvowl.util.elementTools(),
// Required for reloading when the language changes
ontologyInfo,
visibleSidebar = 1,
lastSelectedElement,
detailArea = d3.select("#detailsArea"),
graphArea = d3.select("#canvasArea"),
menuArea = d3.select("#swipeBarContainer"),
collapseButton = d3.select("#sidebarExpandButton");
/**
* Setup the menu bar.
*/
function setupCollapsing(){
// adapted version of this example: http://www.normansblog.de/simple-jquery-accordion/
function collapseContainers( containers ){
containers.classed("hidden", true);
}
function expandContainers( containers ){
containers.classed("hidden", false);
}
var triggers = d3.selectAll(".accordion-trigger");
// Collapse all inactive triggers on startup
collapseContainers(d3.selectAll(".accordion-trigger:not(.accordion-trigger-active) + div"));
triggers.on("click", function (){
var selectedTrigger = d3.select(this),
activeTriggers = d3.selectAll(".accordion-trigger-active");
if ( selectedTrigger.classed("accordion-trigger-active") ) {
// Collapse the active (which is also the selected) trigger
collapseContainers(d3.select(selectedTrigger.node().nextElementSibling));
selectedTrigger.classed("accordion-trigger-active", false);
} else {
// Collapse the other trigger ...
collapseContainers(d3.selectAll(".accordion-trigger-active + div"));
activeTriggers.classed("accordion-trigger-active", false);
// ... and expand the selected one
expandContainers(d3.select(selectedTrigger.node().nextElementSibling));
selectedTrigger.classed("accordion-trigger-active", true);
}
});
}
sidebar.clearOntologyInformation = function (){
d3.select("#ontology-panel").selectAll("*").remove();
clearSelectedNodePanel();
};
/**
* Updates the information of the passed ontology.
* @param data the graph data
* @param statistics the statistics module
*/
sidebar.updateOntologyInformation = function ( data, statistics ){
data = data || {};
ontologyInfo = data.header || {};
var panel = d3.select("#ontology-panel");
panel.selectAll("*").remove();
renderPair(panel, "IRI", ontologyInfo.iri, ontologyInfo.iri);
var title = languageTools.textInLanguage(ontologyInfo.title, graph.language());
renderPair(panel, "Title", title);
renderPair(panel, "Version", ontologyInfo.version);
var authors = ontologyInfo.author;
if ( authors instanceof Array ) authors = authors.join(", ");
renderPair(panel, "Author", authors);
var description = languageTools.textInLanguage(ontologyInfo.description, graph.language());
renderPair(panel, "Description", description);
var other = ontologyInfo.other || {};
for ( var otherKey in other ) {
if ( other.hasOwnProperty(otherKey) ) {
var otherEntries = other[otherKey];
if ( !otherEntries ) continue;
var otherLabel = prefixedName(otherKey);
otherEntries.forEach(function ( ann ){
if ( !ann ) return;
renderPair(panel, otherLabel, ann.value, ann.type === "iri" ? ann.value : undefined);
});
}
}
if ( panel.selectAll(".annotation-row").size() === 0 ) {
panel.append("p").classed("no-selection-hint", true).text("No ontology information available.");
}
sidebar.updateSelectionInformation(undefined);
setLanguages(ontologyInfo.languages);
};
function setLanguages( languages ){
languages = languages || [];
// Put the default and unset label on top of the selection labels
languages.sort(function ( a, b ){
if ( a === webvowl.util.constants().LANG_IRIBASED ) {
return -1;
} else if ( b === webvowl.util.constants().LANG_IRIBASED ) {
return 1;
}
if ( a === webvowl.util.constants().LANG_UNDEFINED ) {
return -1;
} else if ( b === webvowl.util.constants().LANG_UNDEFINED ) {
return 1;
}
return a.localeCompare(b);
});
var languageSelection = d3.select("#language")
.on("change", function (){
graph.language(d3.event.target.value);
sidebar.updateSelectionInformation(lastSelectedElement);
});
languageSelection.selectAll("option").remove();
languageSelection.selectAll("option")
.data(languages)
.enter().append("option")
.attr("value", function ( d ){
return d;
})
.text(function ( d ){
return d;
});
if ( !trySelectDefaultLanguage(languageSelection, languages, "en") ) {
if ( !trySelectDefaultLanguage(languageSelection, languages, webvowl.util.constants().LANG_UNDEFINED) ) {
trySelectDefaultLanguage(languageSelection, languages, webvowl.util.constants().LANG_IRIBASED);
}
}
}
function trySelectDefaultLanguage( selection, languages, language ){
var langIndex = languages.indexOf(language);
if ( langIndex >= 0 ) {
selection.property("selectedIndex", langIndex);
graph.language(language);
return true;
}
return false;
}
function renderPair( container, name, value, iri ){
if ( !value && value !== 0 ) return;
var row = container.append("div").classed("annotation-row", true);
row.append("span").classed("annotation-name", true).text(name);
var valSpan = row.append("span").classed("annotation-value", true);
appendIriLabel(valSpan, value, iri);
}
function clearSelectedNodePanel(){
var panel = d3.select("#selected-node-panel");
panel.selectAll("*").remove();
panel.append("p").classed("no-selection-hint", true).text("Select an element in the visualization.");
}
/**
* Update the information of the selected node.
* @param selectedElement the selection or null if nothing is selected
*/
sidebar.updateSelectionInformation = function ( selectedElement ){
lastSelectedElement = selectedElement;
if ( d3.event && d3.event.defaultPrevented ) {
return;
}
if ( !selectedElement ) {
clearSelectedNodePanel();
return;
}
if ( elementTools.isProperty(selectedElement) ) {
displayPropertyInformation(selectedElement);
} else if ( elementTools.isNode(selectedElement) ) {
displayNodeInformation(selectedElement);
}
};
function displayPropertyInformation( property ){
var panel = d3.select("#selected-node-panel");
panel.selectAll("*").remove();
renderPair(panel, "IRI", property.iri(), property.iri());
renderPair(panel, "Name", prefixedName(property.iri()));
renderPair(panel, "Label", property.labelForCurrentLanguage());
renderPair(panel, "Type", property.type());
if ( property.domain() ) renderPair(panel, "Domain", property.domain().labelForCurrentLanguage(), property.domain().iri());
if ( property.range() ) renderPair(panel, "Range", property.range().labelForCurrentLanguage(), property.range().iri());
if ( property.inverse() ) renderPair(panel, "Inverse", property.inverse().labelForCurrentLanguage(), property.inverse().iri());
renderNodeArrayPairs(panel, "Equivalent", property.equivalents());
renderNodeArrayPairs(panel, "Subproperty", property.subproperties());
renderNodeArrayPairs(panel, "Superproperty", property.superproperties());
if ( property.minCardinality() !== undefined ) {
renderPair(panel, "Min. cardinality", property.minCardinality());
renderPair(panel, "Max. cardinality", property.maxCardinality() !== undefined ? property.maxCardinality() : "*");
} else if ( property.cardinality() !== undefined ) {
renderPair(panel, "Cardinality", property.cardinality());
}
var attrs = getAttributes(property.attributes());
if ( attrs ) renderPair(panel, "Characteristics", attrs);
renderCommentPairs(panel, property.comment());
renderAnnotationPairs(panel, property.annotations());
}
function getAttributes( attributes ){
if ( !attributes || attributes.length === 0 ) return null;
var filtered = attributes.filter(function ( a ){ return a !== "object" && a !== "datatype" && a !== "rdf"; });
return filtered.length > 0 ? filtered.join(", ") : null;
}
function renderNodeArrayPairs( panel, label, nodes ){
if ( !nodes || nodes.length === 0 ) return;
nodes.forEach(function ( el ){
renderPair(panel, label, el.labelForCurrentLanguage(), el.iri());
});
}
function prefixedName( iri ){
var pm = graph.options().prefixModule();
if ( pm && pm.getPrefixRepresentationForFullURI ) {
var prefixed = pm.getPrefixRepresentationForFullURI(iri);
if ( prefixed !== iri ) return prefixed;
}
return iri;
}
function renderCommentPairs( panel, comment ){
if ( !comment ) return;
if ( typeof comment === "string" ) {
renderPair(panel, "rdfs:comment", comment);
return;
}
for ( var lang in comment ) {
if ( comment.hasOwnProperty(lang) && comment[lang] ) {
renderPair(panel, "rdfs:comment", comment[lang]);
}
}
}
function renderAnnotationPairs( panel, annotationObject ){
annotationObject = annotationObject || {};
for ( var key in annotationObject ) {
if ( annotationObject.hasOwnProperty(key) ) {
var entries = annotationObject[key];
if ( !entries ) continue;
var label = prefixedName(key);
entries.forEach(function ( ann ){
if ( !ann ) return;
renderPair(panel, label, ann.value, ann.type === "iri" ? ann.value : undefined);
});
}
}
}
function appendIriLabel( element, name, iri ){
var tag;
if ( iri ) {
tag = element.append("a")
.attr("href", iri)
.attr("title", iri)
.attr("target", "_blank");
} else {
tag = element.append("span");
}
tag.text(name);
}
function displayNodeInformation( node ){
var panel = d3.select("#selected-node-panel");
panel.selectAll("*").remove();
renderPair(panel, "IRI", node.iri(), node.iri());
renderPair(panel, "Name", prefixedName(node.iri()));
renderPair(panel, "Label", node.labelForCurrentLanguage());
renderPair(panel, "Type", node.type());
renderNodeArrayPairs(panel, "Equivalent", node.equivalents());
renderNodeArrayPairs(panel, "Disjoint with", node.disjointWith());
renderNodeArrayPairs(panel, "Individual", node.individuals());
if ( node.links ) {
node.links().forEach(function ( link ){
var prop = link.property ? link.property() : null;
if ( prop && prop.type() === "rdfs:subClassOf" ) {
var parent = prop.range();
if ( parent && parent !== node ) {
renderPair(panel, "rdfs:subClassOf", prefixedName(parent.iri()), parent.iri());
}
}
});
}
var attrs = getAttributes(node.attributes());
if ( attrs ) renderPair(panel, "Characteristics", attrs);
renderCommentPairs(panel, node.comment());
renderAnnotationPairs(panel, node.annotations());
}
/** Collapsible Sidebar functions; **/
sidebar.showSidebar = function ( val, init ){
// make val to bool
if ( val === 1 ) {
visibleSidebar = true;
collapseButton.node().innerHTML = ">";
detailArea.classed("hidden", true);
if ( init === true ) {
detailArea.classed("hidden", !visibleSidebar);
graphArea.style("width", "78%");
graphArea.style("-webkit-animation-name", "none");
menuArea.style("width", "78%");
menuArea.style("-webkit-animation-name", "none");
d3.select("#WarningErrorMessagesContainer").style("width", "78%");
d3.select("#WarningErrorMessagesContainer").style("-webkit-animation-name", "none");
} else {
graphArea.style("width", "78%");
graphArea.style("-webkit-animation-name", "sbCollapseAnimation");
graphArea.style("-webkit-animation-duration", "0.5s");
menuArea.style("width", "78%");
menuArea.style("-webkit-animation-name", "sbCollapseAnimation");
menuArea.style("-webkit-animation-duration", "0.5s");
d3.select("#WarningErrorMessagesContainer").style("width", "78%");
d3.select("#WarningErrorMessagesContainer").style("-webkit-animation-name", "warn_ExpandRightBarAnimation");
d3.select("#WarningErrorMessagesContainer").style("-webkit-animation-duration", "0.5s");
}
graph.options().width(window.innerWidth - (window.innerWidth * 0.22));
graph.options().navigationMenu().updateScrollButtonVisibility();
}
if ( val === 0 ) {
visibleSidebar = false;
detailArea.classed("hidden", true);
collapseButton.node().innerHTML = "<";
// adjust the layout
if ( init === true ) {
graphArea.style("width", "100%");
graphArea.style("-webkit-animation-name", "none");
menuArea.style("width", "100%");
menuArea.style("-webkit-animation-name", "none");
d3.select("#WarningErrorMessagesContainer").style("width", "100%");
d3.select("#WarningErrorMessagesContainer").style("-webkit-animation-name", "none");
} else {
graphArea.style("width", "100%");
graphArea.style("-webkit-animation-name", "sbExpandAnimation");
graphArea.style("-webkit-animation-duration", "0.5s");
menuArea.style("width", "100%");
menuArea.style("-webkit-animation-name", "sbExpandAnimation");
menuArea.style("-webkit-animation-duration", "0.5s");
d3.select("#WarningErrorMessagesContainer").style("width", "100%");
d3.select("#WarningErrorMessagesContainer").style("-webkit-animation-name", "warn_CollapseRightBarAnimation");
d3.select("#WarningErrorMessagesContainer").style("-webkit-animation-duration", "0.5s");
}
graph.options().width(window.innerWidth);
graph.updateCanvasContainerSize();
graph.options().navigationMenu().updateScrollButtonVisibility();
}
};
sidebar.isSidebarVisible = function (){
return visibleSidebar;
};
sidebar.updateSideBarVis = function ( init ){
var vis = sidebar.getSidebarVisibility();
sidebar.showSidebar(parseInt(vis), init);
};
sidebar.getSidebarVisibility = function (){
var isHidden = detailArea.classed("hidden");
if ( isHidden === false ) return String(1);
if ( isHidden === true ) return String(0);
};
sidebar.initSideBarAnimation = function (){
graphArea.node().addEventListener("animationend", function (){
detailArea.classed("hidden", !visibleSidebar);
graph.updateCanvasContainerSize();
graph.options().navigationMenu().updateScrollButtonVisibility();
});
};
sidebar.setup = function (){
setupCollapsing();
sidebar.initSideBarAnimation();
collapseButton.on("click", function (){
graph.options().navigationMenu().hideAllMenus();
var settingValue = parseInt(sidebar.getSidebarVisibility());
if ( settingValue === 1 ) sidebar.showSidebar(0);
else sidebar.showSidebar(1);
});
};
sidebar.updateShowedInformation = function (){
var editMode = graph.editorMode();
d3.select("#generalDetails").classed("hidden", editMode);
d3.select("#generalDetailsEdit").classed("hidden", !editMode);
// store the meta information in graph.options()
// todo: update edit meta info
graph.options().editSidebar().updateGeneralOntologyInfo();
// todo: update showed meta info;
graph.options().sidebar().updateGeneralOntologyInfo();
};
sidebar.updateGeneralOntologyInfo = function (){
// get it from graph.options
var generalMetaObj = graph.options().getGeneralMetaObject();
var preferredLanguage = graph && graph.language ? graph.language() : null;
if ( generalMetaObj.hasOwnProperty("title") ) {
// title has language to it -.-
if ( typeof generalMetaObj.title === "object" ) {
d3.select("#title").node().value = languageTools.textInLanguage(generalMetaObj.title, preferredLanguage);
} else {
d3.select("#title").node().innerHTML = generalMetaObj.title;
}
}
if ( generalMetaObj.hasOwnProperty("iri") ) d3.select("#about").node().innerHTML = generalMetaObj.iri;
if ( generalMetaObj.hasOwnProperty("iri") ) d3.select("#about").node().href = generalMetaObj.iri;
if ( generalMetaObj.hasOwnProperty("version") ) d3.select("#version").node().innerHTML = generalMetaObj.version;
if ( generalMetaObj.hasOwnProperty("author") ) d3.select("#authors").node().innerHTML = generalMetaObj.author;
// this could also be an object >>
if ( generalMetaObj.hasOwnProperty("description") ) {
if ( typeof generalMetaObj.description === "object" ) {
d3.select("#description").node().innerHTML = languageTools.textInLanguage(generalMetaObj.description, preferredLanguage);
}
else {
d3.select("#description").node().innerHTML = generalMetaObj.description;
}
}
};
return sidebar;
};