diff --git a/bundles.json b/bundles.json
index c0dbd4b974..6b0608cdff 100644
--- a/bundles.json
+++ b/bundles.json
@@ -2,6 +2,7 @@
"platform/framework",
"platform/core",
"platform/representation",
+ "platform/commonUI/about",
"platform/commonUI/browse",
"platform/commonUI/edit",
"platform/commonUI/dialog",
diff --git a/platform/commonUI/about/README.md b/platform/commonUI/about/README.md
new file mode 100644
index 0000000000..05bcfe22cd
--- /dev/null
+++ b/platform/commonUI/about/README.md
@@ -0,0 +1,26 @@
+The "about" bundle provides the default lower-right application logo,
+as well as the dialog it launches when clicked.
+
+# Extensions
+
+The About dialog contains several line items to display different
+version properties (e.g. when built, et cetera.) Plug-ins may wish
+to introduce additional line items here, in particular if the
+platform is used to build a separately-branded piece of software.
+
+This bundle introduces the `versions` extension category to support this.
+An extension of this category is implementation-less (all information
+is contained within its declaration) and should include the following
+fields:
+
+* `name`: The name to display for this version line-item; this may
+ be the name of the software, or something else such as "Built".
+* `value`: The value to display corresponding to this line-item;
+ this is typically a version number, revision identifier, or
+ human-readable date.
+* `description`: Optional; a longer-form description of this line
+ item, to display in a tooltip.
+
+Ordering of these line items is handled by extension priority; see framework
+documentation (`platform/framework/README.md`) for information on how
+this ordering is handled.
diff --git a/platform/commonUI/about/bundle.json b/platform/commonUI/about/bundle.json
new file mode 100644
index 0000000000..142241449c
--- /dev/null
+++ b/platform/commonUI/about/bundle.json
@@ -0,0 +1,43 @@
+{
+ "name": "About Open MCT Web",
+ "extensions": {
+ "templates": [
+ {
+ "key": "app-logo",
+ "priority": "optional",
+ "templateUrl": "templates/app-logo.html"
+ },
+ {
+ "key": "about-logo",
+ "priority": "preferred",
+ "templateUrl": "templates/about-logo.html"
+ },
+ {
+ "key": "about-dialog",
+ "templateUrl": "templates/about-dialog.html"
+ },
+ {
+ "key": "overlay-about",
+ "templateUrl": "templates/overlay-about.html"
+ }
+ ],
+ "controllers": [
+ {
+ "key": "LogoController",
+ "depends": [ "overlayService" ],
+ "implementation": "LogoController.js"
+ },
+ {
+ "key": "AboutController",
+ "depends": [ "versions[]", "$window" ],
+ "implementation": "AboutController.js"
+ }
+ ],
+ "routes": [
+ {
+ "when": "/licenses",
+ "templateUrl": "templates/licenses.html"
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/platform/commonUI/about/res/templates/about-dialog.html b/platform/commonUI/about/res/templates/about-dialog.html
new file mode 100644
index 0000000000..7840b8860b
--- /dev/null
+++ b/platform/commonUI/about/res/templates/about-dialog.html
@@ -0,0 +1,12 @@
+
+ This is a placeholder for the about dialog.
+
+
Show licenses.
+
+
+
+ {{version.name}}
+ {{version.value}}
+
+
+
diff --git a/platform/commonUI/about/res/templates/about-logo.html b/platform/commonUI/about/res/templates/about-logo.html
new file mode 100644
index 0000000000..2b658c2696
--- /dev/null
+++ b/platform/commonUI/about/res/templates/about-logo.html
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/platform/commonUI/about/res/templates/app-logo.html b/platform/commonUI/about/res/templates/app-logo.html
new file mode 100644
index 0000000000..8b3cefb5c0
--- /dev/null
+++ b/platform/commonUI/about/res/templates/app-logo.html
@@ -0,0 +1 @@
+Open MCT Web
\ No newline at end of file
diff --git a/platform/commonUI/about/res/templates/licenses.html b/platform/commonUI/about/res/templates/licenses.html
new file mode 100644
index 0000000000..c3af087cd9
--- /dev/null
+++ b/platform/commonUI/about/res/templates/licenses.html
@@ -0,0 +1 @@
+Placeholder for open source licenses.
\ No newline at end of file
diff --git a/platform/commonUI/about/res/templates/overlay-about.html b/platform/commonUI/about/res/templates/overlay-about.html
new file mode 100644
index 0000000000..f9af8cd923
--- /dev/null
+++ b/platform/commonUI/about/res/templates/overlay-about.html
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/platform/commonUI/about/src/AboutController.js b/platform/commonUI/about/src/AboutController.js
new file mode 100644
index 0000000000..77c6ede2cb
--- /dev/null
+++ b/platform/commonUI/about/src/AboutController.js
@@ -0,0 +1,42 @@
+/*global define*/
+
+define(
+ [],
+ function () {
+ "use strict";
+
+ /**
+ * The AboutController provides information to populate the
+ * About dialog.
+ * @constructor
+ * @param {object[]} versions an array of version extensions;
+ * injected from `versions[]`
+ * @param $window Angular-injected window object
+ */
+ function AboutController(versions, $window) {
+ return {
+ /**
+ * Get version info. This is given as an array of
+ * objects, where each object is intended to appear
+ * as a line-item in the version information listing.
+ * @memberof AboutController#
+ * @returns {object[]} version information
+ */
+ versions: function () {
+ return versions;
+ },
+ /**
+ * Open a new window (or tab, depending on browser
+ * configuration) containing open source licenses.
+ * @memberof AboutController#
+ */
+ openLicenses: function () {
+ // Open a new browser window at the licenses route
+ $window.open("#/licenses");
+ }
+ };
+ }
+
+ return AboutController;
+ }
+);
\ No newline at end of file
diff --git a/platform/commonUI/about/src/LogoController.js b/platform/commonUI/about/src/LogoController.js
new file mode 100644
index 0000000000..1ff6b7602f
--- /dev/null
+++ b/platform/commonUI/about/src/LogoController.js
@@ -0,0 +1,28 @@
+/*global define*/
+
+define(
+ [],
+ function () {
+ "use strict";
+
+ /**
+ * The LogoController provides functionality to the application
+ * logo in the bottom-right of the user interface.
+ * @constructor
+ * @param {OverlayService} overlayService the overlay service
+ */
+ function LogoController(overlayService) {
+ return {
+ /**
+ * Display the About dialog.
+ * @memberof LogoController#
+ */
+ showAboutDialog: function () {
+ overlayService.createOverlay("overlay-about");
+ }
+ };
+ }
+
+ return LogoController;
+ }
+);
\ No newline at end of file
diff --git a/platform/commonUI/about/test/AboutControllerSpec.js b/platform/commonUI/about/test/AboutControllerSpec.js
new file mode 100644
index 0000000000..1587b42054
--- /dev/null
+++ b/platform/commonUI/about/test/AboutControllerSpec.js
@@ -0,0 +1,39 @@
+/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
+
+define(
+ ['../src/AboutController'],
+ function (AboutController) {
+ "use strict";
+
+ describe("The About controller", function () {
+ var testVersions,
+ mockWindow,
+ controller;
+
+ beforeEach(function () {
+ testVersions = [
+ { name: "Some name", value: "1.2.3" },
+ { name: "Some other name", value: "3.2.1" }
+ ];
+ mockWindow = jasmine.createSpyObj("$window", ["open"]);
+ controller = new AboutController(testVersions, mockWindow);
+ });
+
+ it("exposes version information", function () {
+ // This will be injected, so it should just give back
+ // what it got in.
+ expect(controller.versions()).toEqual(testVersions);
+ });
+
+ it("opens license information in a window", function () {
+ //Verify precondition
+ expect(mockWindow.open).not.toHaveBeenCalled();
+ controller.openLicenses();
+ expect(mockWindow.open).toHaveBeenCalledWith("#/licenses");
+ });
+
+
+ });
+
+ }
+);
\ No newline at end of file
diff --git a/platform/commonUI/about/test/LogoControllerSpec.js b/platform/commonUI/about/test/LogoControllerSpec.js
new file mode 100644
index 0000000000..f3afb2ab57
--- /dev/null
+++ b/platform/commonUI/about/test/LogoControllerSpec.js
@@ -0,0 +1,32 @@
+/*global define,Promise,describe,it,expect,beforeEach,waitsFor,jasmine*/
+
+define(
+ ['../src/LogoController'],
+ function (LogoController) {
+ "use strict";
+
+ describe("The About controller", function () {
+ var mockOverlayService,
+ controller;
+
+ beforeEach(function () {
+ mockOverlayService = jasmine.createSpyObj(
+ "overlayService",
+ ["createOverlay"]
+ );
+ controller = new LogoController(mockOverlayService);
+ });
+
+ it("shows the about dialog", function () {
+ //Verify precondition
+ expect(mockOverlayService.createOverlay)
+ .not.toHaveBeenCalled();
+ controller.showAboutDialog();
+ expect(mockOverlayService.createOverlay)
+ .toHaveBeenCalledWith("overlay-about");
+ });
+
+ });
+
+ }
+);
\ No newline at end of file
diff --git a/platform/commonUI/about/test/suite.json b/platform/commonUI/about/test/suite.json
new file mode 100644
index 0000000000..e626ff9b7a
--- /dev/null
+++ b/platform/commonUI/about/test/suite.json
@@ -0,0 +1,4 @@
+[
+ "AboutController",
+ "LogoController"
+]
\ No newline at end of file
diff --git a/platform/commonUI/dialog/bundle.json b/platform/commonUI/dialog/bundle.json
index feeb0d9e12..ae1c89cc05 100644
--- a/platform/commonUI/dialog/bundle.json
+++ b/platform/commonUI/dialog/bundle.json
@@ -15,6 +15,16 @@
"templates": [
{
"key": "overlay-dialog",
+ "templateUrl": "templates/overlay-dialog.html"
+ },
+ {
+ "key": "form-dialog",
+ "templateUrl": "templates/dialog.html"
+ }
+ ],
+ "containers": [
+ {
+ "key": "overlay",
"templateUrl": "templates/overlay.html"
}
]
diff --git a/platform/commonUI/dialog/res/templates/dialog.html b/platform/commonUI/dialog/res/templates/dialog.html
new file mode 100644
index 0000000000..87cf45d2d6
--- /dev/null
+++ b/platform/commonUI/dialog/res/templates/dialog.html
@@ -0,0 +1,25 @@
+
+
{{ngModel.title}}
+
+ All fields marked * are required.
+
+
+
+
\ No newline at end of file
diff --git a/platform/commonUI/dialog/res/templates/overlay-dialog.html b/platform/commonUI/dialog/res/templates/overlay-dialog.html
new file mode 100644
index 0000000000..74ec58a075
--- /dev/null
+++ b/platform/commonUI/dialog/res/templates/overlay-dialog.html
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/platform/commonUI/dialog/res/templates/overlay.html b/platform/commonUI/dialog/res/templates/overlay.html
index d5e0d7de51..00636d5d90 100644
--- a/platform/commonUI/dialog/res/templates/overlay.html
+++ b/platform/commonUI/dialog/res/templates/overlay.html
@@ -3,32 +3,12 @@
x
-
-
-
{{ngModel.title}}
-
All fields marked * are required.
-
-
-
+ ng-if="ngModel.cancel"
+ class="btn normal outline ui-symbol close">
+ x
+
+
+
\ No newline at end of file
diff --git a/platform/commonUI/dialog/src/DialogService.js b/platform/commonUI/dialog/src/DialogService.js
index b606c1743e..344a407b94 100644
--- a/platform/commonUI/dialog/src/DialogService.js
+++ b/platform/commonUI/dialog/src/DialogService.js
@@ -76,8 +76,8 @@ define(
// Add the overlay using the OverlayService, which
// will handle actual insertion into the DOM
overlay = overlayService.createOverlay(
- overlayModel,
- "overlay-dialog"
+ "overlay-dialog",
+ overlayModel
);
// Track that a dialog is already visible, to
diff --git a/platform/commonUI/dialog/src/OverlayService.js b/platform/commonUI/dialog/src/OverlayService.js
index 580595162d..32fd0c54b4 100644
--- a/platform/commonUI/dialog/src/OverlayService.js
+++ b/platform/commonUI/dialog/src/OverlayService.js
@@ -25,11 +25,21 @@ define(
* @constructor
*/
function OverlayService($document, $compile, $rootScope) {
- function createOverlay(overlayModel, key) {
+ function createOverlay(key, overlayModel) {
// Create a new scope for this overlay
var scope = $rootScope.$new(),
element;
+ // Stop showing the overlay; additionally, release the scope
+ // that it uses.
+ function dismiss() {
+ scope.$destroy();
+ element.remove();
+ }
+
+ // If no model is supplied, just fill in a default "cancel"
+ overlayModel = overlayModel || { cancel: dismiss };
+
// Populate the scope; will be passed directly to the template
scope.overlay = overlayModel;
scope.key = key;
@@ -38,12 +48,7 @@ define(
element = $compile(TEMPLATE)(scope);
$document.find('body').prepend(element);
- // Stop showing the overlay; additionally, release the scope
- // that it uses.
- function dismiss() {
- scope.$destroy();
- element.remove();
- }
+
return {
dismiss: dismiss
@@ -57,11 +62,12 @@ define(
* template (as pointed to by the `key` argument) is
* responsible for having a useful z-order, and for
* blocking user interactions if appropriate.
+ *
+ * @param {string} key the symbolic key which identifies
+ * the template of the overlay to be shown
* @param {object} overlayModel the model to pass to the
* included overlay template (this will be passed
* in via ng-model)
- * @param {string} key the symbolic key which identifies
- * the template of the overlay to be shown
*/
createOverlay: createOverlay
};
diff --git a/platform/commonUI/dialog/test/DialogServiceSpec.js b/platform/commonUI/dialog/test/DialogServiceSpec.js
index 584e793398..9f3635cd9e 100644
--- a/platform/commonUI/dialog/test/DialogServiceSpec.js
+++ b/platform/commonUI/dialog/test/DialogServiceSpec.js
@@ -56,7 +56,7 @@ define(
it("allows user input to be canceled", function () {
dialogService.getUserInput({}, { someKey: "some value" });
- mockOverlayService.createOverlay.mostRecentCall.args[0].cancel();
+ mockOverlayService.createOverlay.mostRecentCall.args[1].cancel();
expect(mockDeferred.reject).toHaveBeenCalled();
expect(mockDeferred.resolve).not.toHaveBeenCalled();
});
@@ -64,7 +64,7 @@ define(
it("passes back the result of user input when confirmed", function () {
var value = { someKey: 42 };
dialogService.getUserInput({}, value);
- mockOverlayService.createOverlay.mostRecentCall.args[0].confirm();
+ mockOverlayService.createOverlay.mostRecentCall.args[1].confirm();
expect(mockDeferred.reject).not.toHaveBeenCalled();
expect(mockDeferred.resolve).toHaveBeenCalledWith(value);
});
@@ -80,7 +80,7 @@ define(
it("can show multiple dialogs if prior ones are dismissed", function () {
dialogService.getUserInput({}, {});
expect(mockLog.warn).not.toHaveBeenCalled();
- mockOverlayService.createOverlay.mostRecentCall.args[0].confirm();
+ mockOverlayService.createOverlay.mostRecentCall.args[1].confirm();
dialogService.getUserInput({}, {});
expect(mockLog.warn).not.toHaveBeenCalled();
expect(mockDeferred.reject).not.toHaveBeenCalled();
diff --git a/platform/commonUI/dialog/test/OverlayServiceSpec.js b/platform/commonUI/dialog/test/OverlayServiceSpec.js
index 0adde5a0ea..5506098571 100644
--- a/platform/commonUI/dialog/test/OverlayServiceSpec.js
+++ b/platform/commonUI/dialog/test/OverlayServiceSpec.js
@@ -8,7 +8,7 @@ define(
function (OverlayService) {
"use strict";
- describe("The dialog service", function () {
+ describe("The overlay service", function () {
var mockDocument,
mockCompile,
mockRootScope,
@@ -40,19 +40,19 @@ define(
});
it("prepends an mct-include to create overlays", function () {
- overlayService.createOverlay({}, "test");
+ overlayService.createOverlay("test", {});
expect(mockCompile).toHaveBeenCalled();
expect(mockCompile.mostRecentCall.args[0].indexOf("mct-include"))
.not.toEqual(-1);
});
it("adds the templated element to the body", function () {
- overlayService.createOverlay({}, "test");
+ overlayService.createOverlay("test", {});
expect(mockBody.prepend).toHaveBeenCalledWith(mockElement);
});
it("places the provided model/key in its template's scope", function () {
- overlayService.createOverlay({ someKey: 42 }, "test");
+ overlayService.createOverlay("test", { someKey: 42 });
expect(mockScope.overlay).toEqual({ someKey: 42 });
expect(mockScope.key).toEqual("test");
@@ -61,7 +61,7 @@ define(
});
it("removes the prepended element on request", function () {
- var overlay = overlayService.createOverlay({}, "test");
+ var overlay = overlayService.createOverlay("test", {});
// Verify precondition
expect(mockElement.remove).not.toHaveBeenCalled();
diff --git a/platform/commonUI/general/res/templates/bottombar.html b/platform/commonUI/general/res/templates/bottombar.html
index 1036fbc336..e7c326d992 100644
--- a/platform/commonUI/general/res/templates/bottombar.html
+++ b/platform/commonUI/general/res/templates/bottombar.html
@@ -5,5 +5,5 @@
key="indicator.template">
-
+
\ No newline at end of file
diff --git a/platform/core/bundle.json b/platform/core/bundle.json
index 6cb0f329f6..3ae730083c 100644
--- a/platform/core/bundle.json
+++ b/platform/core/bundle.json
@@ -3,6 +3,19 @@
"description": "Defines core concepts of Open MCT Web.",
"sources": "src",
"extensions": {
+ "versions": [
+ {
+ "name": "Open MCT Web",
+ "value": "0.3.0-dev",
+ "priority": 1000
+ },
+ {
+ "name": "Built",
+ "value": "YYYY-MM-DDTHH:MM:ssZ",
+ "description": "The date on which this version of the client was built.",
+ "priority": 990
+ }
+ ],
"components": [
{
"provides": "objectService",
diff --git a/platform/framework/bundle.json b/platform/framework/bundle.json
index a09bea185c..057e9287d0 100644
--- a/platform/framework/bundle.json
+++ b/platform/framework/bundle.json
@@ -12,5 +12,6 @@
}
}
},
- "extensions": {}
+ "extensions": {
+ }
}
\ No newline at end of file
diff --git a/platform/representation/src/MCTInclude.js b/platform/representation/src/MCTInclude.js
index 78ac424180..460fac489b 100644
--- a/platform/representation/src/MCTInclude.js
+++ b/platform/representation/src/MCTInclude.js
@@ -37,12 +37,14 @@ define(
// Prepopulate templateMap for easy look up by key
templates.forEach(function (template) {
- var path = [
- template.bundle.path,
- template.bundle.resources,
- template.templateUrl
- ].join("/");
- templateMap[template.key] = path;
+ var key = template.key,
+ path = [
+ template.bundle.path,
+ template.bundle.resources,
+ template.templateUrl
+ ].join("/");
+ // First found should win (priority ordering)
+ templateMap[key] = templateMap[key] || path;
});
function controller($scope) {