From 36fab50825f5e2e80cf5d27acf7fedf8be6216ed Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 25 Nov 2014 16:53:22 -0800 Subject: [PATCH] [Common UI] Add in-line docs for Browse Add in-line docs for bundle platform/commonUI/browse, which implements Browse mode, one of the common user interface bundles being transitioned in WTD-574. --- README.md | 10 ++- platform/commonUI/browse/bundle.json | 2 +- .../browse/src/ViewSwitcherController.js | 3 +- .../browse/src/creation/CreationService.js | 73 ++++++++++++------- .../browse/src/navigation/NavigateAction.js | 21 ++++-- .../src/navigation/NavigationService.js | 28 ++++++- .../browse/src/windowing/FullscreenAction.js | 10 ++- .../browse/src/windowing/NewWindowAction.js | 8 +- 8 files changed, 116 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index f0b0db1670..c6791d3d06 100644 --- a/README.md +++ b/README.md @@ -95,13 +95,21 @@ Run as `mvn clean install`. Certain terms are used throughout Open MCT Web with consistent meanings or conventions. Any deviations from the below are issues and should be addressed (either by updating this glossary or changing code to reflect -correct usage.) +correct usage.) Other developer documentation, particularly in-line +documentation, may presume an understanding of these terms. * _bundle_: A bundle is a removable, reusable grouping of software elements. The application is composed of bundles. Plug-ins are bundles. For more information, refer to framework documentation (under `platform/framework`.) * _capability_: An object which exposes dynamic behavior or non-persistent state associated with a domain object. +* _composition_: In the context of a domain object, this refers to the set of + other domain objects that compose or are contained by that object. A domain + object's composition is the set of domain objects that should appear + immediately beneath it in a tree hierarchy. A domain object's composition is + described in its model as an array of id's; its composition capability + provides a means to retrieve the actual domain object instances associated + with these identifiers asynchronously. * _description_: When used as an object property, this refers to the human-readable description of a thing; usually a single sentence or short paragraph. (Most often used in the context of extensions, domain diff --git a/platform/commonUI/browse/bundle.json b/platform/commonUI/browse/bundle.json index 36f5745de7..eea4be86d8 100644 --- a/platform/commonUI/browse/bundle.json +++ b/platform/commonUI/browse/bundle.json @@ -79,7 +79,7 @@ { "key": "navigate", "implementation": "navigation/NavigateAction.js", - "depends": [ "navigationService" ] + "depends": [ "navigationService", "$q" ] }, { "key": "window", diff --git a/platform/commonUI/browse/src/ViewSwitcherController.js b/platform/commonUI/browse/src/ViewSwitcherController.js index 6a3852299e..058aaaa360 100644 --- a/platform/commonUI/browse/src/ViewSwitcherController.js +++ b/platform/commonUI/browse/src/ViewSwitcherController.js @@ -9,7 +9,8 @@ define( "use strict"; /** - * + * Controller for the view switcher; populates and maintains a list + * of applicable views for a represented domain object. * @constructor */ function ViewSwitcherController($scope) { diff --git a/platform/commonUI/browse/src/creation/CreationService.js b/platform/commonUI/browse/src/creation/CreationService.js index 301ec7f0e8..14492d1210 100644 --- a/platform/commonUI/browse/src/creation/CreationService.js +++ b/platform/commonUI/browse/src/creation/CreationService.js @@ -15,11 +15,16 @@ define( /** * The creation service is responsible for instantiating and - * persisting new domain objects. This is + * persisting new domain objects. Handles all actual object + * mutation and persistence associated with domain object + * creation. * @constructor */ function CreationService(persistenceService, $q, $log) { + // Persist the new domain object's model; it will be fully + // constituted as a domain object when loaded back, as all + // domain object models are. function doPersist(space, id, model) { return persistenceService.createObject( space, @@ -28,60 +33,72 @@ define( ).then(function () { return id; }); } - function addToComposition(id, parent) { + // Add the newly-created object's id to the parent's + // composition, so that it will subsequently appear + // as a child contained by that parent. + function addToComposition(id, parent, parentPersistence) { var mutatationResult = parent.useCapability("mutation", function (model) { if (Array.isArray(model.composition)) { + // Don't add if the id is already there if (model.composition.indexOf(id) === -1) { model.composition.push(id); } } else { + // This is abnormal; composition should be an array $log.warn(NO_COMPOSITION_WARNING + parent.getId()); + return false; // Cancel mutation } }); return $q.when(mutatationResult).then(function (result) { - var persistence = parent.getCapability("persistence"); - if (!result) { $log.error("Could not mutate " + parent.getId()); - } - - if (!persistence) { - $log.error([ - "Expected to be able to persist ", - parent.getId(), - " but could not." - ].join("")); return undefined; } - return persistence.persist(); + return parentPersistence.persist(); }); } + // Create a new domain object with the provided model as a + // member of the specified parent's composition function createObject(model, parent) { - var persistence = parent.getCapability("persistence"), - result = $q.defer(), - space; + var persistence = parent.getCapability("persistence"); - if (persistence) { - space = persistence.getSpace(); - return $q.when( - uuid() - ).then(function (id) { - return doPersist(space, id, model); - }).then(function (id) { - return addToComposition(id, parent); - }); - } else { + // We need the parent's persistence capability to determine + // what space to create the new object's model in. + if (!persistence) { $log.warn(NON_PERSISTENT_WARNING); - $q.reject(new Error(NON_PERSISTENT_WARNING)); + return $q.reject(new Error(NON_PERSISTENT_WARNING)); } - return result.promise; + // We create a new domain object in three sequential steps: + // 1. Get a new UUID for the object + // 2. Create a model with that ID in the persistence space + // 3. Add that ID to + return $q.when( + uuid() + ).then(function (id) { + return doPersist(persistence.getSpace(), id, model); + }).then(function (id) { + return addToComposition(id, parent, persistence); + }); } return { + /** + * Create a new domain object with the provided model, as + * a member of the provided parent domain object's composition. + * This parent will additionally determine which persistence + * space an object is created within (as it is possible to + * have multiple persistence spaces attached.) + * + * @param {object} model the model for the newly-created + * domain object + * @param {DomainObject} parent the domain object which + * should contain the newly-created domain object + * in its composition + */ createObject: createObject }; } diff --git a/platform/commonUI/browse/src/navigation/NavigateAction.js b/platform/commonUI/browse/src/navigation/NavigateAction.js index 101814201f..a5be1d4616 100644 --- a/platform/commonUI/browse/src/navigation/NavigateAction.js +++ b/platform/commonUI/browse/src/navigation/NavigateAction.js @@ -9,23 +9,34 @@ define( "use strict"; /** - * + * The navigate action navigates to a specific domain object. * @constructor */ - function NavigateAction(navigationService, context) { + function NavigateAction(navigationService, $q, context) { var domainObject = context.domainObject; function perform() { - return Promise.resolve( - navigationService.setNavigation(domainObject) - ); + // Set navigation, and wrap like a promise + return $q.when(navigationService.setNavigation(domainObject)); } return { + /** + * Navigate to the object described in the context. + * @returns {Promise} a promise that is resolved once the + * navigation has been updated + */ perform: perform }; } + /** + * Navigate as an action is only applicable when a domain object + * is described in the action context. + * @param {ActionContext} context the context in which the action + * will be performed + * @returns true if applicable + */ NavigateAction.appliesTo = function (context) { return context.domainObject !== undefined; }; diff --git a/platform/commonUI/browse/src/navigation/NavigationService.js b/platform/commonUI/browse/src/navigation/NavigationService.js index 8b237a645e..3f8e9f41ab 100644 --- a/platform/commonUI/browse/src/navigation/NavigationService.js +++ b/platform/commonUI/browse/src/navigation/NavigationService.js @@ -9,17 +9,20 @@ define( "use strict"; /** - * + * The navigation service maintains the application's current + * navigation state, and allows listening for changes thereto. * @constructor */ function NavigationService() { var navigated, callbacks = []; + // Getter for current navigation function getNavigation() { return navigated; } + // Setter for navigation; invokes callbacks function setNavigation(value) { navigated = value; callbacks.forEach(function (callback) { @@ -27,10 +30,12 @@ define( }); } + // Adds a callback function addListener(callback) { callbacks.push(callback); } + // Filters out a callback function removeListener(callback) { callbacks = callbacks.filter(function (cb) { return cb !== callback; @@ -38,9 +43,30 @@ define( } return { + /** + * Get the current navigation state. + */ getNavigation: getNavigation, + /** + * Set the current navigation state. Thiswill invoke listeners. + * @param {DomainObject} value the domain object to navigate + * to + */ setNavigation: setNavigation, + /** + * Listen for changes in navigation. The passed callback will + * be invoked with the new domain object of navigation when + * this changes. + * @param {function} callback the callback to invoke when + * navigation state changes + */ addListener: addListener, + /** + * Stop listening for changes in navigation state. + * @param {function} callback the callback which should + * no longer be invoked when navigation state + * changes + */ removeListener: removeListener }; } diff --git a/platform/commonUI/browse/src/windowing/FullscreenAction.js b/platform/commonUI/browse/src/windowing/FullscreenAction.js index 50f1e389ab..dd1e113396 100644 --- a/platform/commonUI/browse/src/windowing/FullscreenAction.js +++ b/platform/commonUI/browse/src/windowing/FullscreenAction.js @@ -12,14 +12,22 @@ define( EXIT_FULLSCREEN = "Exit full screen mode."; /** - * + * The fullscreen action toggles between fullscreen display + * and regular in-window display. * @constructor */ function FullscreenAction(context) { return { + /** + * Toggle full screen state + */ perform: function () { screenfull.toggle(); }, + /** + * Get metadata about this action, including the + * applicable glyph to display. + */ getMetadata: function () { // We override getMetadata, because the glyph and // description need to be determined at run-time diff --git a/platform/commonUI/browse/src/windowing/NewWindowAction.js b/platform/commonUI/browse/src/windowing/NewWindowAction.js index 45a7b48c8a..fe96356f80 100644 --- a/platform/commonUI/browse/src/windowing/NewWindowAction.js +++ b/platform/commonUI/browse/src/windowing/NewWindowAction.js @@ -9,11 +9,17 @@ define( "use strict"; /** - * + * The new window action allows a domain object to be opened + * into a new browser window. (Currently this is a stub, present + * to allow the control to appear in the appropriate location in + * the user interface.) * @constructor */ function NewWindowAction($window) { return { + /** + * Open the object in a new window (currently a stub) + */ perform: function () { $window.alert("Not yet functional. This will open objects in a new window."); }