diff --git a/app.js b/app.js
index 3c976a735a..6b7b1bb635 100644
--- a/app.js
+++ b/app.js
@@ -42,6 +42,8 @@
process.exit(0);
}
+ app.disable('x-powered-by');
+
// Override bundles.json for HTTP requests
app.use('/' + BUNDLE_FILE, function (req, res) {
var bundles;
diff --git a/example/notifications/src/DialogLaunchController.js b/example/notifications/src/DialogLaunchController.js
index 4d75690764..6e3e1271f0 100644
--- a/example/notifications/src/DialogLaunchController.js
+++ b/example/notifications/src/DialogLaunchController.js
@@ -44,30 +44,31 @@ define(
periodically with the progress of an ongoing process.
*/
$scope.launchProgress = function (knownProgress) {
- var model = {
- title: "Progress Dialog Example",
- progress: 0,
- hint: "Do not navigate away from this page or close this browser tab while this operation is in progress.",
- actionText: "Calculating...",
- unknownProgress: !knownProgress,
- unknownDuration: false,
- severity: "info",
- options: [
- {
- label: "Cancel Operation",
- callback: function () {
- $log.debug("Operation cancelled");
- dialogService.dismiss();
+ var dialog,
+ model = {
+ title: "Progress Dialog Example",
+ progress: 0,
+ hint: "Do not navigate away from this page or close this browser tab while this operation is in progress.",
+ actionText: "Calculating...",
+ unknownProgress: !knownProgress,
+ unknownDuration: false,
+ severity: "info",
+ options: [
+ {
+ label: "Cancel Operation",
+ callback: function () {
+ $log.debug("Operation cancelled");
+ dialog.dismiss();
+ }
+ },
+ {
+ label: "Do something else...",
+ callback: function () {
+ $log.debug("Something else pressed");
+ }
}
- },
- {
- label: "Do something else...",
- callback: function () {
- $log.debug("Something else pressed");
- }
- }
- ]
- };
+ ]
+ };
function incrementProgress() {
model.progress = Math.min(100, Math.floor(model.progress + Math.random() * 30));
@@ -77,7 +78,9 @@ define(
}
}
- if (dialogService.showBlockingMessage(model)) {
+ dialog = dialogService.showBlockingMessage(model);
+
+ if (dialog) {
//Do processing here
model.actionText = "Processing 100 objects...";
if (knownProgress) {
@@ -93,29 +96,31 @@ define(
Demonstrates launching an error dialog
*/
$scope.launchError = function () {
- var model = {
- title: "Error Dialog Example",
- actionText: "Something happened, and it was not good.",
- severity: "error",
- options: [
- {
- label: "Try Again",
- callback: function () {
- $log.debug("Try Again Pressed");
- dialogService.dismiss();
+ var dialog,
+ model = {
+ title: "Error Dialog Example",
+ actionText: "Something happened, and it was not good.",
+ severity: "error",
+ options: [
+ {
+ label: "Try Again",
+ callback: function () {
+ $log.debug("Try Again Pressed");
+ dialog.dismiss();
+ }
+ },
+ {
+ label: "Cancel",
+ callback: function () {
+ $log.debug("Cancel Pressed");
+ dialog.dismiss();
+ }
}
- },
- {
- label: "Cancel",
- callback: function () {
- $log.debug("Cancel Pressed");
- dialogService.dismiss();
- }
- }
- ]
- };
+ ]
+ };
+ dialog = dialogService.showBlockingMessage(model);
- if (!dialogService.showBlockingMessage(model)) {
+ if (!dialog) {
$log.error("Could not display modal dialog");
}
};
@@ -124,22 +129,25 @@ define(
Demonstrates launching an error dialog
*/
$scope.launchInfo = function () {
- var model = {
- title: "Info Dialog Example",
- actionText: "This is an example of a blocking info" +
- " dialog. This dialog can be used to draw the user's" +
- " attention to an event.",
- severity: "info",
- primaryOption: {
- label: "OK",
- callback: function () {
- $log.debug("OK Pressed");
- dialogService.dismiss();
+ var dialog,
+ model = {
+ title: "Info Dialog Example",
+ actionText: "This is an example of a blocking info" +
+ " dialog. This dialog can be used to draw the user's" +
+ " attention to an event.",
+ severity: "info",
+ primaryOption: {
+ label: "OK",
+ callback: function () {
+ $log.debug("OK Pressed");
+ dialog.dismiss();
+ }
}
- }
- };
+ };
- if (!dialogService.showBlockingMessage(model)) {
+ dialog = dialogService.showBlockingMessage(model);
+
+ if (!dialog) {
$log.error("Could not display modal dialog");
}
};
diff --git a/main.js b/main.js
index 77b56d294b..268c70060d 100644
--- a/main.js
+++ b/main.js
@@ -77,6 +77,7 @@ define([
'./platform/exporters/bundle',
'./platform/telemetry/bundle',
'./platform/features/clock/bundle',
+ './platform/features/fixed/bundle',
'./platform/features/imagery/bundle',
'./platform/features/layout/bundle',
'./platform/features/pages/bundle',
diff --git a/platform/commonUI/browse/bundle.js b/platform/commonUI/browse/bundle.js
index 5388a444c0..4454cfcc89 100644
--- a/platform/commonUI/browse/bundle.js
+++ b/platform/commonUI/browse/bundle.js
@@ -23,6 +23,7 @@
define([
"./src/BrowseController",
"./src/PaneController",
+ "./src/InspectorPaneController",
"./src/BrowseObjectController",
"./src/MenuArrowController",
"./src/navigation/NavigationService",
@@ -44,6 +45,7 @@ define([
], function (
BrowseController,
PaneController,
+ InspectorPaneController,
BrowseObjectController,
MenuArrowController,
NavigationService,
@@ -124,6 +126,17 @@ define([
"depends": [
"$scope"
]
+ },
+ {
+ "key": "InspectorPaneController",
+ "implementation": InspectorPaneController,
+ "priority": "preferred",
+ "depends": [
+ "$scope",
+ "agentService",
+ "$window",
+ "navigationService"
+ ]
}
],
"representations": [
diff --git a/platform/commonUI/browse/res/templates/browse.html b/platform/commonUI/browse/res/templates/browse.html
index 1ad0241020..63197ba84f 100644
--- a/platform/commonUI/browse/res/templates/browse.html
+++ b/platform/commonUI/browse/res/templates/browse.html
@@ -57,7 +57,7 @@
ng-class="{ collapsed : !modelPaneTree.visible() }">
diff --git a/platform/commonUI/browse/src/InspectorPaneController.js b/platform/commonUI/browse/src/InspectorPaneController.js
new file mode 100644
index 0000000000..ef8e3883f7
--- /dev/null
+++ b/platform/commonUI/browse/src/InspectorPaneController.js
@@ -0,0 +1,79 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+
+
+define(
+ ["./PaneController"],
+ function (PaneController) {
+
+ /**
+ * Pane controller that reveals inspector, if hidden, when object
+ * switches to edit mode.
+ *
+ * @param $scope
+ * @param agentService
+ * @param $window
+ * @param navigationService
+ * @constructor
+ */
+ function InspectorPaneController($scope, agentService, $window, navigationService) {
+ PaneController.call(this, $scope, agentService, $window);
+
+ var statusListener,
+ self = this;
+
+ function showInspector(statuses) {
+ if (statuses.indexOf('editing') !== -1 && !self.visible()) {
+ self.toggle();
+ }
+ }
+
+ function attachStatusListener(domainObject) {
+ // Remove existing status listener if existing
+ if (statusListener) {
+ statusListener();
+ }
+
+ if (domainObject.hasCapability("status")) {
+ statusListener = domainObject.getCapability("status").listen(showInspector);
+ }
+ return statusListener;
+ }
+
+ var domainObject = navigationService.getNavigation();
+ if (domainObject) {
+ attachStatusListener(domainObject);
+ }
+
+ var navigationListener = navigationService.addListener(attachStatusListener);
+
+ $scope.$on("$destroy", function () {
+ statusListener();
+ navigationListener();
+ });
+ }
+
+ InspectorPaneController.prototype = Object.create(PaneController.prototype);
+
+ return InspectorPaneController;
+ }
+);
diff --git a/platform/commonUI/browse/test/InspectorPaneControllerSpec.js b/platform/commonUI/browse/test/InspectorPaneControllerSpec.js
new file mode 100644
index 0000000000..635396902b
--- /dev/null
+++ b/platform/commonUI/browse/test/InspectorPaneControllerSpec.js
@@ -0,0 +1,96 @@
+/*****************************************************************************
+ * 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.
+ *****************************************************************************/
+
+define(
+ ["../src/InspectorPaneController"],
+ function (InspectorPaneController) {
+
+ describe("The InspectorPaneController", function () {
+ var mockScope,
+ mockAgentService,
+ mockDomainObject,
+ mockWindow,
+ mockStatusCapability,
+ mockNavigationService,
+ mockNavigationUnlistener,
+ mockStatusUnlistener,
+ controller;
+
+ beforeEach(function () {
+ mockScope = jasmine.createSpyObj("$scope", ["$on"]);
+ mockWindow = jasmine.createSpyObj("$window", ["open"]);
+ mockAgentService = jasmine.createSpyObj(
+ "agentService",
+ ["isMobile", "isPhone", "isTablet", "isPortrait", "isLandscape"]
+ );
+
+ mockNavigationUnlistener = jasmine.createSpy("navigationUnlistener");
+ mockNavigationService = jasmine.createSpyObj(
+ "navigationService",
+ ["getNavigation", "addListener"]
+ );
+ mockNavigationService.addListener.andReturn(mockNavigationUnlistener);
+
+ mockStatusUnlistener = jasmine.createSpy("statusUnlistener");
+ mockStatusCapability = jasmine.createSpyObj(
+ "statusCapability",
+ ["listen"]
+ );
+ mockStatusCapability.listen.andReturn(mockStatusUnlistener);
+
+ mockDomainObject = jasmine.createSpyObj(
+ 'domainObject',
+ [
+ 'getId',
+ 'getModel',
+ 'getCapability',
+ 'hasCapability'
+ ]
+ );
+ mockDomainObject.getId.andReturn("domainObject");
+ mockDomainObject.getModel.andReturn({});
+ mockDomainObject.hasCapability.andReturn(true);
+ mockDomainObject.getCapability.andReturn(mockStatusCapability);
+
+ controller = new InspectorPaneController(mockScope, mockAgentService, mockWindow, mockNavigationService);
+ });
+
+ it("listens for changes to navigation and attaches a status" +
+ " listener", function () {
+ expect(mockNavigationService.addListener).toHaveBeenCalledWith(jasmine.any(Function));
+ mockNavigationService.addListener.mostRecentCall.args[0](mockDomainObject);
+ expect(mockStatusCapability.listen).toHaveBeenCalledWith(jasmine.any(Function));
+ });
+
+ it("if hidden, shows the inspector when domain object switches to" +
+ " edit mode", function () {
+ controller.toggle();
+ // test pre-condition that inspector is hidden
+ expect(controller.visible()).toBe(false);
+ mockNavigationService.addListener.mostRecentCall.args[0](mockDomainObject);
+ mockStatusCapability.listen.mostRecentCall.args[0](["editing"]);
+ expect(controller.visible()).toBe(true);
+ });
+
+ });
+ }
+);
diff --git a/platform/commonUI/dialog/src/DialogService.js b/platform/commonUI/dialog/src/DialogService.js
index 26d11a44de..ca0a4b09b7 100644
--- a/platform/commonUI/dialog/src/DialogService.js
+++ b/platform/commonUI/dialog/src/DialogService.js
@@ -39,25 +39,28 @@ define(
this.overlayService = overlayService;
this.$q = $q;
this.$log = $log;
- this.overlay = undefined;
- this.dialogVisible = false;
+ this.activeOverlay = undefined;
}
- // Stop showing whatever overlay is currently active
- // (e.g. because the user hit cancel)
- DialogService.prototype.dismiss = function () {
- var overlay = this.overlay;
- if (overlay) {
- overlay.dismiss();
+ /**
+ * @private
+ */
+ DialogService.prototype.dismissOverlay = function (overlay) {
+ //Dismiss the overlay
+ overlay.dismiss();
+
+ //If dialog is the current active one, dismiss it
+ if (overlay === this.activeOverlay) {
+ this.activeOverlay = undefined;
}
- this.dialogVisible = false;
};
DialogService.prototype.getDialogResponse = function (key, model, resultGetter, typeClass) {
// We will return this result as a promise, because user
// input is asynchronous.
var deferred = this.$q.defer(),
- self = this;
+ self = this,
+ overlay;
// Confirm function; this will be passed in to the
// overlay-dialog template and associated with a
@@ -65,9 +68,7 @@ define(
function confirm(value) {
// Pass along the result
deferred.resolve(resultGetter ? resultGetter() : value);
-
- // Stop showing the dialog
- self.dismiss();
+ self.dismissOverlay(overlay);
}
// Cancel function; this will be passed in to the
@@ -75,7 +76,7 @@ define(
// Cancel or X button click
function cancel() {
deferred.reject();
- self.dismiss();
+ self.dismissOverlay(overlay);
}
// Add confirm/cancel callbacks
@@ -85,15 +86,11 @@ define(
if (this.canShowDialog(model)) {
// Add the overlay using the OverlayService, which
// will handle actual insertion into the DOM
- this.overlay = this.overlayService.createOverlay(
+ overlay = this.activeOverlay = this.overlayService.createOverlay(
key,
model,
typeClass || "t-dialog"
);
-
- // Track that a dialog is already visible, to
- // avoid spawning multiple dialogs at once.
- this.dialogVisible = true;
} else {
deferred.reject();
}
@@ -156,7 +153,7 @@ define(
* otherwise
*/
DialogService.prototype.canShowDialog = function (dialogModel) {
- if (this.dialogVisible) {
+ if (this.activeOverlay) {
// Only one dialog should be shown at a time.
// The application design should be such that
// we never even try to do this.
@@ -183,6 +180,11 @@ define(
* button is clicked
*/
+ /**
+ * @typedef DialogHandle
+ * @property {function} dismiss a function to dismiss the given dialog
+ */
+
/**
* A description of the model options that may be passed to the
* showBlockingMessage method. Note that the DialogModel desribed
@@ -222,21 +224,26 @@ define(
* the user can take if necessary
* @param {DialogModel} dialogModel defines options for the dialog
* @param {typeClass} string tells overlayService that this overlay should use appropriate CSS class
- * @returns {boolean}
+ * @returns {boolean | {DialogHandle}}
*/
DialogService.prototype.showBlockingMessage = function (dialogModel) {
if (this.canShowDialog(dialogModel)) {
// Add the overlay using the OverlayService, which
// will handle actual insertion into the DOM
- this.overlay = this.overlayService.createOverlay(
- "overlay-blocking-message",
- dialogModel,
- "t-dialog-sm"
- );
- // Track that a dialog is already visible, to
- // avoid spawning multiple dialogs at once.
- this.dialogVisible = true;
- return true;
+ var self = this,
+ overlay = this.overlayService.createOverlay(
+ "overlay-blocking-message",
+ dialogModel,
+ "t-dialog-sm"
+ );
+
+ this.activeOverlay = overlay;
+
+ return {
+ dismiss: function () {
+ self.dismissOverlay(overlay);
+ }
+ };
} else {
return false;
}
diff --git a/platform/commonUI/dialog/test/DialogServiceSpec.js b/platform/commonUI/dialog/test/DialogServiceSpec.js
index f8bfc93ba4..e8b987b996 100644
--- a/platform/commonUI/dialog/test/DialogServiceSpec.js
+++ b/platform/commonUI/dialog/test/DialogServiceSpec.js
@@ -122,7 +122,7 @@ define(
it("invokes the overlay service with the correct parameters when" +
" a blocking dialog is requested", function () {
var dialogModel = {};
- expect(dialogService.showBlockingMessage(dialogModel)).toBe(true);
+ expect(dialogService.showBlockingMessage(dialogModel)).not.toBe(false);
expect(mockOverlayService.createOverlay).toHaveBeenCalledWith(
"overlay-blocking-message",
dialogModel,
@@ -130,6 +130,45 @@ define(
);
});
+ describe("the blocking message dialog", function () {
+ var dialogModel = {};
+ var dialogHandle;
+
+ beforeEach(function () {
+ dialogHandle = dialogService.showBlockingMessage(dialogModel);
+ });
+
+ it("returns a handle to the dialog", function () {
+ expect(dialogHandle).not.toBe(undefined);
+ });
+
+ it("dismissing the dialog dismisses the overlay", function () {
+ dialogHandle.dismiss();
+ expect(mockOverlay.dismiss).toHaveBeenCalled();
+ });
+
+ it("individual dialogs can be dismissed", function () {
+ var secondDialogHandle,
+ secondMockOverlay;
+
+ dialogHandle.dismiss();
+
+ secondMockOverlay = jasmine.createSpyObj(
+ "overlay",
+ ["dismiss"]
+ );
+ mockOverlayService.createOverlay.andReturn(secondMockOverlay);
+ secondDialogHandle = dialogService.showBlockingMessage(dialogModel);
+
+ //Dismiss the first dialog. It should only dismiss if it
+ // is active
+ dialogHandle.dismiss();
+ expect(secondMockOverlay.dismiss).not.toHaveBeenCalled();
+ secondDialogHandle.dismiss();
+ expect(secondMockOverlay.dismiss).toHaveBeenCalled();
+ });
+ });
+
});
}
);
diff --git a/platform/commonUI/edit/src/actions/SaveInProgressDialog.js b/platform/commonUI/edit/src/actions/SaveInProgressDialog.js
index c80989b8e0..56c2c1ad86 100644
--- a/platform/commonUI/edit/src/actions/SaveInProgressDialog.js
+++ b/platform/commonUI/edit/src/actions/SaveInProgressDialog.js
@@ -1,10 +1,11 @@
define([], function () {
function SaveInProgressDialog(dialogService) {
this.dialogService = dialogService;
+ this.dialog = undefined;
}
SaveInProgressDialog.prototype.show = function () {
- this.dialogService.showBlockingMessage({
+ this.dialog = this.dialogService.showBlockingMessage({
title: "Saving...",
hint: "Do not navigate away from this page or close this browser tab while this message is displayed.",
unknownProgress: true,
@@ -13,7 +14,9 @@ define([], function () {
};
SaveInProgressDialog.prototype.hide = function () {
- this.dialogService.dismiss();
+ if (this.dialog) {
+ this.dialog.dismiss();
+ }
};
return SaveInProgressDialog;
diff --git a/platform/commonUI/edit/test/actions/SaveActionSpec.js b/platform/commonUI/edit/test/actions/SaveActionSpec.js
index 8addce60b7..0243f89a11 100644
--- a/platform/commonUI/edit/test/actions/SaveActionSpec.js
+++ b/platform/commonUI/edit/test/actions/SaveActionSpec.js
@@ -70,7 +70,7 @@ define(
};
dialogService = jasmine.createSpyObj(
"dialogService",
- ["showBlockingMessage", "dismiss"]
+ ["showBlockingMessage"]
);
mockDomainObject.hasCapability.andReturn(true);
@@ -111,17 +111,28 @@ define(
expect(mockActionCapability.perform).toHaveBeenCalledWith("navigate");
});
- it("shows a dialog while saving", function () {
- mockEditorCapability.save.andReturn(new Promise(function () {}));
- action.perform();
- expect(dialogService.showBlockingMessage).toHaveBeenCalled();
- expect(dialogService.dismiss).not.toHaveBeenCalled();
- });
+ describe("a blocking dialog", function () {
+ var mockDialogHandle;
- it("hides a dialog when saving is complete", function () {
- action.perform();
- expect(dialogService.showBlockingMessage).toHaveBeenCalled();
- expect(dialogService.dismiss).toHaveBeenCalled();
+ beforeEach(function () {
+ mockDialogHandle = jasmine.createSpyObj("dialogHandle", ["dismiss"]);
+ dialogService.showBlockingMessage.andReturn(mockDialogHandle);
+ });
+
+
+ it("shows a dialog while saving", function () {
+ mockEditorCapability.save.andReturn(new Promise(function () {
+ }));
+ action.perform();
+ expect(dialogService.showBlockingMessage).toHaveBeenCalled();
+ expect(mockDialogHandle.dismiss).not.toHaveBeenCalled();
+ });
+
+ it("hides a dialog when saving is complete", function () {
+ action.perform();
+ expect(dialogService.showBlockingMessage).toHaveBeenCalled();
+ expect(mockDialogHandle.dismiss).toHaveBeenCalled();
+ });
});
});
diff --git a/platform/commonUI/edit/test/actions/SaveAsActionSpec.js b/platform/commonUI/edit/test/actions/SaveAsActionSpec.js
index 4ad8ffa215..fd8ce18c07 100644
--- a/platform/commonUI/edit/test/actions/SaveAsActionSpec.js
+++ b/platform/commonUI/edit/test/actions/SaveAsActionSpec.js
@@ -101,8 +101,7 @@ define(
"dialogService",
[
"getUserInput",
- "showBlockingMessage",
- "dismiss"
+ "showBlockingMessage"
]
);
mockDialogService.getUserInput.andReturn(mockPromise(undefined));
@@ -171,25 +170,33 @@ define(
expect(mockDialogService.getUserInput).toHaveBeenCalled();
});
- it("shows a blocking dialog while waiting for save", function () {
- mockEditorCapability.save.andReturn(new Promise(function () {}));
- action.perform();
- expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
- expect(mockDialogService.dismiss).not.toHaveBeenCalled();
- });
+ describe("a blocking dialog", function () {
+ var mockDialogHandle;
- it("hides the blocking dialog after saving", function () {
- var mockCallback = jasmine.createSpy();
- action.perform().then(mockCallback);
- expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
- waitsFor(function () {
- return mockCallback.calls.length > 0;
+ beforeEach(function () {
+ mockDialogHandle = jasmine.createSpyObj("dialogHandle", ["dismiss"]);
+ mockDialogService.showBlockingMessage.andReturn(mockDialogHandle);
});
- runs(function () {
- expect(mockDialogService.dismiss).toHaveBeenCalled();
+
+ it("indicates that a save is taking place", function () {
+ mockEditorCapability.save.andReturn(new Promise(function () {}));
+ action.perform();
+ expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
+ expect(mockDialogHandle.dismiss).not.toHaveBeenCalled();
+ });
+
+ it("is hidden after saving", function () {
+ var mockCallback = jasmine.createSpy();
+ action.perform().then(mockCallback);
+ expect(mockDialogService.showBlockingMessage).toHaveBeenCalled();
+ waitsFor(function () {
+ return mockCallback.calls.length > 0;
+ });
+ runs(function () {
+ expect(mockDialogHandle.dismiss).toHaveBeenCalled();
+ });
});
});
-
});
}
);
diff --git a/platform/commonUI/general/bundle.js b/platform/commonUI/general/bundle.js
index 1ec3c5a1f4..b2eccc1732 100644
--- a/platform/commonUI/general/bundle.js
+++ b/platform/commonUI/general/bundle.js
@@ -259,7 +259,7 @@ define([
"implementation": ClickAwayController,
"depends": [
"$document",
- "$timeout"
+ "$scope"
]
},
{
diff --git a/platform/commonUI/general/src/controllers/BannerController.js b/platform/commonUI/general/src/controllers/BannerController.js
index cab6eb5d87..4ea001795f 100644
--- a/platform/commonUI/general/src/controllers/BannerController.js
+++ b/platform/commonUI/general/src/controllers/BannerController.js
@@ -54,17 +54,17 @@ define(
};
$scope.maximize = function (notification) {
if (notification.model.severity !== "info") {
-
+ var dialog;
notification.model.cancel = function () {
- dialogService.dismiss();
+ dialog.dismiss();
};
//If the notification is dismissed by the user, close
// the dialog.
notification.onDismiss(function () {
- dialogService.dismiss();
+ dialog.dismiss();
});
- dialogService.showBlockingMessage(notification.model);
+ dialog = dialogService.showBlockingMessage(notification.model);
}
};
}
diff --git a/platform/commonUI/general/src/controllers/ClickAwayController.js b/platform/commonUI/general/src/controllers/ClickAwayController.js
index 6a01c528e9..94ae71c2ea 100644
--- a/platform/commonUI/general/src/controllers/ClickAwayController.js
+++ b/platform/commonUI/general/src/controllers/ClickAwayController.js
@@ -34,7 +34,7 @@ define(
* @param $scope the scope in which this controller is active
* @param $document the document element, injected by Angular
*/
- function ClickAwayController($document, $timeout) {
+ function ClickAwayController($document, $scope) {
var self = this;
this.state = false;
@@ -44,7 +44,7 @@ define(
// `clickaway` action occurs after `toggle` if `toggle` is
// triggered by a click/mouseup.
this.clickaway = function () {
- $timeout(function () {
+ $scope.$apply(function () {
self.deactivate();
});
};
diff --git a/platform/commonUI/general/test/controllers/ClickAwayControllerSpec.js b/platform/commonUI/general/test/controllers/ClickAwayControllerSpec.js
index 22b4035919..8edf90e2c6 100644
--- a/platform/commonUI/general/test/controllers/ClickAwayControllerSpec.js
+++ b/platform/commonUI/general/test/controllers/ClickAwayControllerSpec.js
@@ -26,7 +26,7 @@ define(
describe("The click-away controller", function () {
var mockDocument,
- mockTimeout,
+ mockScope,
controller;
beforeEach(function () {
@@ -34,10 +34,11 @@ define(
"$document",
["on", "off"]
);
- mockTimeout = jasmine.createSpy('timeout');
+ mockScope = jasmine.createSpyObj('$scope', ['$apply']);
+
controller = new ClickAwayController(
mockDocument,
- mockTimeout
+ mockScope
);
});
@@ -77,18 +78,15 @@ define(
});
it("deactivates and detaches listener on document click", function () {
- var callback, timeout;
+ var callback, apply;
controller.setState(true);
callback = mockDocument.on.mostRecentCall.args[1];
callback();
- timeout = mockTimeout.mostRecentCall.args[0];
- timeout();
+ apply = mockScope.$apply.mostRecentCall.args[0];
+ apply();
expect(controller.isActive()).toEqual(false);
expect(mockDocument.off).toHaveBeenCalledWith("mouseup", callback);
});
-
-
-
});
}
);
diff --git a/platform/commonUI/notification/src/NotificationIndicatorController.js b/platform/commonUI/notification/src/NotificationIndicatorController.js
index 8b8ab798b4..c0f8f17848 100644
--- a/platform/commonUI/notification/src/NotificationIndicatorController.js
+++ b/platform/commonUI/notification/src/NotificationIndicatorController.js
@@ -49,9 +49,6 @@ define(
//Launch the message list dialog with the models
// from the notifications
messages: notificationService.notifications
- },
- cancel: function () {
- dialogService.dismiss();
}
});
diff --git a/platform/commonUI/notification/test/NotificationIndicatorControllerSpec.js b/platform/commonUI/notification/test/NotificationIndicatorControllerSpec.js
index 324552ac89..44fc256714 100644
--- a/platform/commonUI/notification/test/NotificationIndicatorControllerSpec.js
+++ b/platform/commonUI/notification/test/NotificationIndicatorControllerSpec.js
@@ -54,22 +54,7 @@ define(
expect(mockDialogService.getDialogResponse).toHaveBeenCalled();
expect(mockDialogService.getDialogResponse.mostRecentCall.args[0]).toBe('overlay-message-list');
expect(mockDialogService.getDialogResponse.mostRecentCall.args[1].dialog).toBeDefined();
- expect(mockDialogService.getDialogResponse.mostRecentCall.args[1].cancel).toBeDefined();
- //Invoke the cancel callback
- mockDialogService.getDialogResponse.mostRecentCall.args[1].cancel();
- expect(mockDialogService.dismiss).toHaveBeenCalled();
});
-
- it("provides a means of dismissing the message list", function () {
- expect(mockScope.showNotificationsList).toBeDefined();
- mockScope.showNotificationsList();
- expect(mockDialogService.getDialogResponse).toHaveBeenCalled();
- expect(mockDialogService.getDialogResponse.mostRecentCall.args[1].cancel).toBeDefined();
- //Invoke the cancel callback
- mockDialogService.getDialogResponse.mostRecentCall.args[1].cancel();
- expect(mockDialogService.dismiss).toHaveBeenCalled();
- });
-
});
}
);
diff --git a/platform/entanglement/src/actions/CopyAction.js b/platform/entanglement/src/actions/CopyAction.js
index ed2e74c98f..805b5f48ba 100644
--- a/platform/entanglement/src/actions/CopyAction.js
+++ b/platform/entanglement/src/actions/CopyAction.js
@@ -86,7 +86,9 @@ define(
severity: "info"
});
} else if (phase.toLowerCase() === "copying") {
- this.dialogService.dismiss();
+ if (this.dialog) {
+ this.dialog.dismiss();
+ }
if (!this.notification) {
this.notification = this.notificationService
.notify({
@@ -115,7 +117,8 @@ define(
}
function error(errorDetails) {
- var errorMessage = {
+ var errorDialog,
+ errorMessage = {
title: "Error copying objects.",
severity: "error",
hint: errorDetails.message,
@@ -123,12 +126,12 @@ define(
options: [{
label: "OK",
callback: function () {
- self.dialogService.dismiss();
+ errorDialog.dismiss();
}
}]
};
- self.dialogService.dismiss();
+ self.dialog.dismiss();
if (self.notification) {
self.notification.dismiss(); // Clear the progress notification
}
@@ -136,7 +139,7 @@ define(
//Show a minimized notification of error for posterity
self.notificationService.notify(errorMessage);
//Display a blocking message
- self.dialogService.showBlockingMessage(errorMessage);
+ errorDialog = self.dialogService.showBlockingMessage(errorMessage);
}
function notification(details) {
diff --git a/platform/entanglement/test/actions/CopyActionSpec.js b/platform/entanglement/test/actions/CopyActionSpec.js
index a884cd6fb0..a626268440 100644
--- a/platform/entanglement/test/actions/CopyActionSpec.js
+++ b/platform/entanglement/test/actions/CopyActionSpec.js
@@ -44,6 +44,7 @@ define(
notificationService,
notification,
dialogService,
+ mockDialog,
mockLog,
abstractComposePromise,
progress = {phase: "copying", totalObjects: 10, processed: 1};
@@ -120,9 +121,12 @@ define(
.andReturn(locationServicePromise);
dialogService = jasmine.createSpyObj('dialogService',
- ['showBlockingMessage', 'dismiss']
+ ['showBlockingMessage']
);
+ mockDialog = jasmine.createSpyObj("dialog", ["dismiss"]);
+ dialogService.showBlockingMessage.andReturn(mockDialog);
+
notification = jasmine.createSpyObj('notification',
['dismiss', 'model']
);
diff --git a/platform/features/fixed/bundle.js b/platform/features/fixed/bundle.js
new file mode 100644
index 0000000000..121501588b
--- /dev/null
+++ b/platform/features/fixed/bundle.js
@@ -0,0 +1,222 @@
+/*****************************************************************************
+ * Open MCT, Copyright (c) 2014-2016, United States Government
+ * as represented by the Administrator of the National Aeronautics and Space
+ * Administration. All rights reserved.
+ *
+ * Open MCT 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 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.
+ *****************************************************************************/
+
+define([
+ "text!../layout/res/templates/fixed.html",
+ 'legacyRegistry'
+], function (
+ fixedTemplate,
+ legacyRegistry
+) {
+
+ legacyRegistry.register("platform/features/fixed", {
+ "name": "Fixed position components.",
+ "description": "Plug in adding Fixed Position object type.",
+ "extensions": {
+ "views": [
+ {
+ "key": "fixed-display",
+ "name": "Fixed Position Display",
+ "glyph": "3",
+ "type": "telemetry.fixed",
+ "template": fixedTemplate,
+ "uses": [
+ "composition"
+ ],
+ "editable": true,
+ "toolbar": {
+ "sections": [
+ {
+ "items": [
+ {
+ "method": "add",
+ "glyph": "\u002b",
+ "control": "menu-button",
+ "text": "Add",
+ "options": [
+ {
+ "name": "Box",
+ "glyph": "\u00e0",
+ "key": "fixed.box"
+ },
+ {
+ "name": "Line",
+ "glyph": "\u00e2",
+ "key": "fixed.line"
+ },
+ {
+ "name": "Text",
+ "glyph": "\u00e4",
+ "key": "fixed.text"
+ },
+ {
+ "name": "Image",
+ "glyph": "\u00e3",
+ "key": "fixed.image"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "items": [
+ {
+ "method": "order",
+ "glyph": "á",
+ "control": "menu-button",
+ "options": [
+ {
+ "name": "Move to Top",
+ "glyph": "\u00eb",
+ "key": "top"
+ },
+ {
+ "name": "Move Up",
+ "glyph": "\u005e",
+ "key": "up"
+ },
+ {
+ "name": "Move Down",
+ "glyph": "\u0076",
+ "key": "down"
+ },
+ {
+ "name": "Move to Bottom",
+ "glyph": "\u00ee",
+ "key": "bottom"
+ }
+ ]
+ },
+ {
+ "property": "fill",
+ "glyph": "",
+ "control": "color"
+ },
+ {
+ "property": "stroke",
+ "glyph": "â",
+ "control": "color"
+ },
+ {
+ "property": "color",
+ "glyph": "ä",
+ "mandatory": true,
+ "control": "color"
+ },
+ {
+ "property": "url",
+ "glyph": "ã",
+ "control": "dialog-button",
+ "title": "Image Properties",
+ "dialog": {
+ "control": "textfield",
+ "name": "Image URL",
+ "required": true
+ }
+ },
+ {
+ "property": "text",
+ "glyph": "G",
+ "control": "dialog-button",
+ "title": "Text Properties",
+ "dialog": {
+ "control": "textfield",
+ "name": "Text",
+ "required": true
+ }
+ },
+ {
+ "method": "showTitle",
+ "glyph": "ç",
+ "control": "button",
+ "description": "Show telemetry element title."
+ },
+ {
+ "method": "hideTitle",
+ "glyph": "å",
+ "control": "button",
+ "description": "Hide telemetry element title."
+ }
+ ]
+ },
+ {
+ "items": [
+ {
+ "method": "remove",
+ "control": "button",
+ "glyph": "Z"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ],
+ "types": [
+ {
+ "key": "telemetry.fixed",
+ "name": "Fixed Position Display",
+ "glyph": "3",
+ "description": "A panel for collecting telemetry" +
+ " elements in a fixed position display.",
+ "priority": 899,
+ "delegates": [
+ "telemetry"
+ ],
+ "features": "creation",
+ "contains": [
+ {
+ "has": "telemetry"
+ }
+ ],
+ "model": {
+ "composition": []
+ },
+ "properties": [
+ {
+ "name": "Layout Grid",
+ "control": "composite",
+ "items": [
+ {
+ "name": "Horizontal grid (px)",
+ "control": "textfield",
+ "cssclass": "l-small l-numeric"
+ },
+ {
+ "name": "Vertical grid (px)",
+ "control": "textfield",
+ "cssclass": "l-small l-numeric"
+ }
+ ],
+ "pattern": "^(\\d*[1-9]\\d*)?$",
+ "property": "layoutGrid",
+ "conversion": "number[]"
+ }
+ ],
+ "views": [
+ "fixed-display"
+ ]
+ }
+ ]
+ }
+ });
+});