Holger Knublauch

Tree selection working

......@@ -580,9 +580,34 @@ app:ClassTreeDataProvider
rdfs:label "Class tree data provider"^^xsd:string ;
arg:treeChildrenTemplate
app:ClassTreeChildren ;
arg:treePathTemplate
app:ClassTreePath ;
arg:treeRootsTemplate
app:ClassTreeRoots .
app:ClassTreePath
rdf:type spin:SelectTemplate ;
rdfs:label "Class tree path"^^xsd:string ;
rdfs:subClassOf app:TreePathTemplates ;
spin:body
[ rdf:type sp:Select ;
sp:resultVariables ([ sp:varName "path"^^xsd:string
]) ;
sp:where ([ rdf:type sp:Bind ;
sp:expression
[ rdf:type spif:shortestObjectsPath ;
sp:arg1 [ sp:varName "node"^^xsd:string
] ;
sp:arg2 rdfs:subClassOf ;
sp:arg3 [ sp:varName "root"^^xsd:string
]
] ;
sp:variable
[ sp:varName "path"^^xsd:string
]
])
] .
app:ClassTreeRoots
rdf:type spin:SelectTemplate ;
rdfs:label "Class tree roots"^^xsd:string ;
......@@ -860,6 +885,7 @@ app:CustomEditForm
] ;
ui:child
[ rdf:type html:Form ;
html:autocomplete "off"^^xsd:string ;
html:class "appForm ui-layout-content"^^xsd:string ;
html:id [ sp:varName "fid"^^xsd:string
] ;
......@@ -3973,6 +3999,7 @@ app:SearchForm
] ;
ui:child
[ rdf:type html:Form ;
html:autocomplete "off"^^xsd:string ;
html:class
[ rdf:type ui:concat ;
sp:arg1 "appForm ui-layout-content "^^xsd:string ;
......@@ -5481,7 +5508,9 @@ app:TreeDataProvider
rdf:type ui:NodeClass ;
rdfs:comment """Instances of this class are used as server callbacks to drive an app:Tree.
A TreeDataProvider is backed by two SELECT queries - one to get the roots, and one to get the children of a given node. Optionally, a root resource can be supplied to overload the default root(s)."""^^xsd:string ;
A TreeDataProvider is backed by two SELECT queries - one to get the roots, and one to get the children of a given node. Optionally, a root resource can be supplied to overload the default root(s).
Another operation that trees must support is finding an expansion path from a root to a given node. To support this, each TreeDataProvider points to a SPIN template that delivers a path. This typically uses the spif:shortestObjectsPath function."""^^xsd:string ;
rdfs:label "Tree data provider"^^xsd:string ;
rdfs:subClassOf app:TreeElements ;
spin:constraint
......@@ -5492,6 +5521,12 @@ A TreeDataProvider is backed by two SELECT queries - one to get the roots, and o
] ;
spin:constraint
[ rdf:type spl:Argument ;
rdfs:comment "This SPIN template is called with the variable ?node pre-bound to a node in the tree and ?root possibly pointing to a root resource. The template must return a single result variable containing a path from a root to that node. See spif:shortestObjectsPath for a default implementation. The path must be a space-separated string concatenation of URIs."^^xsd:string ;
spl:predicate arg:treePathTemplate ;
spl:valueType spin:Template
] ;
spin:constraint
[ rdf:type spl:Argument ;
rdfs:comment "A subclass of app:TreeRootsTemplates that delivers the roots of the tree. Will be bypassed if the tree itself defined an arg:rootResource."^^xsd:string ;
spl:optional "true"^^xsd:boolean ;
spl:predicate arg:treeRootsTemplate ;
......@@ -5583,6 +5618,25 @@ app:TreeElements
rdfs:label "Tree elements"^^xsd:string ;
rdfs:subClassOf app:Elements .
app:TreePathTemplates
rdf:type spin:SelectTemplate ;
rdfs:comment "An abstract superclass for SPIN templates used by TreeDataProviders to find a path from a node to a root."^^xsd:string ;
rdfs:label "Tree path templates"^^xsd:string ;
rdfs:subClassOf spin:SelectTemplates ;
spin:constraint
[ rdf:type spl:Argument ;
rdfs:comment "The node to start traversal at."^^xsd:string ;
spl:predicate arg:node ;
spl:valueType rdfs:Resource
] ;
spin:constraint
[ rdf:type spl:Argument ;
rdfs:comment "An optional root resource to stop traversal at."^^xsd:string ;
spl:optional "true"^^xsd:boolean ;
spl:predicate arg:root ;
spl:valueType rdfs:Resource
] .
app:TreeRootsTemplates
rdf:type spin:SelectTemplate ;
rdfs:comment "Abstract superclass for queries that can deliver the roots of a tree."^^xsd:string ;
......@@ -5596,6 +5650,115 @@ app:TreeRootsTemplates
spl:valueType rdfs:Resource
] .
app:TreeShortestPathCallback
rdf:type ui:NodeClass ;
rdfs:comment "An element building a JSON array with URIs based on spif:shortestObjectsPath. Called using uispin?_viewClass=app:TreeShortestPathCallback&_format=json&subject=...&dataProvider=..."^^xsd:string ;
rdfs:label "Tree shortest path callback"^^xsd:string ;
rdfs:subClassOf app:TreeElements ;
spin:constraint
[ rdf:type spl:Argument ;
rdfs:comment "The TreeDataProvider that contains the pathExpression needed to walk to the root."^^xsd:string ;
spl:predicate arg:dataProvider ;
spl:valueType app:TreeDataProvider
] ;
spin:constraint
[ rdf:type spl:Argument ;
rdfs:comment "The node resource to start traversal at."^^xsd:string ;
spl:predicate arg:node ;
spl:valueType rdfs:Resource
] ;
spin:constraint
[ rdf:type spl:Argument ;
rdfs:comment "The root resource to stop at."^^xsd:string ;
spl:optional "true"^^xsd:boolean ;
spl:predicate arg:root ;
spl:valueType rdfs:Resource
] ;
ui:prototype
[ rdf:type ui:group ;
let:template
[ rdf:type sp:Select ;
sp:resultVariables ([ sp:varName "template"^^xsd:string
]) ;
sp:where ([ rdf:type sp:NamedGraph ;
sp:elements ([ sp:object
[ sp:varName "template"^^xsd:string
] ;
sp:predicate arg:treePathTemplate ;
sp:subject
[ sp:varName "dataProvider"^^xsd:string
]
]) ;
sp:graphNameNode ui:graph
])
] ;
ui:child
[ rdf:type ui:call ;
arg:node
[ sp:varName "node"^^xsd:string
] ;
arg:root
[ sp:varName "root"^^xsd:string
] ;
ui:child
[ rdf:type ui:group ;
let:path
[ rdf:type spr:cell ;
sp:arg1 [ sp:varName "rs"^^xsd:string
] ;
sp:arg2 0 ;
sp:arg3 0
] ;
ui:child
[ rdf:type swon:RSArray ;
arg:resultSet
[ rdf:type sp:Select ;
sp:resultVariables ([ sp:varName "value"^^xsd:string
]) ;
sp:where ([ sp:object
[ sp:varName "?0"^^xsd:string
] ;
sp:predicate spif:split ;
sp:subject
[ sp:varName "value"^^xsd:string
]
] [ sp:object
[ sp:varName "path"^^xsd:string
] ;
sp:predicate rdf:first ;
sp:subject
[ sp:varName "?0"^^xsd:string
]
] [ sp:object
[ sp:varName "?1"^^xsd:string
] ;
sp:predicate rdf:rest ;
sp:subject
[ sp:varName "?0"^^xsd:string
]
] [ sp:object " " ;
sp:predicate rdf:first ;
sp:subject
[ sp:varName "?1"^^xsd:string
]
] [ sp:object () ;
sp:predicate rdf:rest ;
sp:subject
[ sp:varName "?1"^^xsd:string
]
])
] ;
ui:childIndex 0
] ;
ui:childIndex 0
] ;
ui:childIndex 0 ;
ui:template
[ sp:varName "template"^^xsd:string
]
]
] .
app:TreeTemplates
rdf:type spin:SelectTemplate ;
rdfs:comment """Base class for SELECT templates that are used to populate trees. There are two kinds of queries:
......@@ -7354,6 +7517,11 @@ arg:treeChildrenTemplate
rdfs:label "tree children template"^^xsd:string ;
rdfs:subPropertyOf sp:arg .
arg:treePathTemplate
rdf:type rdf:Property ;
rdfs:label "tree path template"^^xsd:string ;
rdfs:subPropertyOf sp:arg .
arg:treeRootsTemplate
rdf:type rdf:Property ;
rdfs:label "tree roots template"^^xsd:string ;
......@@ -7379,6 +7547,16 @@ arg:width
rdfs:label "width"^^xsd:string ;
rdfs:subPropertyOf sp:arg .
html:treedataprovider
rdf:type html:Attribute ;
rdfs:label "tree data provider"^^xsd:string ;
rdfs:subPropertyOf html:attributes .
html:treeroot
rdf:type html:Attribute ;
rdfs:label "tree root"^^xsd:string ;
rdfs:subPropertyOf html:attributes .
ui:SubjectWidgetRowClass
rdf:type rdfs:Class ;
rdfs:label "Subject widget row class"^^xsd:string ;
......
......@@ -339,6 +339,73 @@ function appReloadForm(resourceURI, queryGraphURI, linkElementId) {
/**
* Selects a given node in a given tree.
* Will expand if necessary, using a server-side shortest path algorithm.
* @param treeId the id of the tree
* @param nodeURI the URI of the resource to select
*/
function appSelectTreeNode(treeId, nodeURI) {
// TODO: Currently this only works on the Tree that was created last
// but not if multiple trees are on a page
var tree = $('#' + treeId);
var dataProviderURI = tree.attr('treedataprovider');
if(!dataProviderURI) {
alert('Error: Element with id ' + treeId + ' does not have treedataprovider attribute');
return;
}
var rootURI = tree.attr('treeroot');
// Do nothing if it's already selected
var sel = tree.jstree('get_selected');
if(sel) {
if(sel.attr('resource') == nodeURI) {
return;
}
}
// Load path to root from the server and then call helper function
var data = {
_format: 'json',
_viewClass: 'app:TreeShortestPathCallback',
dataProvider: '<' + dataProviderURI + '>',
node: '<' + nodeURI + '>'
};
if(rootURI) {
data.root = '<' + rootURI + '>';
}
$.get(uispinServlet, data, function(path) {
appSelectTreeNodeHelper(tree, tree, path, 0);
});
}
// Private helper function - walks an array, expanding nodes along the way
function appSelectTreeNodeHelper(tree, node, path, index) {
var next = path[index];
node.children("ul").children("li").each(function(i, o) {
var child = $(o);
if(child.attr('resource') == next) {
if(index == path.length - 1) {
// End reached: select this node
tree.jstree('select_node', child, true);
child[0].scrollIntoView();
}
else {
tree.jstree('open_node', child, function() {
appSelectTreeNodeHelper(tree, child, path, index + 1);
});
}
}
});
}
/**
* Submits a form and switches it to viewing mode when done.
* @param form the id of the form
* @param servlet the optional name of the servlet
......
......@@ -5,8 +5,7 @@
ui:view="{= ?dataProvider }"
arg:root="{= ?root }">
<!-- The div that will be turned into a jsTree below -->
<div id="{= ?id }" />
<div id="{= ?id }" treedataprovider="{= ?dataProvider }" treeroot="{= ?root }"/>
<script type="text/javascript">
$(function () {
......@@ -15,12 +14,7 @@
"plugins" : [
"themes",
"json_data",
"ui",
"crrm",
"cookies",
"search",
"types",
"hotkeys" ],
"ui" ],
"json_data" : {
"ajax" : {
......@@ -40,6 +34,10 @@
"themes" : {
"theme" : "classic"
},
"ui": {
"select_limit": 1
}
});
});
......