diff --git a/README.md b/README.md
index 441b275acf..f0b0db1670 100644
--- a/README.md
+++ b/README.md
@@ -122,8 +122,12 @@ correct usage.)
* _name_: When used as an object property, this refers to the human-readable
name for a thing. (Most often used in the context of extensions, domain
object models, or other similar application-specific objects.)
+* _navigation_: Refers to the current state of the application with respect
+ to the user's expressed interest in a specific domain object; e.g. when
+ a user clicks on a domain object in the tree, they are _navigating_ to
+ it, and it is thereafter considered the _navigated_ object (until the
+ user makes another such choice.)
* _space_: A name used to identify a persistence store. Interactions with
persistence with generally involve a `space` parameter in some form, to
distinguish multiple persistence stores from one another (for cases
where there are multiple valid persistence locations available.)
-
\ No newline at end of file
diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json
index 2bf8f37c47..f5c0114fb0 100644
--- a/platform/commonUI/general/bundle.json
+++ b/platform/commonUI/general/bundle.json
@@ -68,8 +68,8 @@
"templateUrl": "templates/test.html"
},
{
- "key": "tree-item",
- "templateUrl": "templates/tree-item.html",
+ "key": "tree-node",
+ "templateUrl": "templates/tree-node.html",
"uses": [ "action" ]
},
{
diff --git a/platform/commonUI/general/res/templates/tree-item.html b/platform/commonUI/general/res/templates/tree-node.html
similarity index 100%
rename from platform/commonUI/general/res/templates/tree-item.html
rename to platform/commonUI/general/res/templates/tree-node.html
diff --git a/platform/commonUI/general/res/templates/tree.html b/platform/commonUI/general/res/templates/tree.html
index 8a60580c7b..16ffb7d936 100644
--- a/platform/commonUI/general/res/templates/tree.html
+++ b/platform/commonUI/general/res/templates/tree.html
@@ -1,6 +1,6 @@
diff --git a/platform/commonUI/general/src/TreeNodeController.js b/platform/commonUI/general/src/TreeNodeController.js
index 0f4d3a370e..9310b212c1 100644
--- a/platform/commonUI/general/src/TreeNodeController.js
+++ b/platform/commonUI/general/src/TreeNodeController.js
@@ -9,7 +9,24 @@ define(
"use strict";
/**
+ * The TreeNodeController supports the tree node representation;
+ * a tree node has a label for the current object as well as a
+ * subtree which shows (and is not loaded until) the node is
+ * expanded.
*
+ * This controller tracks the following, so that the tree node
+ * template may update its state accordingly:
+ *
+ * * Whether or not the tree node has ever been expanded (this
+ * is used to lazily load, exactly once, the subtree)
+ * * Whether or not the node is currently the domain object
+ * of navigation (this gets highlighted differently to
+ * provide the user with visual feedback.)
+ *
+ * Additionally, this controller will automatically trigger
+ * node expansion when this tree node's _subtree_ will contain
+ * the navigated object (recursively, this becomes an
+ * expand-to-show-navigated-object behavior.)
* @constructor
*/
function TreeNodeController($scope, navigationService) {
@@ -17,30 +34,45 @@ define(
isNavigated = false,
hasBeenExpanded = false;
- function idsEqual(objA, objB) {
- return (objA === objB) ||
- (objA && objB && (objA.getId() === objB.getId()));
+ // Look up the id for a domain object. A convenience
+ // for mapping; additionally does some undefined-checking.
+ function getId(obj) {
+ return obj && obj.getId && obj.getId();
}
+ // Check if two domain objects have the same ID
+ function idsEqual(objA, objB) {
+ return getId(objA) === getId(objB);
+ }
+
+ // Get the parent of a domain object, as reported by
+ // its context capability. This is used to distinguish
+ // two different instances of a domain object that have
+ // been reached in different ways.
function parentOf(domainObject) {
var context = domainObject &&
domainObject.getCapability("context");
return context && context.getParent();
}
- function getId(obj) {
- return obj.getId();
- }
-
// Verify that id paths are equivalent, staring at
// index, ending at the end of the node path.
function checkPath(nodePath, navPath, index) {
index = index || 0;
+
+ // The paths overlap if we have made it past the
+ // end of the node's path; otherwise, check the
+ // id at the current index for equality and perform
+ // a recursive step for subsequent ids in the paths,
+ // until we exceed path length or hit a mismatch.
return (index >= nodePath.length) ||
(idsEqual(navPath[index], nodePath[index]) &&
checkPath(nodePath, navPath, index + 1));
}
+ // Check if the navigated object is in the subtree of this
+ // node's domain object, by comparing the paths reported
+ // by their context capability.
function isOnNavigationPath(nodeObject, navObject) {
var nodeContext = nodeObject &&
nodeObject.getCapability('context'),
@@ -58,14 +90,20 @@ define(
return false; // No context to judge by
}
+ // Consider the currently-navigated object and update
+ // parameters which support display.
function checkNavigation() {
var nodeObject = $scope.domainObject;
+ // Check if we are the navigated object. Check the parent
+ // as well to make sure we are the same instance of the
+ // navigated object.
isNavigated =
idsEqual(nodeObject, navigatedObject) &&
idsEqual(parentOf(nodeObject), parentOf(navigatedObject));
- // Expand if necessary
+ // Expand if necessary (if the navigated object will
+ // be in this node's subtree)
if (isOnNavigationPath(nodeObject, navigatedObject) &&
$scope.toggle !== undefined) {
$scope.toggle.setState(true);
@@ -73,11 +111,14 @@ define(
}
}
+ // Callback for the navigation service; track the currently
+ // navigated object and update display parameters as needed.
function setNavigation(object) {
navigatedObject = object;
checkNavigation();
}
+ // Listen for changes which will effect display parameters
navigationService.addListener(setNavigation);
$scope.$on("$destroy", function () {
navigationService.removeListener(setNavigation);
@@ -85,12 +126,26 @@ define(
$scope.$watch("domainObject", checkNavigation);
return {
+ /**
+ * This method should be called when a node is expanded
+ * to record that this has occurred, to support one-time
+ * lazy loading of the node's subtree.
+ */
trackExpansion: function () {
hasBeenExpanded = true;
},
+ /**
+ * Check if this not has ever been expanded.
+ * @returns true if it has been expanded
+ */
hasBeenExpanded: function () {
return hasBeenExpanded;
},
+ /**
+ * Check whether or not the domain object represented by
+ * this tree node is currently the navigated object.
+ * @returns true if this is the navigated object
+ */
isNavigated: function () {
return isNavigated;
}