Showing
3 changed files
with
252 additions
and
9 deletions
| ... | @@ -580,9 +580,34 @@ app:ClassTreeDataProvider | ... | @@ -580,9 +580,34 @@ app:ClassTreeDataProvider |
| 580 | rdfs:label "Class tree data provider"^^xsd:string ; | 580 | rdfs:label "Class tree data provider"^^xsd:string ; |
| 581 | arg:treeChildrenTemplate | 581 | arg:treeChildrenTemplate |
| 582 | app:ClassTreeChildren ; | 582 | app:ClassTreeChildren ; |
| 583 | + arg:treePathTemplate | ||
| 584 | + app:ClassTreePath ; | ||
| 583 | arg:treeRootsTemplate | 585 | arg:treeRootsTemplate |
| 584 | app:ClassTreeRoots . | 586 | app:ClassTreeRoots . |
| 585 | 587 | ||
| 588 | +app:ClassTreePath | ||
| 589 | + rdf:type spin:SelectTemplate ; | ||
| 590 | + rdfs:label "Class tree path"^^xsd:string ; | ||
| 591 | + rdfs:subClassOf app:TreePathTemplates ; | ||
| 592 | + spin:body | ||
| 593 | + [ rdf:type sp:Select ; | ||
| 594 | + sp:resultVariables ([ sp:varName "path"^^xsd:string | ||
| 595 | + ]) ; | ||
| 596 | + sp:where ([ rdf:type sp:Bind ; | ||
| 597 | + sp:expression | ||
| 598 | + [ rdf:type spif:shortestObjectsPath ; | ||
| 599 | + sp:arg1 [ sp:varName "node"^^xsd:string | ||
| 600 | + ] ; | ||
| 601 | + sp:arg2 rdfs:subClassOf ; | ||
| 602 | + sp:arg3 [ sp:varName "root"^^xsd:string | ||
| 603 | + ] | ||
| 604 | + ] ; | ||
| 605 | + sp:variable | ||
| 606 | + [ sp:varName "path"^^xsd:string | ||
| 607 | + ] | ||
| 608 | + ]) | ||
| 609 | + ] . | ||
| 610 | + | ||
| 586 | app:ClassTreeRoots | 611 | app:ClassTreeRoots |
| 587 | rdf:type spin:SelectTemplate ; | 612 | rdf:type spin:SelectTemplate ; |
| 588 | rdfs:label "Class tree roots"^^xsd:string ; | 613 | rdfs:label "Class tree roots"^^xsd:string ; |
| ... | @@ -860,6 +885,7 @@ app:CustomEditForm | ... | @@ -860,6 +885,7 @@ app:CustomEditForm |
| 860 | ] ; | 885 | ] ; |
| 861 | ui:child | 886 | ui:child |
| 862 | [ rdf:type html:Form ; | 887 | [ rdf:type html:Form ; |
| 888 | + html:autocomplete "off"^^xsd:string ; | ||
| 863 | html:class "appForm ui-layout-content"^^xsd:string ; | 889 | html:class "appForm ui-layout-content"^^xsd:string ; |
| 864 | html:id [ sp:varName "fid"^^xsd:string | 890 | html:id [ sp:varName "fid"^^xsd:string |
| 865 | ] ; | 891 | ] ; |
| ... | @@ -3973,6 +3999,7 @@ app:SearchForm | ... | @@ -3973,6 +3999,7 @@ app:SearchForm |
| 3973 | ] ; | 3999 | ] ; |
| 3974 | ui:child | 4000 | ui:child |
| 3975 | [ rdf:type html:Form ; | 4001 | [ rdf:type html:Form ; |
| 4002 | + html:autocomplete "off"^^xsd:string ; | ||
| 3976 | html:class | 4003 | html:class |
| 3977 | [ rdf:type ui:concat ; | 4004 | [ rdf:type ui:concat ; |
| 3978 | sp:arg1 "appForm ui-layout-content "^^xsd:string ; | 4005 | sp:arg1 "appForm ui-layout-content "^^xsd:string ; |
| ... | @@ -5481,7 +5508,9 @@ app:TreeDataProvider | ... | @@ -5481,7 +5508,9 @@ app:TreeDataProvider |
| 5481 | rdf:type ui:NodeClass ; | 5508 | rdf:type ui:NodeClass ; |
| 5482 | rdfs:comment """Instances of this class are used as server callbacks to drive an app:Tree. | 5509 | rdfs:comment """Instances of this class are used as server callbacks to drive an app:Tree. |
| 5483 | 5510 | ||
| 5484 | -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 ; | 5511 | +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). |
| 5512 | + | ||
| 5513 | +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 ; | ||
| 5485 | rdfs:label "Tree data provider"^^xsd:string ; | 5514 | rdfs:label "Tree data provider"^^xsd:string ; |
| 5486 | rdfs:subClassOf app:TreeElements ; | 5515 | rdfs:subClassOf app:TreeElements ; |
| 5487 | spin:constraint | 5516 | spin:constraint |
| ... | @@ -5492,6 +5521,12 @@ A TreeDataProvider is backed by two SELECT queries - one to get the roots, and o | ... | @@ -5492,6 +5521,12 @@ A TreeDataProvider is backed by two SELECT queries - one to get the roots, and o |
| 5492 | ] ; | 5521 | ] ; |
| 5493 | spin:constraint | 5522 | spin:constraint |
| 5494 | [ rdf:type spl:Argument ; | 5523 | [ rdf:type spl:Argument ; |
| 5524 | + 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 ; | ||
| 5525 | + spl:predicate arg:treePathTemplate ; | ||
| 5526 | + spl:valueType spin:Template | ||
| 5527 | + ] ; | ||
| 5528 | + spin:constraint | ||
| 5529 | + [ rdf:type spl:Argument ; | ||
| 5495 | 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 ; | 5530 | 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 ; |
| 5496 | spl:optional "true"^^xsd:boolean ; | 5531 | spl:optional "true"^^xsd:boolean ; |
| 5497 | spl:predicate arg:treeRootsTemplate ; | 5532 | spl:predicate arg:treeRootsTemplate ; |
| ... | @@ -5583,6 +5618,25 @@ app:TreeElements | ... | @@ -5583,6 +5618,25 @@ app:TreeElements |
| 5583 | rdfs:label "Tree elements"^^xsd:string ; | 5618 | rdfs:label "Tree elements"^^xsd:string ; |
| 5584 | rdfs:subClassOf app:Elements . | 5619 | rdfs:subClassOf app:Elements . |
| 5585 | 5620 | ||
| 5621 | +app:TreePathTemplates | ||
| 5622 | + rdf:type spin:SelectTemplate ; | ||
| 5623 | + rdfs:comment "An abstract superclass for SPIN templates used by TreeDataProviders to find a path from a node to a root."^^xsd:string ; | ||
| 5624 | + rdfs:label "Tree path templates"^^xsd:string ; | ||
| 5625 | + rdfs:subClassOf spin:SelectTemplates ; | ||
| 5626 | + spin:constraint | ||
| 5627 | + [ rdf:type spl:Argument ; | ||
| 5628 | + rdfs:comment "The node to start traversal at."^^xsd:string ; | ||
| 5629 | + spl:predicate arg:node ; | ||
| 5630 | + spl:valueType rdfs:Resource | ||
| 5631 | + ] ; | ||
| 5632 | + spin:constraint | ||
| 5633 | + [ rdf:type spl:Argument ; | ||
| 5634 | + rdfs:comment "An optional root resource to stop traversal at."^^xsd:string ; | ||
| 5635 | + spl:optional "true"^^xsd:boolean ; | ||
| 5636 | + spl:predicate arg:root ; | ||
| 5637 | + spl:valueType rdfs:Resource | ||
| 5638 | + ] . | ||
| 5639 | + | ||
| 5586 | app:TreeRootsTemplates | 5640 | app:TreeRootsTemplates |
| 5587 | rdf:type spin:SelectTemplate ; | 5641 | rdf:type spin:SelectTemplate ; |
| 5588 | rdfs:comment "Abstract superclass for queries that can deliver the roots of a tree."^^xsd:string ; | 5642 | rdfs:comment "Abstract superclass for queries that can deliver the roots of a tree."^^xsd:string ; |
| ... | @@ -5596,6 +5650,115 @@ app:TreeRootsTemplates | ... | @@ -5596,6 +5650,115 @@ app:TreeRootsTemplates |
| 5596 | spl:valueType rdfs:Resource | 5650 | spl:valueType rdfs:Resource |
| 5597 | ] . | 5651 | ] . |
| 5598 | 5652 | ||
| 5653 | +app:TreeShortestPathCallback | ||
| 5654 | + rdf:type ui:NodeClass ; | ||
| 5655 | + 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 ; | ||
| 5656 | + rdfs:label "Tree shortest path callback"^^xsd:string ; | ||
| 5657 | + rdfs:subClassOf app:TreeElements ; | ||
| 5658 | + spin:constraint | ||
| 5659 | + [ rdf:type spl:Argument ; | ||
| 5660 | + rdfs:comment "The TreeDataProvider that contains the pathExpression needed to walk to the root."^^xsd:string ; | ||
| 5661 | + spl:predicate arg:dataProvider ; | ||
| 5662 | + spl:valueType app:TreeDataProvider | ||
| 5663 | + ] ; | ||
| 5664 | + spin:constraint | ||
| 5665 | + [ rdf:type spl:Argument ; | ||
| 5666 | + rdfs:comment "The node resource to start traversal at."^^xsd:string ; | ||
| 5667 | + spl:predicate arg:node ; | ||
| 5668 | + spl:valueType rdfs:Resource | ||
| 5669 | + ] ; | ||
| 5670 | + spin:constraint | ||
| 5671 | + [ rdf:type spl:Argument ; | ||
| 5672 | + rdfs:comment "The root resource to stop at."^^xsd:string ; | ||
| 5673 | + spl:optional "true"^^xsd:boolean ; | ||
| 5674 | + spl:predicate arg:root ; | ||
| 5675 | + spl:valueType rdfs:Resource | ||
| 5676 | + ] ; | ||
| 5677 | + ui:prototype | ||
| 5678 | + [ rdf:type ui:group ; | ||
| 5679 | + let:template | ||
| 5680 | + [ rdf:type sp:Select ; | ||
| 5681 | + sp:resultVariables ([ sp:varName "template"^^xsd:string | ||
| 5682 | + ]) ; | ||
| 5683 | + sp:where ([ rdf:type sp:NamedGraph ; | ||
| 5684 | + sp:elements ([ sp:object | ||
| 5685 | + [ sp:varName "template"^^xsd:string | ||
| 5686 | + ] ; | ||
| 5687 | + sp:predicate arg:treePathTemplate ; | ||
| 5688 | + sp:subject | ||
| 5689 | + [ sp:varName "dataProvider"^^xsd:string | ||
| 5690 | + ] | ||
| 5691 | + ]) ; | ||
| 5692 | + sp:graphNameNode ui:graph | ||
| 5693 | + ]) | ||
| 5694 | + ] ; | ||
| 5695 | + ui:child | ||
| 5696 | + [ rdf:type ui:call ; | ||
| 5697 | + arg:node | ||
| 5698 | + [ sp:varName "node"^^xsd:string | ||
| 5699 | + ] ; | ||
| 5700 | + arg:root | ||
| 5701 | + [ sp:varName "root"^^xsd:string | ||
| 5702 | + ] ; | ||
| 5703 | + ui:child | ||
| 5704 | + [ rdf:type ui:group ; | ||
| 5705 | + let:path | ||
| 5706 | + [ rdf:type spr:cell ; | ||
| 5707 | + sp:arg1 [ sp:varName "rs"^^xsd:string | ||
| 5708 | + ] ; | ||
| 5709 | + sp:arg2 0 ; | ||
| 5710 | + sp:arg3 0 | ||
| 5711 | + ] ; | ||
| 5712 | + ui:child | ||
| 5713 | + [ rdf:type swon:RSArray ; | ||
| 5714 | + arg:resultSet | ||
| 5715 | + [ rdf:type sp:Select ; | ||
| 5716 | + sp:resultVariables ([ sp:varName "value"^^xsd:string | ||
| 5717 | + ]) ; | ||
| 5718 | + sp:where ([ sp:object | ||
| 5719 | + [ sp:varName "?0"^^xsd:string | ||
| 5720 | + ] ; | ||
| 5721 | + sp:predicate spif:split ; | ||
| 5722 | + sp:subject | ||
| 5723 | + [ sp:varName "value"^^xsd:string | ||
| 5724 | + ] | ||
| 5725 | + ] [ sp:object | ||
| 5726 | + [ sp:varName "path"^^xsd:string | ||
| 5727 | + ] ; | ||
| 5728 | + sp:predicate rdf:first ; | ||
| 5729 | + sp:subject | ||
| 5730 | + [ sp:varName "?0"^^xsd:string | ||
| 5731 | + ] | ||
| 5732 | + ] [ sp:object | ||
| 5733 | + [ sp:varName "?1"^^xsd:string | ||
| 5734 | + ] ; | ||
| 5735 | + sp:predicate rdf:rest ; | ||
| 5736 | + sp:subject | ||
| 5737 | + [ sp:varName "?0"^^xsd:string | ||
| 5738 | + ] | ||
| 5739 | + ] [ sp:object " " ; | ||
| 5740 | + sp:predicate rdf:first ; | ||
| 5741 | + sp:subject | ||
| 5742 | + [ sp:varName "?1"^^xsd:string | ||
| 5743 | + ] | ||
| 5744 | + ] [ sp:object () ; | ||
| 5745 | + sp:predicate rdf:rest ; | ||
| 5746 | + sp:subject | ||
| 5747 | + [ sp:varName "?1"^^xsd:string | ||
| 5748 | + ] | ||
| 5749 | + ]) | ||
| 5750 | + ] ; | ||
| 5751 | + ui:childIndex 0 | ||
| 5752 | + ] ; | ||
| 5753 | + ui:childIndex 0 | ||
| 5754 | + ] ; | ||
| 5755 | + ui:childIndex 0 ; | ||
| 5756 | + ui:template | ||
| 5757 | + [ sp:varName "template"^^xsd:string | ||
| 5758 | + ] | ||
| 5759 | + ] | ||
| 5760 | + ] . | ||
| 5761 | + | ||
| 5599 | app:TreeTemplates | 5762 | app:TreeTemplates |
| 5600 | rdf:type spin:SelectTemplate ; | 5763 | rdf:type spin:SelectTemplate ; |
| 5601 | rdfs:comment """Base class for SELECT templates that are used to populate trees. There are two kinds of queries: | 5764 | 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 | ... | @@ -7354,6 +7517,11 @@ arg:treeChildrenTemplate |
| 7354 | rdfs:label "tree children template"^^xsd:string ; | 7517 | rdfs:label "tree children template"^^xsd:string ; |
| 7355 | rdfs:subPropertyOf sp:arg . | 7518 | rdfs:subPropertyOf sp:arg . |
| 7356 | 7519 | ||
| 7520 | +arg:treePathTemplate | ||
| 7521 | + rdf:type rdf:Property ; | ||
| 7522 | + rdfs:label "tree path template"^^xsd:string ; | ||
| 7523 | + rdfs:subPropertyOf sp:arg . | ||
| 7524 | + | ||
| 7357 | arg:treeRootsTemplate | 7525 | arg:treeRootsTemplate |
| 7358 | rdf:type rdf:Property ; | 7526 | rdf:type rdf:Property ; |
| 7359 | rdfs:label "tree roots template"^^xsd:string ; | 7527 | rdfs:label "tree roots template"^^xsd:string ; |
| ... | @@ -7379,6 +7547,16 @@ arg:width | ... | @@ -7379,6 +7547,16 @@ arg:width |
| 7379 | rdfs:label "width"^^xsd:string ; | 7547 | rdfs:label "width"^^xsd:string ; |
| 7380 | rdfs:subPropertyOf sp:arg . | 7548 | rdfs:subPropertyOf sp:arg . |
| 7381 | 7549 | ||
| 7550 | +html:treedataprovider | ||
| 7551 | + rdf:type html:Attribute ; | ||
| 7552 | + rdfs:label "tree data provider"^^xsd:string ; | ||
| 7553 | + rdfs:subPropertyOf html:attributes . | ||
| 7554 | + | ||
| 7555 | +html:treeroot | ||
| 7556 | + rdf:type html:Attribute ; | ||
| 7557 | + rdfs:label "tree root"^^xsd:string ; | ||
| 7558 | + rdfs:subPropertyOf html:attributes . | ||
| 7559 | + | ||
| 7382 | ui:SubjectWidgetRowClass | 7560 | ui:SubjectWidgetRowClass |
| 7383 | rdf:type rdfs:Class ; | 7561 | rdf:type rdfs:Class ; |
| 7384 | rdfs:label "Subject widget row class"^^xsd:string ; | 7562 | rdfs:label "Subject widget row class"^^xsd:string ; | ... | ... |
| ... | @@ -339,6 +339,73 @@ function appReloadForm(resourceURI, queryGraphURI, linkElementId) { | ... | @@ -339,6 +339,73 @@ function appReloadForm(resourceURI, queryGraphURI, linkElementId) { |
| 339 | 339 | ||
| 340 | 340 | ||
| 341 | /** | 341 | /** |
| 342 | + * Selects a given node in a given tree. | ||
| 343 | + * Will expand if necessary, using a server-side shortest path algorithm. | ||
| 344 | + * @param treeId the id of the tree | ||
| 345 | + * @param nodeURI the URI of the resource to select | ||
| 346 | + */ | ||
| 347 | +function appSelectTreeNode(treeId, nodeURI) { | ||
| 348 | + | ||
| 349 | + // TODO: Currently this only works on the Tree that was created last | ||
| 350 | + // but not if multiple trees are on a page | ||
| 351 | + | ||
| 352 | + var tree = $('#' + treeId); | ||
| 353 | + var dataProviderURI = tree.attr('treedataprovider'); | ||
| 354 | + if(!dataProviderURI) { | ||
| 355 | + alert('Error: Element with id ' + treeId + ' does not have treedataprovider attribute'); | ||
| 356 | + return; | ||
| 357 | + } | ||
| 358 | + | ||
| 359 | + var rootURI = tree.attr('treeroot'); | ||
| 360 | + | ||
| 361 | + // Do nothing if it's already selected | ||
| 362 | + var sel = tree.jstree('get_selected'); | ||
| 363 | + if(sel) { | ||
| 364 | + if(sel.attr('resource') == nodeURI) { | ||
| 365 | + return; | ||
| 366 | + } | ||
| 367 | + } | ||
| 368 | + | ||
| 369 | + // Load path to root from the server and then call helper function | ||
| 370 | + var data = { | ||
| 371 | + _format: 'json', | ||
| 372 | + _viewClass: 'app:TreeShortestPathCallback', | ||
| 373 | + dataProvider: '<' + dataProviderURI + '>', | ||
| 374 | + node: '<' + nodeURI + '>' | ||
| 375 | + }; | ||
| 376 | + if(rootURI) { | ||
| 377 | + data.root = '<' + rootURI + '>'; | ||
| 378 | + } | ||
| 379 | + $.get(uispinServlet, data, function(path) { | ||
| 380 | + appSelectTreeNodeHelper(tree, tree, path, 0); | ||
| 381 | + }); | ||
| 382 | +} | ||
| 383 | + | ||
| 384 | + | ||
| 385 | +// Private helper function - walks an array, expanding nodes along the way | ||
| 386 | +function appSelectTreeNodeHelper(tree, node, path, index) { | ||
| 387 | + | ||
| 388 | + var next = path[index]; | ||
| 389 | + | ||
| 390 | + node.children("ul").children("li").each(function(i, o) { | ||
| 391 | + var child = $(o); | ||
| 392 | + if(child.attr('resource') == next) { | ||
| 393 | + if(index == path.length - 1) { | ||
| 394 | + // End reached: select this node | ||
| 395 | + tree.jstree('select_node', child, true); | ||
| 396 | + child[0].scrollIntoView(); | ||
| 397 | + } | ||
| 398 | + else { | ||
| 399 | + tree.jstree('open_node', child, function() { | ||
| 400 | + appSelectTreeNodeHelper(tree, child, path, index + 1); | ||
| 401 | + }); | ||
| 402 | + } | ||
| 403 | + } | ||
| 404 | + }); | ||
| 405 | +} | ||
| 406 | + | ||
| 407 | + | ||
| 408 | +/** | ||
| 342 | * Submits a form and switches it to viewing mode when done. | 409 | * Submits a form and switches it to viewing mode when done. |
| 343 | * @param form the id of the form | 410 | * @param form the id of the form |
| 344 | * @param servlet the optional name of the servlet | 411 | * @param servlet the optional name of the servlet | ... | ... |
| ... | @@ -5,8 +5,7 @@ | ... | @@ -5,8 +5,7 @@ |
| 5 | ui:view="{= ?dataProvider }" | 5 | ui:view="{= ?dataProvider }" |
| 6 | arg:root="{= ?root }"> | 6 | arg:root="{= ?root }"> |
| 7 | 7 | ||
| 8 | - <!-- The div that will be turned into a jsTree below --> | 8 | + <div id="{= ?id }" treedataprovider="{= ?dataProvider }" treeroot="{= ?root }"/> |
| 9 | - <div id="{= ?id }" /> | ||
| 10 | 9 | ||
| 11 | <script type="text/javascript"> | 10 | <script type="text/javascript"> |
| 12 | $(function () { | 11 | $(function () { |
| ... | @@ -15,12 +14,7 @@ | ... | @@ -15,12 +14,7 @@ |
| 15 | "plugins" : [ | 14 | "plugins" : [ |
| 16 | "themes", | 15 | "themes", |
| 17 | "json_data", | 16 | "json_data", |
| 18 | - "ui", | 17 | + "ui" ], |
| 19 | - "crrm", | ||
| 20 | - "cookies", | ||
| 21 | - "search", | ||
| 22 | - "types", | ||
| 23 | - "hotkeys" ], | ||
| 24 | 18 | ||
| 25 | "json_data" : { | 19 | "json_data" : { |
| 26 | "ajax" : { | 20 | "ajax" : { |
| ... | @@ -40,6 +34,10 @@ | ... | @@ -40,6 +34,10 @@ |
| 40 | 34 | ||
| 41 | "themes" : { | 35 | "themes" : { |
| 42 | "theme" : "classic" | 36 | "theme" : "classic" |
| 37 | + }, | ||
| 38 | + | ||
| 39 | + "ui": { | ||
| 40 | + "select_limit": 1 | ||
| 43 | } | 41 | } |
| 44 | }); | 42 | }); |
| 45 | }); | 43 | }); | ... | ... |
-
Please register or login to post a comment