-
diff --git a/platform/commonUI/browse/res/templates/view-object.html b/platform/commonUI/browse/res/templates/view-object.html
new file mode 100644
index 0000000000..b670e1645e
--- /dev/null
+++ b/platform/commonUI/browse/res/templates/view-object.html
@@ -0,0 +1,33 @@
+
+
+
+
diff --git a/platform/commonUI/browse/src/BrowseController.js b/platform/commonUI/browse/src/BrowseController.js
index d1d5aa92cc..9f1834f80d 100644
--- a/platform/commonUI/browse/src/BrowseController.js
+++ b/platform/commonUI/browse/src/BrowseController.js
@@ -60,13 +60,6 @@ define(
($route.current.params.ids || defaultPath).split("/")
);
- function isDirty(){
- var editorCapability = $scope.navigatedObject &&
- $scope.navigatedObject.getCapability("editor"),
- hasChanges = editorCapability && editorCapability.dirty();
- return hasChanges;
- }
-
function updateRoute(domainObject) {
var priorRoute = $route.current,
// Act as if params HADN'T changed to avoid page reload
@@ -83,9 +76,7 @@ define(
// urlService.urlForLocation used to adjust current
// path to new, addressed, path based on
// domainObject
- $location.path(urlService.urlForLocation("browse",
- domainObject.hasCapability('editor') ?
- domainObject.getOriginalObject() : domainObject));
+ $location.path(urlService.urlForLocation("browse", domainObject));
}
@@ -97,17 +88,15 @@ define(
return;
}
- if (isDirty() && !confirm(CONFIRM_MSG)) {
- $scope.treeModel.selectedObject = $scope.navigatedObject;
- navigationService.setNavigation($scope.navigatedObject);
- } else {
- if ($scope.navigatedObject && $scope.navigatedObject.hasCapability("editor")){
- $scope.navigatedObject.getCapability("editor").cancel();
- }
+ if (navigationService.setNavigation(domainObject)) {
$scope.navigatedObject = domainObject;
$scope.treeModel.selectedObject = domainObject;
- navigationService.setNavigation(domainObject);
updateRoute(domainObject);
+ } else {
+ //If navigation was unsuccessful (ie. blocked), reset
+ // the selected object in the tree to the currently
+ // navigated object
+ $scope.treeModel.selectedObject = $scope.navigatedObject ;
}
}
@@ -184,18 +173,13 @@ define(
selectedObject: navigationService.getNavigation()
};
- $scope.beforeUnloadWarning = function() {
- return isDirty() ?
- "Unsaved changes will be lost if you leave this page." :
- undefined;
- };
-
// Listen for changes in navigation state.
navigationService.addListener(setNavigation);
- // Also listen for changes which come from the tree
+ // Also listen for changes which come from the tree. Changes in
+ // the tree will trigger a change in browse navigation state.
$scope.$watch("treeModel.selectedObject", setNavigation);
-
+
// Clean up when the scope is destroyed
$scope.$on("$destroy", function () {
navigationService.removeListener(setNavigation);
diff --git a/platform/commonUI/browse/src/navigation/NavigationService.js b/platform/commonUI/browse/src/navigation/NavigationService.js
index 87e5582ef7..e2b7168b3c 100644
--- a/platform/commonUI/browse/src/navigation/NavigationService.js
+++ b/platform/commonUI/browse/src/navigation/NavigationService.js
@@ -37,7 +37,7 @@ define(
*/
function NavigationService() {
this.navigated = undefined;
- this.callbacks = [];
+ this.callbacks = {};
}
/**
@@ -53,12 +53,20 @@ define(
* @param {DomainObject} domainObject the domain object to navigate to
*/
NavigationService.prototype.setNavigation = function (value) {
+ var canNavigate = true;
if (this.navigated !== value) {
- this.navigated = value;
- this.callbacks.forEach(function (callback) {
- callback(value);
- });
+ canNavigate = (this.callbacks['before'] || [])
+ .reduce(function (previous, callback) {
+ return callback(value) && previous;
+ }, true);
+ if (canNavigate) {
+ this.navigated = value;
+ this.callbacks['after'].forEach(function (callback) {
+ callback(value);
+ });
+ }
}
+ return canNavigate;
};
/**
@@ -67,9 +75,13 @@ define(
* this changes.
* @param {function} callback the callback to invoke when
* navigation state changes
+ * @param {string} [event=after] the navigation event to listen to.
+ * One of 'before' or 'after'.
*/
- NavigationService.prototype.addListener = function (callback) {
- this.callbacks.push(callback);
+ NavigationService.prototype.addListener = function (callback, event) {
+ event = event || 'after';
+ this.callbacks[event] = this.callbacks[event] || [];
+ this.callbacks[event].push(callback);
};
/**
@@ -77,9 +89,12 @@ define(
* @param {function} callback the callback which should
* no longer be invoked when navigation state
* changes
+ * @param {string} [event=after] the navigation event to the
+ * callback is registered to. One of 'before' or 'after'.
*/
- NavigationService.prototype.removeListener = function (callback) {
- this.callbacks = this.callbacks.filter(function (cb) {
+ NavigationService.prototype.removeListener = function (callback, event) {
+ event = event || 'after';
+ this.callbacks[event] = this.callbacks[event].filter(function (cb) {
return cb !== callback;
});
};
diff --git a/platform/commonUI/edit/bundle.js b/platform/commonUI/edit/bundle.js
index c4b0da1798..9fc0c98939 100644
--- a/platform/commonUI/edit/bundle.js
+++ b/platform/commonUI/edit/bundle.js
@@ -26,6 +26,7 @@ define([
"./src/controllers/EditActionController",
"./src/controllers/EditPanesController",
"./src/controllers/ElementsController",
+ "./src/controllers/EditObjectController",
"./src/directives/MCTBeforeUnload",
"./src/actions/LinkAction",
"./src/actions/EditAction",
@@ -48,6 +49,7 @@ define([
EditActionController,
EditPanesController,
ElementsController,
+ EditObjectController,
MCTBeforeUnload,
LinkAction,
EditAction,
@@ -106,6 +108,13 @@ define([
"depends": [
"$scope"
]
+ },
+ {
+ "key": "EditObjectController",
+ "implementation": EditObjectController,
+ "depends": [
+ "$scope"
+ ]
}
],
"directives": [
@@ -206,6 +215,9 @@ define([
"template": editObjectTemplate,
"uses": [
"view"
+ ],
+ "gestures": [
+ "drop"
]
},
{
diff --git a/platform/commonUI/edit/res/templates/edit-object.html b/platform/commonUI/edit/res/templates/edit-object.html
index 71dc233a82..7b2f32e1b3 100644
--- a/platform/commonUI/edit/res/templates/edit-object.html
+++ b/platform/commonUI/edit/res/templates/edit-object.html
@@ -19,50 +19,52 @@
this source code distribution or the Licensing information page available
at runtime from the About dialog for additional information.
-->
-
-
-
-
-
-
-
-
+
+
diff --git a/platform/commonUI/edit/res/templates/edit.html b/platform/commonUI/edit/res/templates/edit.html
index 07a677bce8..489eed822b 100644
--- a/platform/commonUI/edit/res/templates/edit.html
+++ b/platform/commonUI/edit/res/templates/edit.html
@@ -21,7 +21,7 @@
-->
diff --git a/platform/commonUI/edit/res/templates/inspector-edit.html b/platform/commonUI/edit/res/templates/inspector-edit.html
new file mode 100644
index 0000000000..5f3e4d522e
--- /dev/null
+++ b/platform/commonUI/edit/res/templates/inspector-edit.html
@@ -0,0 +1,80 @@
+
+
+
+
diff --git a/platform/commonUI/edit/src/actions/EditAction.js b/platform/commonUI/edit/src/actions/EditAction.js
index 6b8ba3e042..d771f75dd4 100644
--- a/platform/commonUI/edit/src/actions/EditAction.js
+++ b/platform/commonUI/edit/src/actions/EditAction.js
@@ -72,13 +72,26 @@ define(
* Enter edit mode.
*/
EditAction.prototype.perform = function () {
- var editableObject;
+ var self = this;
if (!this.domainObject.hasCapability("editor")) {
- editableObject = new EditableDomainObject(this.domainObject, this.$q);
- editableObject.getCapability('status').set('editing', true);
- this.navigationService.setNavigation(editableObject);
+ //TODO: This is only necessary because the drop gesture is
+ // wrapping the object itself, need to refactor this later.
+ // All responsibility for switching into edit mode should be
+ // in the edit action, and not duplicated in the gesture
+ this.domainObject = new EditableDomainObject(this.domainObject, this.$q);
}
- //this.$location.path("/edit");
+ this.navigationService.setNavigation(this.domainObject);
+ this.domainObject.getCapability('status').set('editing', true);
+
+ //Register a listener to automatically cancel this edit action
+ //if the user navigates away from this object.
+ function cancelEditing(navigatedTo){
+ if (!navigatedTo || navigatedTo.getId() !== self.domainObject.getId()) {
+ self.domainObject.getCapability('editor').cancel();
+ self.navigationService.removeListener(cancelEditing);
+ }
+ }
+ this.navigationService.addListener(cancelEditing);
};
/**
diff --git a/platform/commonUI/edit/src/controllers/EditObjectController.js b/platform/commonUI/edit/src/controllers/EditObjectController.js
new file mode 100644
index 0000000000..eb5d494cac
--- /dev/null
+++ b/platform/commonUI/edit/src/controllers/EditObjectController.js
@@ -0,0 +1,65 @@
+/*****************************************************************************
+ * Open MCT Web, Copyright (c) 2014-2015, United States Government
+ * as represented by the Administrator of the National Aeronautics and Space
+ * Administration. All rights reserved.
+ *
+ * Open MCT Web is licensed under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ * Open MCT Web includes source code licensed under additional open source
+ * licenses. See the Open Source Licenses file (LICENSES.md) included with
+ * this source code distribution or the Licensing information page available
+ * at runtime from the About dialog for additional information.
+ *****************************************************************************/
+/*global define,Promise*/
+
+/**
+ * This bundle implements Edit mode.
+ * @namespace platform/commonUI/edit
+ */
+define(
+ [],
+ function () {
+ "use strict";
+
+ /**
+ * Controller which is responsible for populating the scope for
+ * Edit mode
+ * @memberof platform/commonUI/edit
+ * @constructor
+ */
+ function EditObjectController($scope) {
+ this.scope = $scope;
+ }
+
+ /**
+ * Get the warning to show if the user attempts to navigate
+ * away from Edit mode while unsaved changes are present.
+ * @returns {string} the warning to show, or undefined if
+ * there are no unsaved changes
+ */
+ EditObjectController.prototype.getUnloadWarning = function () {
+ var navigatedObject = this.scope.domainObject,
+ editorCapability = navigatedObject &&
+ navigatedObject.getCapability("editor"),
+ statusCapability = navigatedObject &&
+ navigatedObject.getCapability("status"),
+ hasChanges = statusCapability && statusCapability.get('editing')
+ && editorCapability && editorCapability.dirty();
+
+ return hasChanges ?
+ "Unsaved changes will be lost if you leave this page." :
+ undefined;
+ };
+
+ return EditObjectController;
+ }
+);
diff --git a/platform/commonUI/edit/src/directives/MCTBeforeUnload.js b/platform/commonUI/edit/src/directives/MCTBeforeUnload.js
index 3e7501c788..226e85f4a0 100644
--- a/platform/commonUI/edit/src/directives/MCTBeforeUnload.js
+++ b/platform/commonUI/edit/src/directives/MCTBeforeUnload.js
@@ -35,7 +35,7 @@ define(
* @constructor
* @param $window the window
*/
- function MCTBeforeUnload($window) {
+ function MCTBeforeUnload($window, navigationService) {
var unloads = [],
oldBeforeUnload = $window.onbeforeunload;
@@ -57,6 +57,7 @@ define(
// Stop using this unload expression
function removeUnload() {
+ navigationService.removeListener(checkNavigationEvent, "before");
unloads = unloads.filter(function (callback) {
return callback !== unload;
});
@@ -65,17 +66,28 @@ define(
}
}
- // Show a dialog before allowing a location change
- function checkLocationChange(event) {
+ function shouldAllowNavigation(){
// Get an unload message (if any)
var warning = unload();
// Prompt the user if there's an unload message
- if (warning && !$window.confirm(warning)) {
- // ...and prevent the route change if it was confirmed
+ return !warning || $window.confirm(warning);
+ }
+
+ // Show a dialog before allowing a location change
+ function checkLocationChange(event) {
+ if (!shouldAllowNavigation()) {
+ // Prevent the route change if it was confirmed
event.preventDefault();
}
}
+ // Show a dialog before allowing a location change
+ function checkNavigationEvent(event) {
+ // Return a false value to the navigationService to
+ // indicate that the navigation event should be prevented
+ return shouldAllowNavigation();
+ }
+
// If this is the first active instance of this directive,
// register as the window's beforeunload handler
if (unloads.length === 0) {
@@ -90,6 +102,8 @@ define(
// Also handle route changes
scope.$on("$locationChangeStart", checkLocationChange);
+
+ navigationService.addListener(checkNavigationEvent, "before");
}
return {
diff --git a/platform/commonUI/edit/src/representers/EditRepresenter.js b/platform/commonUI/edit/src/representers/EditRepresenter.js
index 0844f65e67..e53318c1b0 100644
--- a/platform/commonUI/edit/src/representers/EditRepresenter.js
+++ b/platform/commonUI/edit/src/representers/EditRepresenter.js
@@ -49,6 +49,7 @@ define(
var self = this;
this.scope = scope;
+ this.listenHandle = undefined;
// Mutate and persist a new version of a domain object's model.
function doPersist(model) {
@@ -100,10 +101,13 @@ define(
// Place the "commit" method in the scope
scope.commit = commit;
scope.setEditable = setEditable;
+
}
// Handle a specific representation of a specific domain object
EditRepresenter.prototype.represent = function represent(representation, representedObject) {
+ var scope = this.scope,
+ self = this;
// Track the key, to know which view configuration to save to.
this.key = (representation || {}).key;
// Track the represented object
@@ -113,11 +117,26 @@ define(
// Ensure existing watches are released
this.destroy();
+
+ /**
+ * Listen for changes in object state. If the object becomes
+ * editable then change the view and inspector regions
+ * object representation accordingly
+ */
+ this.listenHandle = this.domainObject.getCapability('status').listen(function(statuses){
+ if (statuses.indexOf('editing')!=-1){
+ scope.viewRegionTemplate = 'edit-object';
+ scope.inspectorRegionTemplate = 'inspector-edit'
+ } else {
+ delete scope.viewRegionTemplate;
+ }
+ });
};
// Respond to the destruction of the current representation.
EditRepresenter.prototype.destroy = function destroy() {
// Nothing to clean up
+ this.listenHandle && this.listenHandle();
};
return EditRepresenter;
diff --git a/platform/commonUI/general/res/templates/inspector-browse.html b/platform/commonUI/general/res/templates/inspector-browse.html
new file mode 100644
index 0000000000..3a7a60f516
--- /dev/null
+++ b/platform/commonUI/general/res/templates/inspector-browse.html
@@ -0,0 +1,64 @@
+
+
+
+
+
diff --git a/platform/representation/src/gestures/DropGesture.js b/platform/representation/src/gestures/DropGesture.js
index 1b7881a770..225211c3bd 100644
--- a/platform/representation/src/gestures/DropGesture.js
+++ b/platform/representation/src/gestures/DropGesture.js
@@ -165,16 +165,18 @@ define(
if (shouldCreateVirtualPanel(domainObject, selectedObject)){
editableDomainObject = createVirtualPanel(domainObject, selectedObject);
if (editableDomainObject) {
- navigationService.setNavigation(editableDomainObject);
+ editableDomainObject.getCapability('action').perform('edit');
+ //navigationService.setNavigation(editableDomainObject);
broadcastDrop(id, event);
- editableDomainObject.getCapability('status').set('editing', true);
+ //editableDomainObject.getCapability('status').set('editing', true);
}
} else {
$q.when(action && action.perform()).then(function (result) {
//Don't go into edit mode for folders
if (domainObjectType!=='folder') {
- navigationService.setNavigation(editableDomainObject);
- editableDomainObject.getCapability('status').set('editing', true);
+ // navigationService.setNavigation(editableDomainObject);
+ //editableDomainObject.getCapability('status').set('editing', true);
+ editableDomainObject.getCapability('action').perform('edit');
}
broadcastDrop(id, event);
});