From cc470f671a4adf1366fbd55aa4b27bd790516524 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 30 Jun 2015 10:14:26 -0700 Subject: [PATCH 01/84] [Core] Test missing model decorator WTD-1334. --- .../test/models/MissingModelDecoratorSpec.js | 84 +++++++++++++++++++ platform/core/test/suite.json | 1 + 2 files changed, 85 insertions(+) create mode 100644 platform/core/test/models/MissingModelDecoratorSpec.js diff --git a/platform/core/test/models/MissingModelDecoratorSpec.js b/platform/core/test/models/MissingModelDecoratorSpec.js new file mode 100644 index 0000000000..da9d4fc54c --- /dev/null +++ b/platform/core/test/models/MissingModelDecoratorSpec.js @@ -0,0 +1,84 @@ +/***************************************************************************** + * 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,describe,it,expect,beforeEach,waitsFor,jasmine*/ + +define( + ["../../src/models/MissingModelDecorator"], + function (MissingModelDecorator) { + "use strict"; + + describe("The missing model decorator", function () { + var mockModelService, + testModels, + decorator; + + function asPromise(value) { + return (value || {}).then ? value : { + then: function (callback) { + return asPromise(callback(value)); + } + }; + } + + beforeEach(function () { + mockModelService = jasmine.createSpyObj( + "modelService", + [ "getModels" ] + ); + + testModels = { + testId: { someKey: "some value" } + }; + + mockModelService.getModels.andReturn(asPromise(testModels)); + + decorator = new MissingModelDecorator(mockModelService); + }); + + it("delegates to the wrapped model service", function () { + decorator.getModels(['a', 'b', 'c']); + expect(mockModelService.getModels) + .toHaveBeenCalledWith(['a', 'b', 'c']); + }); + + it("provides models for any IDs which are missing", function () { + var models; + decorator.getModels(['testId', 'otherId']) + .then(function (m) { models = m; }); + expect(models.otherId).toBeDefined(); + }); + + it("does not overwrite existing models", function () { + var models; + decorator.getModels(['testId', 'otherId']) + .then(function (m) { models = m; }); + expect(models.testId).toEqual({ someKey: "some value" }); + }); + + it("does not modify the wrapped service's response", function () { + decorator.getModels(['testId', 'otherId']); + expect(testModels.otherId).toBeUndefined(); + }); + }); + + } +); diff --git a/platform/core/test/suite.json b/platform/core/test/suite.json index acc7391d02..e2a7d8f57a 100644 --- a/platform/core/test/suite.json +++ b/platform/core/test/suite.json @@ -15,6 +15,7 @@ "capabilities/RelationshipCapability", "models/ModelAggregator", + "models/MissingModelDecorator", "models/PersistedModelProvider", "models/RootModelProvider", "models/StaticModelProvider", From 3e5fa30d9d17dfab4f526b370afe11ce85941974 Mon Sep 17 00:00:00 2001 From: larkin Date: Tue, 30 Jun 2015 16:18:37 -0700 Subject: [PATCH 02/84] [Style] Add stub for label link icon --- platform/commonUI/general/res/templates/label.html | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/platform/commonUI/general/res/templates/label.html b/platform/commonUI/general/res/templates/label.html index bfa7bd56ff..701e6ff24c 100644 --- a/platform/commonUI/general/res/templates/label.html +++ b/platform/commonUI/general/res/templates/label.html @@ -22,7 +22,14 @@ {{type.getGlyph()}} + - {{model.name}} + + + è + + + {{model.name}} + From d5d7ac90acc929c3bfec92702b34913d47f85319 Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Tue, 30 Jun 2015 17:58:56 -0700 Subject: [PATCH 03/84] [Frontend] Markup and CSS for link icon indicators WTD-1423 Grid item version with link at bottom right of main icon; --- .../browse/res/templates/items/grid-item.html | 8 +- platform/commonUI/general/res/css/items.css | 73 +++++++++++-------- .../general/res/css/theme-espresso.css | 45 +++++++----- platform/commonUI/general/res/css/tree.css | 63 +++++++++------- .../commonUI/general/res/sass/_constants.scss | 3 +- .../commonUI/general/res/sass/_icons.scss | 3 + .../general/res/sass/items/_item.scss | 30 +++++++- .../commonUI/general/res/sass/tree/_tree.scss | 17 ++++- .../commonUI/general/res/templates/label.html | 9 +-- 9 files changed, 163 insertions(+), 88 deletions(-) diff --git a/platform/commonUI/browse/res/templates/items/grid-item.html b/platform/commonUI/browse/res/templates/items/grid-item.html index e64afd4a9f..67d744ca1d 100644 --- a/platform/commonUI/browse/res/templates/items/grid-item.html +++ b/platform/commonUI/browse/res/templates/items/grid-item.html @@ -32,7 +32,13 @@
-
{{type.getGlyph()}}
+
+ {{type.getGlyph()}} + + + ô + +
}
diff --git a/platform/commonUI/general/res/css/items.css b/platform/commonUI/general/res/css/items.css index c40b3f7bd9..ed1e1c6c4e 100644 --- a/platform/commonUI/general/res/css/items.css +++ b/platform/commonUI/general/res/css/items.css @@ -151,59 +151,70 @@ /* line 160, ../sass/_mixins.scss */ .items-holder .item.grid-item.btn-menu .invoke-menu { color: #828282; } - /* line 42, ../sass/items/_item.scss */ - .items-holder .item.grid-item .item-main .item-type { - -moz-transition-property: "color"; - -o-transition-property: "color"; - -webkit-transition-property: "color"; - transition-property: "color"; - -moz-transition-duration: 200ms; - -o-transition-duration: 200ms; - -webkit-transition-duration: 200ms; - transition-duration: 200ms; - -moz-transition-timing-function: ease-in-out; - -o-transition-timing-function: ease-in-out; - -webkit-transition-timing-function: ease-in-out; - transition-timing-function: ease-in-out; } /* line 46, ../sass/items/_item.scss */ .items-holder .item.grid-item:hover .item-main .item-type { color: #0099cc !important; } - /* line 49, ../sass/items/_item.scss */ + /* line 48, ../sass/items/_item.scss */ + .items-holder .item.grid-item:hover .item-main .item-type .l-link-icon { + color: #5bf5ef; } + /* line 52, ../sass/items/_item.scss */ .items-holder .item.grid-item:hover .item-main .item-open { opacity: 1; } - /* line 54, ../sass/items/_item.scss */ + /* line 57, ../sass/items/_item.scss */ .items-holder .item.grid-item .contents { top: 5px; right: 5px; bottom: 5px; left: 5px; } - /* line 58, ../sass/items/_item.scss */ + /* line 61, ../sass/items/_item.scss */ .items-holder .item.grid-item .bar.top-bar.abs { bottom: auto; height: 20px; line-height: 20px; z-index: 5; } - /* line 63, ../sass/items/_item.scss */ + /* line 66, ../sass/items/_item.scss */ .items-holder .item.grid-item .bar.top-bar.abs .left, .items-holder .item.grid-item .bar.top-bar.abs .right { width: auto; } - /* line 65, ../sass/items/_item.scss */ + /* line 68, ../sass/items/_item.scss */ .items-holder .item.grid-item .bar.top-bar.abs .left .icon, .items-holder .item.grid-item .bar.top-bar.abs .right .icon { margin-left: 5px; } - /* line 70, ../sass/items/_item.scss */ + /* line 73, ../sass/items/_item.scss */ .items-holder .item.grid-item .bar.bottom-bar.abs { top: auto; height: 30px; padding: 5px; } - /* line 76, ../sass/items/_item.scss */ + /* line 79, ../sass/items/_item.scss */ .items-holder .item.grid-item .item-main { line-height: 160px; z-index: 1; } - /* line 82, ../sass/items/_item.scss */ + /* line 85, ../sass/items/_item.scss */ .items-holder .item.grid-item .item-main .item-type { + overflow: false; + position: absolute; + top: 40px; + right: 40px; + bottom: 40px; + left: 40px; + width: auto; + height: auto; color: #737373; text-align: center; - font-size: 6em; } - /* line 88, ../sass/items/_item.scss */ + font-size: 96.9px; + line-height: 102px; + bottom: auto; + height: 102px; + top: 30px; } + /* line 97, ../sass/items/_item.scss */ + .items-holder .item.grid-item .item-main .item-type .l-link-icon { + color: #09948f; + height: 36px; + line-height: 36px; + position: absolute; + font-size: 32px; + right: -10px; + bottom: -10px; + z-index: 2; } + /* line 110, ../sass/items/_item.scss */ .items-holder .item.grid-item .item-main .item-open { -moz-transition-property: "opacity"; -o-transition-property: "opacity"; @@ -223,17 +234,17 @@ width: 50px; pointer-events: none; text-align: right; } - /* line 100, ../sass/items/_item.scss */ + /* line 122, ../sass/items/_item.scss */ .items-holder .item.grid-item .title { text-shadow: rgba(0, 0, 0, 0.1) 0 1px 2px; color: #cccccc; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } - /* line 108, ../sass/items/_item.scss */ + /* line 130, ../sass/items/_item.scss */ .items-holder .item.grid-item .details { font-size: 0.8em; } - /* line 111, ../sass/items/_item.scss */ + /* line 133, ../sass/items/_item.scss */ .items-holder .item.grid-item.selected { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzBhYzJmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwYjRmMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; @@ -270,15 +281,15 @@ /* line 160, ../sass/_mixins.scss */ .items-holder .item.grid-item.selected.btn-menu .invoke-menu { color: #52d4ff; } - /* line 116, ../sass/items/_item.scss */ + /* line 138, ../sass/items/_item.scss */ .items-holder .item.grid-item.selected .item-type, .items-holder .item.grid-item.selected .top-bar .icon:not(.alert) { color: #80dfff; } - /* line 117, ../sass/items/_item.scss */ + /* line 139, ../sass/items/_item.scss */ .items-holder .item.grid-item.selected .item-main .item-open { color: #80dfff; } - /* line 118, ../sass/items/_item.scss */ + /* line 140, ../sass/items/_item.scss */ .items-holder .item.grid-item.selected .title { color: white; } - /* line 120, ../sass/items/_item.scss */ + /* line 142, ../sass/items/_item.scss */ .items-holder .item.grid-item.selected:hover .item-main .item-type { color: white !important; } diff --git a/platform/commonUI/general/res/css/theme-espresso.css b/platform/commonUI/general/res/css/theme-espresso.css index 49c5675a07..bc8e713630 100644 --- a/platform/commonUI/general/res/css/theme-espresso.css +++ b/platform/commonUI/general/res/css/theme-espresso.css @@ -92,7 +92,7 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 5, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, @@ -113,38 +113,38 @@ time, mark, audio, video { font-size: 100%; vertical-align: baseline; } -/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 22, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html { line-height: 1; } -/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 24, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ ol, ul { list-style: none; } -/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 26, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ table { border-collapse: collapse; border-spacing: 0; } -/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 28, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } -/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 30, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q, blockquote { quotes: none; } - /* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ + /* line 103, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q:before, q:after, blockquote:before, blockquote:after { content: ""; content: none; } -/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 32, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ a img { border: none; } -/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 116, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } @@ -1256,26 +1256,37 @@ mct-container { .tabular tr td, .tabular tr .td, .tabular .tr td, .tabular .tr .td { border-top: 1px solid rgba(255, 255, 255, 0.1); min-width: 110px; + color: #fff; padding: 2px 5px; vertical-align: top; } - /* line 107, ../sass/lists/_tabular.scss */ + /* line 108, ../sass/lists/_tabular.scss */ .tabular tr td.numeric, .tabular tr .td.numeric, .tabular .tr td.numeric, .tabular .tr .td.numeric { text-align: right; } - /* line 113, ../sass/lists/_tabular.scss */ + /* line 111, ../sass/lists/_tabular.scss */ + .tabular tr td.s-cell-type-value, .tabular tr .td.s-cell-type-value, .tabular .tr td.s-cell-type-value, .tabular .tr .td.s-cell-type-value { + text-align: right; } + /* line 113, ../sass/lists/_tabular.scss */ + .tabular tr td.s-cell-type-value .l-cell-contents, .tabular tr .td.s-cell-type-value .l-cell-contents, .tabular .tr td.s-cell-type-value .l-cell-contents, .tabular .tr .td.s-cell-type-value .l-cell-contents { + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + border-radius: 2px; + padding-left: 5px; + padding-right: 5px; } + /* line 122, ../sass/lists/_tabular.scss */ .tabular.filterable tbody, .tabular.filterable .tbody { top: 36px; } - /* line 118, ../sass/lists/_tabular.scss */ + /* line 127, ../sass/lists/_tabular.scss */ .tabular.fixed-header { height: 100%; } - /* line 120, ../sass/lists/_tabular.scss */ + /* line 129, ../sass/lists/_tabular.scss */ .tabular.fixed-header thead, .tabular.fixed-header .thead, .tabular.fixed-header tbody tr, .tabular.fixed-header .tbody .tr { display: table; table-layout: fixed; } - /* line 125, ../sass/lists/_tabular.scss */ + /* line 134, ../sass/lists/_tabular.scss */ .tabular.fixed-header thead, .tabular.fixed-header .thead { width: calc(100% - 10px); } - /* line 128, ../sass/lists/_tabular.scss */ + /* line 137, ../sass/lists/_tabular.scss */ .tabular.fixed-header tbody, .tabular.fixed-header .tbody { overflow: hidden; position: absolute; @@ -1288,7 +1299,7 @@ mct-container { top: 18px; display: block; overflow-y: scroll; } - /* line 136, ../sass/lists/_tabular.scss */ + /* line 145, ../sass/lists/_tabular.scss */ .tabular.t-event-messages td, .tabular.t-event-messages .td { min-width: 150px; } @@ -2495,7 +2506,7 @@ label.checkbox.custom { -webkit-box-sizing: border-box; box-sizing: border-box; border-top: 1px solid #737373; - line-height: 1.4rem; + line-height: 1.5rem; padding: 3px 10px 3px 30px; white-space: nowrap; } /* line 45, ../sass/controls/_menus.scss */ diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index 75b40aa115..614a74df81 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -122,9 +122,9 @@ ul.tree { -webkit-transition: background-color 0.25s; transition: background-color 0.25s; display: block; - font-size: 0.80em; - height: 1.4rem; - line-height: 1.4rem; + font-size: 0.8em; + height: 1.5rem; + line-height: 1.5rem; margin-bottom: 3px; position: relative; } /* line 38, ../sass/tree/_tree.scss */ @@ -150,17 +150,19 @@ ul.tree { left: 20px; } /* line 55, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .label .type-icon { - overflow: hidden; + overflow: false; position: absolute; - top: 0px; - right: 0px; - bottom: 0px; - left: 0px; + top: 0; + right: 0; + bottom: 0; + left: 0; width: auto; height: auto; text-shadow: rgba(0, 0, 0, 0.6) 0 1px 2px; - color: #0099cc; } - /* line 59, ../sass/tree/_tree.scss */ + color: #0099cc; + right: auto; + width: 1em; } + /* line 60, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .label .type-icon .alert { text-shadow: rgba(0, 0, 0, 0.3) 0 1px 2px; background: #333; @@ -175,7 +177,16 @@ ul.tree { width: auto; position: absolute; z-index: 2; } - /* line 75, ../sass/tree/_tree.scss */ + /* line 75, ../sass/tree/_tree.scss */ + ul.tree li span.tree-item .label .type-icon .icon.l-link-icon { + text-shadow: black 0 1px 2px; + color: #5bf5ef; + position: absolute; + font-size: 0.5em; + right: -5px; + bottom: -8px; + z-index: 2; } + /* line 86, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .label .title-label { overflow: hidden; position: absolute; @@ -186,55 +197,55 @@ ul.tree { width: auto; height: auto; display: block; - left: 20px; + left: 25px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } - /* line 87, ../sass/tree/_tree.scss */ + /* line 98, ../sass/tree/_tree.scss */ ul.tree li span.tree-item.loading { pointer-events: none; } - /* line 89, ../sass/tree/_tree.scss */ + /* line 100, ../sass/tree/_tree.scss */ ul.tree li span.tree-item.loading .label { opacity: 0.5; } - /* line 91, ../sass/tree/_tree.scss */ + /* line 102, ../sass/tree/_tree.scss */ ul.tree li span.tree-item.loading .label .title-label { font-style: italic; } - /* line 95, ../sass/tree/_tree.scss */ + /* line 106, ../sass/tree/_tree.scss */ ul.tree li span.tree-item.loading .wait-spinner { margin-left: 14px; } - /* line 100, ../sass/tree/_tree.scss */ + /* line 111, ../sass/tree/_tree.scss */ ul.tree li span.tree-item.selected { background: #005177; color: #fff; } - /* line 104, ../sass/tree/_tree.scss */ + /* line 115, ../sass/tree/_tree.scss */ ul.tree li span.tree-item.selected .view-control { color: #0099cc; } - /* line 107, ../sass/tree/_tree.scss */ + /* line 118, ../sass/tree/_tree.scss */ ul.tree li span.tree-item.selected .label .type-icon { color: #fff; } - /* line 113, ../sass/tree/_tree.scss */ + /* line 124, ../sass/tree/_tree.scss */ ul.tree li span.tree-item:not(.selected):hover { background: #404040; color: #cccccc; } - /* line 116, ../sass/tree/_tree.scss */ + /* line 127, ../sass/tree/_tree.scss */ ul.tree li span.tree-item:not(.selected):hover .context-trigger { display: block; } - /* line 119, ../sass/tree/_tree.scss */ + /* line 130, ../sass/tree/_tree.scss */ ul.tree li span.tree-item:not(.selected):hover .icon { color: #33ccff; } - /* line 125, ../sass/tree/_tree.scss */ + /* line 136, ../sass/tree/_tree.scss */ ul.tree li span.tree-item:not(.loading) { cursor: pointer; } - /* line 129, ../sass/tree/_tree.scss */ + /* line 140, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .context-trigger { top: -1px; position: absolute; right: 3px; } - /* line 135, ../sass/tree/_tree.scss */ + /* line 146, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .context-trigger .invoke-menu { font-size: 0.75em; height: 0.9rem; line-height: 0.9rem; } - /* line 144, ../sass/tree/_tree.scss */ + /* line 155, ../sass/tree/_tree.scss */ ul.tree ul.tree { margin-left: 15px; } diff --git a/platform/commonUI/general/res/sass/_constants.scss b/platform/commonUI/general/res/sass/_constants.scss index 8a8fed19d1..1cb6b20fda 100644 --- a/platform/commonUI/general/res/sass/_constants.scss +++ b/platform/commonUI/general/res/sass/_constants.scss @@ -42,6 +42,7 @@ $colorKeySelectedBg: #005177; $colorKeyFg: #fff; $colorAlt1: #ffc700; $colorAlert: #ff3c00; +$colorIconLink: #5bf5ef; $colorPausedBg: #c56f01; $colorPausedFg: #fff; $colorCreateBtn: $colorKey; @@ -145,7 +146,7 @@ $controlDisabledOpacity: 0.3; $formLabelW: 20%; $formInputH: 22px; $formRowCtrlsH: 14px; -$menuLineH: 1.4rem; +$menuLineH: 1.5rem; $scrollbarTrackSize: 10px; $scrollbarTrackColorBg: rgba(#000, 0.4); $btnStdH: 25px; diff --git a/platform/commonUI/general/res/sass/_icons.scss b/platform/commonUI/general/res/sass/_icons.scss index 71be99d43a..c0f40a729a 100644 --- a/platform/commonUI/general/res/sass/_icons.scss +++ b/platform/commonUI/general/res/sass/_icons.scss @@ -85,3 +85,6 @@ //font-size: $menuLineH * 0.95 // Normalizing for new icomoon symbols font } +.l-link-icon { +} + diff --git a/platform/commonUI/general/res/sass/items/_item.scss b/platform/commonUI/general/res/sass/items/_item.scss index 5a5cdaf9a3..edfdc619a2 100644 --- a/platform/commonUI/general/res/sass/items/_item.scss +++ b/platform/commonUI/general/res/sass/items/_item.scss @@ -29,6 +29,9 @@ &.grid-item { //div { @include test() } $d: $ueBrowseGridItemLg; + //$iconD: 100px; + $iconMargin: 40px; + $iconD: ($d - ($iconMargin * 2)) * 0.85; $transTime: 200ms; @include btnSubtle($colorItemBase); box-sizing: border-box; @@ -39,12 +42,12 @@ margin-bottom: $interiorMarginSm; margin-right: $interiorMarginSm; position: relative; - .item-main .item-type { - @include trans-prop-nice("color", $transTime); - } &:hover .item-main { .item-type { color: $colorKey !important; + .l-link-icon { + color: $colorIconLink; + } } .item-open { //display: block; @@ -80,10 +83,29 @@ line-height: $lh; z-index: 1; .item-type { + //@include trans-prop-nice("color", $transTime); + @include absPosDefault($iconMargin, false); + //@include test(red); color: $colorItemFg; text-align: center; - font-size: 6em; + font-size: $iconD * 0.95; //6em; + line-height: $iconD; + bottom: auto; + height: $iconD; + top: $iconMargin - 10; //line-height: $lh; + .l-link-icon { + //@include test(blue); + //@include trans-prop-nice("color", $transTime); + color: darken($colorIconLink, 35%); + height: 36px; + line-height: 36px; + position: absolute; + font-size: 32px; + right: -10px; + bottom: -10px; + z-index: 2; + } } .item-open { //@include test(); diff --git a/platform/commonUI/general/res/sass/tree/_tree.scss b/platform/commonUI/general/res/sass/tree/_tree.scss index 356bb8a527..d92c9afebb 100644 --- a/platform/commonUI/general/res/sass/tree/_tree.scss +++ b/platform/commonUI/general/res/sass/tree/_tree.scss @@ -29,7 +29,7 @@ ul.tree { @include border-radius($basicCr); @include single-transition(background-color, 0.25s); display: block; - font-size: 0.80em; + font-size: 0.8em; height: $menuLineH; line-height: $menuLineH; margin-bottom: $interiorMarginSm; @@ -53,9 +53,10 @@ ul.tree { left: $runningItemW + $interiorMargin; .type-icon { - @include absPosDefault(); + @include absPosDefault(0, false); @include txtShdwSubtle(0.6); color: $colorItemTreeIcon; + right: auto; width: 1em; .alert { @include txtShdwSubtle(0.3); background: $colorBodyBg; @@ -71,11 +72,21 @@ ul.tree { position: absolute; z-index: 2; } + .icon.l-link-icon { + @include txtShdwSubtle(1); + $d: 20px; + color: $colorIconLink; + position: absolute; + font-size: 0.5em; + right: -5px; + bottom: -8px; + z-index: 2; + } } .title-label { @include absPosDefault(); display: block; - left: $runningItemW + ($interiorMargin); + left: $runningItemW + ($interiorMargin * 2); //right: $treeContextTriggerW + $interiorMargin; overflow: hidden; text-overflow: ellipsis; diff --git a/platform/commonUI/general/res/templates/label.html b/platform/commonUI/general/res/templates/label.html index 701e6ff24c..da63abd07a 100644 --- a/platform/commonUI/general/res/templates/label.html +++ b/platform/commonUI/general/res/templates/label.html @@ -22,13 +22,12 @@ {{type.getGlyph()}} - + + + ô + - - - è - {{model.name}} From e0727e848597fdfdcfe954297933f77ee71c5b9d Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Tue, 30 Jun 2015 18:13:17 -0700 Subject: [PATCH 04/84] [Frontend] Markup and CSS for link icon indicators WTD-1423 Added small icon to upper right; IN PROGRESS; --- .../browse/res/templates/items/grid-item.html | 6 ++-- platform/commonUI/general/res/css/items.css | 35 ++++++++++--------- platform/commonUI/general/res/css/tree.css | 2 +- .../commonUI/general/res/sass/_constants.scss | 2 +- .../commonUI/general/res/sass/_icons.scss | 6 +--- .../general/res/sass/items/_item.scss | 12 ++++--- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/platform/commonUI/browse/res/templates/items/grid-item.html b/platform/commonUI/browse/res/templates/items/grid-item.html index 67d744ca1d..6372b8c393 100644 --- a/platform/commonUI/browse/res/templates/items/grid-item.html +++ b/platform/commonUI/browse/res/templates/items/grid-item.html @@ -29,15 +29,15 @@
P
+ + ô
{{type.getGlyph()}} - - ô - + ô
}
diff --git a/platform/commonUI/general/res/css/items.css b/platform/commonUI/general/res/css/items.css index ed1e1c6c4e..4b3ac6f8b9 100644 --- a/platform/commonUI/general/res/css/items.css +++ b/platform/commonUI/general/res/css/items.css @@ -156,7 +156,7 @@ color: #0099cc !important; } /* line 48, ../sass/items/_item.scss */ .items-holder .item.grid-item:hover .item-main .item-type .l-link-icon { - color: #5bf5ef; } + color: #49dedb; } /* line 52, ../sass/items/_item.scss */ .items-holder .item.grid-item:hover .item-main .item-open { opacity: 1; } @@ -177,17 +177,20 @@ width: auto; } /* line 68, ../sass/items/_item.scss */ .items-holder .item.grid-item .bar.top-bar.abs .left .icon, .items-holder .item.grid-item .bar.top-bar.abs .right .icon { - margin-left: 5px; } - /* line 73, ../sass/items/_item.scss */ + margin-left: 3px; } + /* line 70, ../sass/items/_item.scss */ + .items-holder .item.grid-item .bar.top-bar.abs .left .icon.l-link-icon, .items-holder .item.grid-item .bar.top-bar.abs .right .icon.l-link-icon { + color: #49dedb; } + /* line 76, ../sass/items/_item.scss */ .items-holder .item.grid-item .bar.bottom-bar.abs { top: auto; height: 30px; padding: 5px; } - /* line 79, ../sass/items/_item.scss */ + /* line 82, ../sass/items/_item.scss */ .items-holder .item.grid-item .item-main { line-height: 160px; z-index: 1; } - /* line 85, ../sass/items/_item.scss */ + /* line 88, ../sass/items/_item.scss */ .items-holder .item.grid-item .item-main .item-type { overflow: false; position: absolute; @@ -204,17 +207,17 @@ bottom: auto; height: 102px; top: 30px; } - /* line 97, ../sass/items/_item.scss */ + /* line 100, ../sass/items/_item.scss */ .items-holder .item.grid-item .item-main .item-type .l-link-icon { - color: #09948f; + color: #1a8e8b; height: 36px; line-height: 36px; position: absolute; font-size: 32px; - right: -10px; + right: -13px; bottom: -10px; z-index: 2; } - /* line 110, ../sass/items/_item.scss */ + /* line 112, ../sass/items/_item.scss */ .items-holder .item.grid-item .item-main .item-open { -moz-transition-property: "opacity"; -o-transition-property: "opacity"; @@ -234,17 +237,17 @@ width: 50px; pointer-events: none; text-align: right; } - /* line 122, ../sass/items/_item.scss */ + /* line 124, ../sass/items/_item.scss */ .items-holder .item.grid-item .title { text-shadow: rgba(0, 0, 0, 0.1) 0 1px 2px; color: #cccccc; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } - /* line 130, ../sass/items/_item.scss */ + /* line 132, ../sass/items/_item.scss */ .items-holder .item.grid-item .details { font-size: 0.8em; } - /* line 133, ../sass/items/_item.scss */ + /* line 135, ../sass/items/_item.scss */ .items-holder .item.grid-item.selected { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzBhYzJmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwYjRmMCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; @@ -281,15 +284,15 @@ /* line 160, ../sass/_mixins.scss */ .items-holder .item.grid-item.selected.btn-menu .invoke-menu { color: #52d4ff; } - /* line 138, ../sass/items/_item.scss */ + /* line 140, ../sass/items/_item.scss */ .items-holder .item.grid-item.selected .item-type, .items-holder .item.grid-item.selected .top-bar .icon:not(.alert) { color: #80dfff; } - /* line 139, ../sass/items/_item.scss */ + /* line 141, ../sass/items/_item.scss */ .items-holder .item.grid-item.selected .item-main .item-open { color: #80dfff; } - /* line 140, ../sass/items/_item.scss */ + /* line 142, ../sass/items/_item.scss */ .items-holder .item.grid-item.selected .title { color: white; } - /* line 142, ../sass/items/_item.scss */ + /* line 144, ../sass/items/_item.scss */ .items-holder .item.grid-item.selected:hover .item-main .item-type { color: white !important; } diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index 614a74df81..ec69f0ebc3 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -180,7 +180,7 @@ ul.tree { /* line 75, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .label .type-icon .icon.l-link-icon { text-shadow: black 0 1px 2px; - color: #5bf5ef; + color: #49dedb; position: absolute; font-size: 0.5em; right: -5px; diff --git a/platform/commonUI/general/res/sass/_constants.scss b/platform/commonUI/general/res/sass/_constants.scss index 1cb6b20fda..c9c3374f76 100644 --- a/platform/commonUI/general/res/sass/_constants.scss +++ b/platform/commonUI/general/res/sass/_constants.scss @@ -42,7 +42,7 @@ $colorKeySelectedBg: #005177; $colorKeyFg: #fff; $colorAlt1: #ffc700; $colorAlert: #ff3c00; -$colorIconLink: #5bf5ef; +$colorIconLink: #49dedb; $colorPausedBg: #c56f01; $colorPausedFg: #fff; $colorCreateBtn: $colorKey; diff --git a/platform/commonUI/general/res/sass/_icons.scss b/platform/commonUI/general/res/sass/_icons.scss index c0f40a729a..69fdf7c472 100644 --- a/platform/commonUI/general/res/sass/_icons.scss +++ b/platform/commonUI/general/res/sass/_icons.scss @@ -83,8 +83,4 @@ .super-menu.menu.dropdown .icon { //font-size: $menuLineH * 0.95 // Normalizing for new icomoon symbols font -} - -.l-link-icon { -} - +} \ No newline at end of file diff --git a/platform/commonUI/general/res/sass/items/_item.scss b/platform/commonUI/general/res/sass/items/_item.scss index edfdc619a2..650585b25d 100644 --- a/platform/commonUI/general/res/sass/items/_item.scss +++ b/platform/commonUI/general/res/sass/items/_item.scss @@ -66,7 +66,10 @@ .left, .right { width: auto; .icon { - margin-left: $interiorMargin; + margin-left: $interiorMarginSm; + &.l-link-icon { + color: $colorIconLink; + } } } } @@ -95,14 +98,13 @@ top: $iconMargin - 10; //line-height: $lh; .l-link-icon { - //@include test(blue); - //@include trans-prop-nice("color", $transTime); - color: darken($colorIconLink, 35%); + // When the link icon is in the item-type icon holder + color: darken($colorIconLink, 25%); height: 36px; line-height: 36px; position: absolute; font-size: 32px; - right: -10px; + right: -13px; bottom: -10px; z-index: 2; } From 2a032bf66d002379a5f75ccd01532ce1e1e2a94d Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Wed, 1 Jul 2015 09:48:35 -0700 Subject: [PATCH 05/84] [Frontend] CSS and font updates ONLY from open1423 WTD-1423 Cherry-pick this into open1404 to get latest fonts and CSS into open-master; --- platform/commonUI/general/res/css/forms.css | 6 +- platform/commonUI/general/res/css/items.css | 22 ++-- .../general/res/css/theme-espresso.css | 110 +++++++++--------- platform/commonUI/general/res/css/tree.css | 62 +++++----- .../symbols/iconmoon.io-WTD-Symbols-v2.0.json | 72 ++++++++---- .../general/res/fonts/symbols/wtdsymbols.eot | Bin 9860 -> 10072 bytes .../general/res/fonts/symbols/wtdsymbols.svg | 3 +- .../general/res/fonts/symbols/wtdsymbols.ttf | Bin 9684 -> 9896 bytes .../general/res/fonts/symbols/wtdsymbols.woff | Bin 9760 -> 9972 bytes .../commonUI/general/res/sass/_icons.scss | 74 ++++++------ .../commonUI/general/res/sass/_mixins.scss | 10 ++ .../general/res/sass/items/_item.scss | 10 +- .../commonUI/general/res/sass/tree/_tree.scss | 54 ++++----- 13 files changed, 229 insertions(+), 194 deletions(-) diff --git a/platform/commonUI/general/res/css/forms.css b/platform/commonUI/general/res/css/forms.css index bc7cbac350..3bb97a0f77 100644 --- a/platform/commonUI/general/res/css/forms.css +++ b/platform/commonUI/general/res/css/forms.css @@ -391,7 +391,7 @@ input[type="text"] { margin: 0 0 2px 2px; overflow: hidden; position: relative; } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .form-control.select:not(.disabled):hover { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; @@ -400,10 +400,10 @@ input[type="text"] { background-image: -webkit-linear-gradient(#636363, #575757); background-image: linear-gradient(#636363, #575757); color: #bdbdbd; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .form-control.select:not(.disabled):hover.btn-menu .invoke-menu { color: #878787; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .form-control.select.btn-menu .invoke-menu { color: #757575; } /* line 29, ../sass/forms/_selects.scss */ diff --git a/platform/commonUI/general/res/css/items.css b/platform/commonUI/general/res/css/items.css index 4b3ac6f8b9..c0ba5edecf 100644 --- a/platform/commonUI/general/res/css/items.css +++ b/platform/commonUI/general/res/css/items.css @@ -136,7 +136,7 @@ margin-bottom: 3px; margin-right: 3px; position: relative; } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .items-holder .item.grid-item:not(.disabled):hover { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzcwNzA3MCIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; @@ -145,17 +145,17 @@ background-image: -webkit-linear-gradient(#707070, #636363); background-image: linear-gradient(#707070, #636363); color: #bdbdbd; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .items-holder .item.grid-item:not(.disabled):hover.btn-menu .invoke-menu { color: #949494; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .items-holder .item.grid-item.btn-menu .invoke-menu { color: #828282; } /* line 46, ../sass/items/_item.scss */ .items-holder .item.grid-item:hover .item-main .item-type { color: #0099cc !important; } /* line 48, ../sass/items/_item.scss */ - .items-holder .item.grid-item:hover .item-main .item-type .l-link-icon { + .items-holder .item.grid-item:hover .item-main .item-type .l-icon-link { color: #49dedb; } /* line 52, ../sass/items/_item.scss */ .items-holder .item.grid-item:hover .item-main .item-open { @@ -179,7 +179,7 @@ .items-holder .item.grid-item .bar.top-bar.abs .left .icon, .items-holder .item.grid-item .bar.top-bar.abs .right .icon { margin-left: 3px; } /* line 70, ../sass/items/_item.scss */ - .items-holder .item.grid-item .bar.top-bar.abs .left .icon.l-link-icon, .items-holder .item.grid-item .bar.top-bar.abs .right .icon.l-link-icon { + .items-holder .item.grid-item .bar.top-bar.abs .left .icon.l-icon-link, .items-holder .item.grid-item .bar.top-bar.abs .right .icon.l-icon-link { color: #49dedb; } /* line 76, ../sass/items/_item.scss */ .items-holder .item.grid-item .bar.bottom-bar.abs { @@ -208,14 +208,14 @@ height: 102px; top: 30px; } /* line 100, ../sass/items/_item.scss */ - .items-holder .item.grid-item .item-main .item-type .l-link-icon { + .items-holder .item.grid-item .item-main .item-type .l-icon-link { color: #1a8e8b; height: 36px; line-height: 36px; position: absolute; font-size: 32px; - right: -13px; - bottom: -10px; + left: 0px; + bottom: 10px; z-index: 2; } /* line 112, ../sass/items/_item.scss */ .items-holder .item.grid-item .item-main .item-open { @@ -269,7 +269,7 @@ color: #999; display: inline-block; color: #80dfff; } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .items-holder .item.grid-item.selected:not(.disabled):hover { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzJlY2JmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzE0YzRmZiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; @@ -278,10 +278,10 @@ background-image: -webkit-linear-gradient(#2ecbff, #14c4ff); background-image: linear-gradient(#2ecbff, #14c4ff); color: #bdbdbd; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .items-holder .item.grid-item.selected:not(.disabled):hover.btn-menu .invoke-menu { color: #75ddff; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .items-holder .item.grid-item.selected.btn-menu .invoke-menu { color: #52d4ff; } /* line 140, ../sass/items/_item.scss */ diff --git a/platform/commonUI/general/res/css/theme-espresso.css b/platform/commonUI/general/res/css/theme-espresso.css index bc8e713630..acf68b7037 100644 --- a/platform/commonUI/general/res/css/theme-espresso.css +++ b/platform/commonUI/general/res/css/theme-espresso.css @@ -92,7 +92,7 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 5, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, @@ -113,38 +113,38 @@ time, mark, audio, video { font-size: 100%; vertical-align: baseline; } -/* line 22, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html { line-height: 1; } -/* line 24, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ ol, ul { list-style: none; } -/* line 26, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ table { border-collapse: collapse; border-spacing: 0; } -/* line 28, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } -/* line 30, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q, blockquote { quotes: none; } - /* line 103, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ + /* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q:before, q:after, blockquote:before, blockquote:after { content: ""; content: none; } -/* line 32, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ a img { border: none; } -/* line 116, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } @@ -1063,27 +1063,33 @@ mct-container { text-shadow: none; display: inline-block; } -/* line 60, ../sass/_icons.scss */ +/* line 57, ../sass/_icons.scss */ .btn-menu .invoke-menu, .icon.major .invoke-menu { margin-left: 3px; } -/* -.object-header .type-icon { - color: $colorKey; - margin-right: $interiorMarginSm; -} -*/ -/* line 72, ../sass/_icons.scss */ +/* line 62, ../sass/_icons.scss */ .menu .type-icon, .tree-item .type-icon, .super-menu.menu .type-icon { position: absolute; } -/* line 80, ../sass/_icons.scss */ +/* line 68, ../sass/_icons.scss */ .tree-item .type-icon { font-size: 16px; } +/* line 72, ../sass/_icons.scss */ +.l-icon-link:before { + content: "\f4"; } + +/* line 76, ../sass/_icons.scss */ +.l-icon-alert { + display: none !important; } + /* line 78, ../sass/_icons.scss */ + .l-icon-alert:before { + color: #ff3c00; + content: "!"; } + /*.s-limit-upr, .s-limit-lwr { $a: 0.5; @@ -1434,7 +1440,7 @@ mct-container { color: #999; display: inline-block; color: #ccf2ff; } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .btn.major:not(.disabled):hover, .s-btn.major:not(.disabled):hover, .major.icon-btn:not(.disabled):hover, @@ -1446,13 +1452,13 @@ mct-container { background-image: -webkit-linear-gradient(#2ecbff, #14c4ff); background-image: linear-gradient(#2ecbff, #14c4ff); color: #bdbdbd; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .btn.major:not(.disabled):hover.btn-menu .invoke-menu, .s-btn.major:not(.disabled):hover.btn-menu .invoke-menu, .major.icon-btn:not(.disabled):hover.btn-menu .invoke-menu, .major.s-icon-btn:not(.disabled):hover.btn-menu .invoke-menu { color: #75ddff; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .btn.major.btn-menu .invoke-menu, .s-btn.major.btn-menu .invoke-menu, .major.btn-menu.icon-btn .invoke-menu, @@ -1482,7 +1488,7 @@ mct-container { border-top: 1px solid #2ecbff; color: #ccf2ff; display: inline-block; } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .btn.major:hover:not(.disabled):hover, .s-btn.major:hover:not(.disabled):hover, .major.icon-btn:hover:not(.disabled):hover, @@ -1494,13 +1500,13 @@ mct-container { background-image: -webkit-linear-gradient(#47d1ff, #2ecbff); background-image: linear-gradient(#47d1ff, #2ecbff); color: white; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .btn.major:hover:not(.disabled):hover.btn-menu .invoke-menu, .s-btn.major:hover:not(.disabled):hover.btn-menu .invoke-menu, .major.icon-btn:hover:not(.disabled):hover.btn-menu .invoke-menu, .major.s-icon-btn:hover:not(.disabled):hover.btn-menu .invoke-menu { color: #8fe3ff; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .btn.major:hover.btn-menu .invoke-menu, .s-btn.major:hover.btn-menu .invoke-menu, .major.icon-btn:hover.btn-menu .invoke-menu, @@ -1536,7 +1542,7 @@ mct-container { border-top: 1px solid #8a8a8a; color: #cccccc; display: inline-block; } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .btn.subtle:not(.disabled):hover, .s-btn.subtle:not(.disabled):hover, .subtle.icon-btn:not(.disabled):hover, @@ -1548,13 +1554,13 @@ mct-container { background-image: -webkit-linear-gradient(#969696, #8a8a8a); background-image: linear-gradient(#969696, #8a8a8a); color: #f0f0f0; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .btn.subtle:not(.disabled):hover.btn-menu .invoke-menu, .s-btn.subtle:not(.disabled):hover.btn-menu .invoke-menu, .subtle.icon-btn:not(.disabled):hover.btn-menu .invoke-menu, .subtle.s-icon-btn:not(.disabled):hover.btn-menu .invoke-menu { color: #bababa; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .btn.subtle.btn-menu .invoke-menu, .s-btn.subtle.btn-menu .invoke-menu, .subtle.btn-menu.icon-btn .invoke-menu, @@ -1587,7 +1593,7 @@ mct-container { border-top: 1px solid #575757; color: #999; display: inline-block; } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .btn.very-subtle:not(.disabled):hover, .btn.s-very-subtle:not(.disabled):hover, .s-btn.very-subtle:not(.disabled):hover, .very-subtle.icon-btn:not(.disabled):hover, @@ -1602,7 +1608,7 @@ mct-container { background-image: -webkit-linear-gradient(#636363, #575757); background-image: linear-gradient(#636363, #575757); color: #bdbdbd; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .btn.very-subtle:not(.disabled):hover.btn-menu .invoke-menu, .btn.s-very-subtle:not(.disabled):hover.btn-menu .invoke-menu, .s-btn.very-subtle:not(.disabled):hover.btn-menu .invoke-menu, .very-subtle.icon-btn:not(.disabled):hover.btn-menu .invoke-menu, @@ -1611,7 +1617,7 @@ mct-container { .s-very-subtle.icon-btn:not(.disabled):hover.btn-menu .invoke-menu, .s-very-subtle.s-icon-btn:not(.disabled):hover.btn-menu .invoke-menu { color: #878787; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .btn.very-subtle.btn-menu .invoke-menu, .btn.s-very-subtle.btn-menu .invoke-menu, .s-btn.very-subtle.btn-menu .invoke-menu, .very-subtle.btn-menu.icon-btn .invoke-menu, @@ -1647,7 +1653,7 @@ mct-container { border-top: 1px solid #fe9510; color: #fff; display: inline-block; } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .btn.very-subtle.paused:not(.disabled):hover, .btn.s-very-subtle.paused:not(.disabled):hover, .s-btn.very-subtle.paused:not(.disabled):hover, .very-subtle.paused.icon-btn:not(.disabled):hover, @@ -1662,7 +1668,7 @@ mct-container { background-image: -webkit-linear-gradient(#fea029, #fe9510); background-image: linear-gradient(#fea029, #fe9510); color: white; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .btn.very-subtle.paused:not(.disabled):hover.btn-menu .invoke-menu, .btn.s-very-subtle.paused:not(.disabled):hover.btn-menu .invoke-menu, .s-btn.very-subtle.paused:not(.disabled):hover.btn-menu .invoke-menu, .very-subtle.paused.icon-btn:not(.disabled):hover.btn-menu .invoke-menu, @@ -1671,7 +1677,7 @@ mct-container { .s-very-subtle.paused.icon-btn:not(.disabled):hover.btn-menu .invoke-menu, .s-very-subtle.paused.s-icon-btn:not(.disabled):hover.btn-menu .invoke-menu { color: #fec070; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .btn.very-subtle.paused.btn-menu .invoke-menu, .btn.s-very-subtle.paused.btn-menu .invoke-menu, .s-btn.very-subtle.paused.btn-menu .invoke-menu, .very-subtle.paused.btn-menu.icon-btn .invoke-menu, @@ -2133,7 +2139,7 @@ label.checkbox.custom { color: lighten($c, 10%); } }*/ } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .btn-menu:not(.disabled):hover { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; @@ -2142,10 +2148,10 @@ label.checkbox.custom { background-image: -webkit-linear-gradient(#636363, #575757); background-image: linear-gradient(#636363, #575757); color: #bdbdbd; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .btn-menu:not(.disabled):hover.btn-menu .invoke-menu { color: #878787; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .btn-menu.btn-menu .invoke-menu { color: #757575; } /* line 285, ../sass/controls/_controls.scss */ @@ -2277,7 +2283,7 @@ label.checkbox.custom { auto: 0; bottom: auto; left: auto; } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .slider .knob:not(.disabled):hover { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; @@ -2286,13 +2292,13 @@ label.checkbox.custom { background-image: -webkit-linear-gradient(#636363, #575757); background-image: linear-gradient(#636363, #575757); color: #bdbdbd; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .slider .knob:not(.disabled):hover.btn-menu .invoke-menu { color: #878787; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .slider .knob.btn-menu .invoke-menu { color: #757575; } - /* line 176, ../sass/_mixins.scss */ + /* line 186, ../sass/_mixins.scss */ .slider .knob:before { -moz-transition-property: "border-color"; -o-transition-property: "border-color"; @@ -2316,7 +2322,7 @@ label.checkbox.custom { left: 2px; bottom: 5px; top: 5px; } - /* line 198, ../sass/_mixins.scss */ + /* line 208, ../sass/_mixins.scss */ .slider .knob:not(.disabled):hover:before { -moz-transition-property: "border-color"; -o-transition-property: "border-color"; @@ -2488,14 +2494,14 @@ label.checkbox.custom { padding: 3px 0; position: absolute; z-index: 10; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .menu-element .menu.btn-menu .invoke-menu { color: #828282; } /* line 37, ../sass/controls/_menus.scss */ .menu-element .menu ul { margin: 0; padding: 0; } - /* line 266, ../sass/_mixins.scss */ + /* line 276, ../sass/_mixins.scss */ .menu-element .menu ul li { list-style-type: none; margin: 0; @@ -2551,7 +2557,7 @@ label.checkbox.custom { border-top: 1px solid #919191; color: #999; display: inline-block; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .menu-element .context-menu.btn-menu .invoke-menu, .menu-element .super-menu.btn-menu .invoke-menu { color: #b0b0b0; } @@ -3414,7 +3420,7 @@ input[type="text"] { margin: 0 0 2px 2px; overflow: hidden; position: relative; } - /* line 152, ../sass/_mixins.scss */ + /* line 162, ../sass/_mixins.scss */ .form-control.select:not(.disabled):hover { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; @@ -3423,10 +3429,10 @@ input[type="text"] { background-image: -webkit-linear-gradient(#636363, #575757); background-image: linear-gradient(#636363, #575757); color: #bdbdbd; } - /* line 155, ../sass/_mixins.scss */ + /* line 165, ../sass/_mixins.scss */ .form-control.select:not(.disabled):hover.btn-menu .invoke-menu { color: #878787; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .form-control.select.btn-menu .invoke-menu { color: #757575; } /* line 29, ../sass/forms/_selects.scss */ @@ -4044,7 +4050,7 @@ input[type="text"] { bottom: 15%; left: 15%; z-index: 101; } - /* line 160, ../sass/_mixins.scss */ + /* line 170, ../sass/_mixins.scss */ .overlay > .holder.btn-menu .invoke-menu { color: #757575; } /* line 45, ../sass/overlay/_overlay.scss */ @@ -4552,7 +4558,7 @@ input[type="text"] { right: 0; width: auto; height: 5px; } - /* line 176, ../sass/_mixins.scss */ + /* line 186, ../sass/_mixins.scss */ .split-layout.horizontal > .splitter:before { -moz-transition-property: "border-color"; -o-transition-property: "border-color"; @@ -4576,7 +4582,7 @@ input[type="text"] { top: 2px; left: 5px; right: 5px; } - /* line 198, ../sass/_mixins.scss */ + /* line 208, ../sass/_mixins.scss */ .split-layout.horizontal > .splitter:not(.disabled):hover:before { -moz-transition-property: "border-color"; -o-transition-property: "border-color"; @@ -4606,7 +4612,7 @@ input[type="text"] { bottom: 0; cursor: col-resize; width: 5px; } - /* line 176, ../sass/_mixins.scss */ + /* line 186, ../sass/_mixins.scss */ .split-layout.vertical > .splitter:before { -moz-transition-property: "border-color"; -o-transition-property: "border-color"; @@ -4630,7 +4636,7 @@ input[type="text"] { left: 2px; bottom: 5px; top: 5px; } - /* line 198, ../sass/_mixins.scss */ + /* line 208, ../sass/_mixins.scss */ .split-layout.vertical > .splitter:not(.disabled):hover:before { -moz-transition-property: "border-color"; -o-transition-property: "border-color"; diff --git a/platform/commonUI/general/res/css/tree.css b/platform/commonUI/general/res/css/tree.css index ec69f0ebc3..b5b16680c8 100644 --- a/platform/commonUI/general/res/css/tree.css +++ b/platform/commonUI/general/res/css/tree.css @@ -99,20 +99,20 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 22, ../sass/tree/_tree.scss */ +/* line 23, ../sass/tree/_tree.scss */ ul.tree { margin: 0; padding: 0; } - /* line 266, ../sass/_mixins.scss */ + /* line 276, ../sass/_mixins.scss */ ul.tree li { list-style-type: none; margin: 0; padding: 0; } - /* line 24, ../sass/tree/_tree.scss */ + /* line 25, ../sass/tree/_tree.scss */ ul.tree li { display: block; position: relative; } - /* line 27, ../sass/tree/_tree.scss */ + /* line 28, ../sass/tree/_tree.scss */ ul.tree li span.tree-item { -moz-border-radius: 2px; -webkit-border-radius: 2px; @@ -127,16 +127,16 @@ ul.tree { line-height: 1.5rem; margin-bottom: 3px; position: relative; } - /* line 38, ../sass/tree/_tree.scss */ + /* line 39, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .view-control { display: inline-block; margin-left: 5px; font-size: 0.75em; width: 10px; } - /* line 44, ../sass/tree/_tree.scss */ + /* line 45, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .view-control:hover { color: #ffc700; } - /* line 49, ../sass/tree/_tree.scss */ + /* line 50, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .label { display: block; overflow: hidden; @@ -147,8 +147,8 @@ ul.tree { left: 0px; width: auto; height: auto; - left: 20px; } - /* line 55, ../sass/tree/_tree.scss */ + left: 15px; } + /* line 57, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .label .type-icon { overflow: false; position: absolute; @@ -160,32 +160,32 @@ ul.tree { height: auto; text-shadow: rgba(0, 0, 0, 0.6) 0 1px 2px; color: #0099cc; + left: 5px; right: auto; width: 1em; } - /* line 60, ../sass/tree/_tree.scss */ - ul.tree li span.tree-item .label .type-icon .alert { - text-shadow: rgba(0, 0, 0, 0.3) 0 1px 2px; - background: #333; - color: #ff3c00; - font-size: 0.7em; - margin-top: -3px; - top: 0; - right: auto; - bottom: auto; - left: 9px; - height: auto; - width: auto; - position: absolute; - z-index: 2; } - /* line 75, ../sass/tree/_tree.scss */ - ul.tree li span.tree-item .label .type-icon .icon.l-link-icon { + /* line 65, ../sass/tree/_tree.scss */ + ul.tree li span.tree-item .label .type-icon .icon.l-icon-link, ul.tree li span.tree-item .label .type-icon .icon.l-icon-alert { text-shadow: black 0 1px 2px; - color: #49dedb; position: absolute; - font-size: 0.5em; - right: -5px; - bottom: -8px; z-index: 2; } + /* line 71, ../sass/tree/_tree.scss */ + ul.tree li span.tree-item .label .type-icon .icon.l-icon-alert { + color: #ff3c00; + font-size: 8px; + line-height: 8px; + height: 8px; + width: 8px; + top: 1px; + right: -2px; } + /* line 77, ../sass/tree/_tree.scss */ + ul.tree li span.tree-item .label .type-icon .icon.l-icon-link { + color: #49dedb; + font-size: 8px; + line-height: 8px; + height: 8px; + width: 8px; + left: -3px; + bottom: 5px; } /* line 86, ../sass/tree/_tree.scss */ ul.tree li span.tree-item .label .title-label { overflow: hidden; @@ -197,7 +197,7 @@ ul.tree { width: auto; height: auto; display: block; - left: 25px; + left: 30px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } diff --git a/platform/commonUI/general/res/fonts/symbols/iconmoon.io-WTD-Symbols-v2.0.json b/platform/commonUI/general/res/fonts/symbols/iconmoon.io-WTD-Symbols-v2.0.json index 45b1da9c33..e2215bed12 100644 --- a/platform/commonUI/general/res/fonts/symbols/iconmoon.io-WTD-Symbols-v2.0.json +++ b/platform/commonUI/general/res/fonts/symbols/iconmoon.io-WTD-Symbols-v2.0.json @@ -1,8 +1,8 @@ { "metadata": { "name": "WTD Symbols v2.", - "lastOpened": 1435266597671, - "created": 1435266594435 + "lastOpened": 1435765696898, + "created": 1435764071891 }, "iconSets": [ { @@ -352,7 +352,7 @@ "tempChar": "" }, { - "order": 45, + "order": 75, "id": 30, "prevSize": 32, "code": 244, @@ -415,13 +415,21 @@ "name": "icon-object", "tempChar": "" }, + { + "order": 73, + "id": 77, + "prevSize": 32, + "code": 63, + "name": "icon-object-unknown", + "tempChar": "" + }, { "order": 53, "id": 22, "prevSize": 32, "code": 86, "name": "icon-packet", - "tempChar": "" + "tempChar": "" }, { "order": 54, @@ -429,7 +437,7 @@ "prevSize": 32, "code": 234, "name": "icon-page", - "tempChar": "" + "tempChar": "" }, { "order": 55, @@ -437,7 +445,7 @@ "prevSize": 32, "code": 241, "name": "icon-pause", - "tempChar": "" + "tempChar": "" }, { "order": 56, @@ -445,7 +453,7 @@ "prevSize": 32, "code": 112, "name": "icon-pencil", - "tempChar": "" + "tempChar": "" }, { "order": 65, @@ -453,7 +461,7 @@ "prevSize": 32, "code": 79, "name": "icon-people", - "tempChar": "" + "tempChar": "" }, { "order": 57, @@ -461,7 +469,7 @@ "prevSize": 32, "code": 239, "name": "icon-play", - "tempChar": "" + "tempChar": "" }, { "order": 58, @@ -469,7 +477,7 @@ "prevSize": 32, "code": 233, "name": "icon-plot-resource", - "tempChar": "" + "tempChar": "" }, { "order": 59, @@ -477,7 +485,7 @@ "prevSize": 32, "code": 43, "name": "icon-plus", - "tempChar": "" + "tempChar": "" }, { "order": 60, @@ -485,7 +493,7 @@ "prevSize": 32, "code": 45, "name": "icon-minus", - "tempChar": "" + "tempChar": "" }, { "order": 61, @@ -493,7 +501,7 @@ "prevSize": 32, "code": 54, "name": "icon-sine", - "tempChar": "" + "tempChar": "" }, { "order": 62, @@ -501,7 +509,7 @@ "prevSize": 32, "code": 228, "name": "icon-T", - "tempChar": "" + "tempChar": "" }, { "order": 63, @@ -509,7 +517,7 @@ "prevSize": 32, "code": 116, "name": "icon-telemetry-panel", - "tempChar": "" + "tempChar": "" }, { "order": 64, @@ -517,7 +525,7 @@ "prevSize": 32, "code": 84, "name": "icon-telemetry", - "tempChar": "" + "tempChar": "" }, { "order": 18, @@ -525,7 +533,7 @@ "prevSize": 32, "code": 246, "name": "icon-thumbs-strip", - "tempChar": "" + "tempChar": "" }, { "order": 67, @@ -533,7 +541,7 @@ "prevSize": 32, "code": 83, "name": "icon-timeline", - "tempChar": "" + "tempChar": "" }, { "order": 68, @@ -541,7 +549,7 @@ "prevSize": 32, "code": 245, "name": "icon-timer", - "tempChar": "" + "tempChar": "" }, { "order": 69, @@ -549,7 +557,7 @@ "prevSize": 32, "code": 90, "name": "icon-trash", - "tempChar": "" + "tempChar": "" }, { "order": 70, @@ -557,7 +565,7 @@ "prevSize": 32, "code": 229, "name": "icon-two-parts-both", - "tempChar": "" + "tempChar": "" }, { "order": 71, @@ -565,7 +573,7 @@ "prevSize": 32, "code": 231, "name": "icon-two-parts-one-only", - "tempChar": "" + "tempChar": "" }, { "order": 72, @@ -573,7 +581,7 @@ "prevSize": 32, "code": 120, "name": "icon-x-heavy", - "tempChar": "" + "tempChar": "" }, { "order": 66, @@ -581,7 +589,7 @@ "prevSize": 32, "code": 58946, "name": "icon-x", - "tempChar": "" + "tempChar": "" } ], "id": 2, @@ -1289,7 +1297,7 @@ { "id": 30, "paths": [ - "M832 0h-640c-105.6 0-192 86.4-192 192v640c0 105.6 86.4 192 192 192h640c105.6 0 192-86.4 192-192v-640c0-105.6-86.4-192-192-192zM832 640l-128-128-512 320 320-512-128-128h448v448z" + "M1024 512l-512-512v307.2l-512 204.8v256h512v256z" ], "attrs": [ {} @@ -1410,6 +1418,20 @@ "icon-object" ] }, + { + "id": 77, + "paths": [ + "M510-2l-512 320v384l512 320 512-320v-384l-512-320zM585.4 859.2c-21.2 20.8-46 30.8-76 30.8-31.2 0-56.2-9.8-76.2-29.6-20-20-29.6-44.8-29.6-76.2 0-30.4 10.2-55.2 31-76.2s45.2-31.2 74.8-31.2c29.6 0 54.2 10.4 75.6 32s31.8 46.4 31.8 76c-0.2 29-10.8 54-31.4 74.4zM638.2 546.6c-23.6 11.8-37.4 22-43.4 32.4-3.6 6.2-6 14.8-7.4 26.8v41h-161.4v-44.2c0-40.2 4.4-69.8 13-88 8-17.2 22.6-30.2 44.8-40l34.8-15.4c32-14.2 48.2-35.2 48.2-62.8 0-16-6-30.4-17.2-41.8-11.2-11.2-25.6-17.2-41.6-17.2-24 0-54.4 10-62.8 57.4l-2.2 12.2h-147l1.4-16.2c4-44.6 17-82.4 38.8-112.2 19.6-27 45.6-48.6 77-64.6s64.6-24 98.2-24c60.6 0 110.2 19.4 151.4 59.6 41.2 40 61.2 88 61.2 147.2 0 70.8-28.8 121.4-85.8 149.8z" + ], + "attrs": [ + {} + ], + "isMulticolor": false, + "grid": 0, + "tags": [ + "icon-object-unknown" + ] + }, { "id": 22, "paths": [ diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.eot index a341f741c908067f4310726966890594b5ee507f..278460b5a892863f3aa8a67a1b5d1bce9938b561 100755 GIT binary patch delta 747 zcmYLGT}TvB6h3!mc7Aq#w{~Z@MR<84FD)-E|*gT_UIuqdy`Lsx^NW(p*r=p4JBg zF(|i*^1-ACBBDZA(5xON3p2|?kmx}|LVAb|dNC|wZg-LB-g7v7=R4=)+;az;KOJOG zQ~}&K3T%SOKN?LI(uMrm#}xonL40p#rZ)!w8US^gM831@Vn?CnY?|OKKxkXGJ=4Y( zikAVxBZN<6NrJN&h2S}YquK7heuJae2`&-6`mUZcnTE>LPeO$VKh~Y;&p``ZAow}K zp>vt;c3*Jm`$>{mCJhgAJ-vNE6AFwWGmCDaMw6wk#y{Zqcmcn~^Y{&(!>{ox{1U&w z7Ji1G;%WQ@PvJ>?3?Icu{0IE|{3*YaXdrWuN}DSbS9H-sOrFLzo}q1e23QEfVE_TS zh@s62iiC}-S`@EOG^9}7F5MeI9yiMof+OaMY!HnoMM}zrkua;G2&vt${~gG-fg;z2 zCe`qI4OLZCO^xZ^n5N}5O^ds9hGx(mj%9UM#OD)u!6R)lILbt{TT`pNzMWfYn}WeW zbu~R>TlRo$p)?vm=|6Whm7JKbtfUepL)T*}O7a@-kcI6v!5Ue1bDA^ckvzO0=ut@v zCv{IqlBCLDVE>MIlU}^ZUGo|U09y>u7Fj}h0S?zz7enSP&y6fH`N9GQT+9c5Q5DJ2 zNBL9g?llmZ@_)eM^wgz)(YzjRK+Wd6aEiq?p<`w`QfD?sKIbj!H=Ur*)02#k*~4@& zH<*$m?Z`Q9J4$Q^JIwyz4soO0J#LkE@~!*?|4ncTHA1WK*y(qUILDnOF)Fr-{o)nz zp*SzDNKF;e;@dpTWQ&ACZxon8Ma87R|t*cmODGmH`xCKfuBZ`GY@W$6L7bO~f#LrF76#@6 zKrf0<{vah{s?N!%t|-Xt@VCLgu+X0gOg8*uV036;JivUQ&>tcGx1r(R0Valqe+~?r z{S|&P$;4Nu7{>G4d}ZKf0XdlA;`WTUFnV%|vN@yAS8z>&q##j%Ft5vLyKEG_{q zIj$V8C0viVesJ?~>u`HZyWDC-fMgud?tJ) neAoC{_&xaJ_}2g(#K^$F!{EbE$^eWeAYcN9i}2=t)su_>>@B3z diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg index 0eef723d78..9c9d712d2d 100755 --- a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg +++ b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.svg @@ -18,6 +18,7 @@ + @@ -72,7 +73,7 @@ - + diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.ttf index e56f67ce32b7029747b46962a71a4e634f6bc831..b113a531a4551bf778e4357d799af1542a883677 100755 GIT binary patch delta 730 zcmYLGTS!z<6g}tOJNNyXa_&rn&eORTnp8SEA2ALQR188d{1K`#9|LI)C}m&cM}ZjR z*oE-Jq6i|QLKyH-ecUX}43j|ml8BIkn4%xUBJODq5}mU*o3+>8i+%Q4P2X=Vg!3Ek zKO%%H!4LLi266}?9UqyT(V780DzsDKv% zS7-YMhfI#%1Y82W#@_z3ndYkGPoP4;PxfVoa;P0$1pEwe=zONH%NJbzb_x<}(C{GF zKQM@BppZE-K6?|lSZ#PLzCzxTW%7nBk=JCAydp2j3-X-U_U@=p2ZMpyT6*5GongnuDLjl*f9~oU zoS3hyq=AxY7%>eec%64C!mhetouX85x)}1v9$pZPYFUpY3{Oaw<*H!d@a}lpD1KqD zdrgcGu^B|$u!QmgT<)-&fqBbwV;d%4UM7eXR|3DN%EZK@{Aq3f29lWacc6E3Ggtma zYdzeITdm4Sk|hq%F{==1u*M=E@;3FGZlW*H(~OTfz;rV=n35~y%DHa4N^Cbf%KqSv zaueJ=Zk-qT4t|RNDu_az&>=h){bE79C6=UWsY4o)u1OE2C23vu$>SJgOv=%gU6p npsXsNlueaY18SQ(qE4!7T2kxPrnCjU0>SGj)LQ%={fz$t))B&7 delta 511 zcmZ4Cd&PT#V*T@LR~Q%=Wq{ZvJ+Ziefq_AQfq^LjNOPp;RHk)(I3Wz=XD~3xM`WZX zrm*#jMKdrc9stUlWdH@(53uk8`9FYsm5khy3MDq?UknUNAoC1z@{<$wwABL`7?gd0 z^0RUiD+(B*7|MbC7eKy3USe*lg#4AaaX`HsKn<%3@{3Ctn1NCZs#_-Rn9FE4IgGL2 z^xXfm|IhqC_5bAm6aSC@KlcCd|3m)|{NMk7*Z-aWcl_V}f7}19|AYSr{STD#kaCl< zmEr^%!8low$zieq6Z_^wrVf_PFWD!E^D;3o{6E0Lzk-!vZa!`uZZGZ> z?it)$xS#NF@$BGb;WglO;|<|W;;rCqBd@fUyJwOu%pv-h5x>BqIP6x1U@9 diff --git a/platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff b/platform/commonUI/general/res/fonts/symbols/wtdsymbols.woff index 88de29cc857dc01ff94549f48566b35ca18298c0..5989698d985a8edf4a4779ef52ba8d97e4303da9 100755 GIT binary patch delta 778 zcmYLHOGs2v82-<_ckW~Eb86g%7uiq2#XdP6>?AKYSB6W$Itoy@BFWGh7Yea>ODv5 z>j42-krfcv^+TWv7bra+4d+%rF1Dw-vH;Wwaq)klwP!B15!(|0{|*cJrgO=3YpMkx zus}G~7TA38YMK}Uf=+S{S>OytNq2Pj5?dSqRauB|^v_J^S;7lt2xrJbO-bTMN2)g) z1qfS7{p)Cgp7W`WR$?Pb(IX4K`LCz5on76e`uY6YeN}As<9B!t&*B;U7Qex- z@hkiizrY55j-TO4{1i{%aeNY=z{kCZya&7quN`PWq~+Q|A0-w?seUF$V-ru&COri# z_~00TfE+~7W(5TUk+KRDtE#R^pvt|vyA-*cEJqw15m#`-QHK(QViAJ@Rz*R=-H`t` zkZA%%wh0Yt#O;o#s-kLYSa*jtEvIQ(%%L+hgYIxFt2=@okH8BqX;Xxw3W#=UYMI-! zXG=wc&sSPrPEVPJ*=HIkiTY4-?VhHR74}$>R1zto>tPked5yQp!p^8KD$7nzv-@3= zix&hvBx!-T?($2LRN^Z=xGUD67c04&?g;r7*kFJ*$Plan*c{s(45`?r>o-5G>3FzU2(+H(gC% zq{kT#v!7{WZZXTYq%CV3wk@-5>;U_nJIW1m54a`X&NuU8{1?G4M1^MIvE6IGVZUu( z7DHmQ*ehNWN5mO%N%BZlQj0Vo$K}iNm^>}d%b(<*3agYVr<8tWNLf%5YDOJXr!^;# N?kH$1?hAcJe*l63$5j9T delta 565 zcmez3yTC`R+~3WOfsp|S)D#%FLA2@>2Byh{OkxvtRO_E#yON$*T)@DmS~v-OHaX8;9(VlF_w3J9|wVByWkEvW#C zWiT)>8i2488}qN6{A8dyWwe{Th_T=F-2b!x&-_32|K$G@|BwGa_W$tzL;nx_-~WHt z|DFGL{NMh6+yAZqgZ~Hp50vtda+9)^;$&cEU<7*EW^w})_vW=s9W0woIVOmQF)=Xw zKfuDke1JiKK^$nEq7s{^poo~UqLG=YpoyBYpgJd`x}qSn!`}w~!a{#0Fxl{rfzhFX z@c{FILVtw#--d>N2bdTd{y8vgel7o#NhZEJ#W0@V<|_j?3(#{63>UX&yoJ$|l+77^ zCR-@mF)^r4-k@wedA;(z`YNVvOy8Kzm}f8_Vt&RV#*)KwfaL?L0&5QIGd3=^0=5h6 z66|X1DePVBk2nlCvN*ap)^I%H)Z?7RCBP-emBY1!>k-!vZa!`uZZGZ>?it)$xS#NF z@$BGb;WglO;|<|W;;rCq Date: Wed, 1 Jul 2015 09:50:53 -0700 Subject: [PATCH 06/84] [Frontend] Markup updates to label and grid-item WTD-1423 Depends on CSS and font updates in 2a032bf --- .../commonUI/browse/res/templates/items/grid-item.html | 9 +++++---- platform/commonUI/general/res/templates/label.html | 9 +++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/platform/commonUI/browse/res/templates/items/grid-item.html b/platform/commonUI/browse/res/templates/items/grid-item.html index 6372b8c393..6d041b48b9 100644 --- a/platform/commonUI/browse/res/templates/items/grid-item.html +++ b/platform/commonUI/browse/res/templates/items/grid-item.html @@ -27,17 +27,18 @@
- +
P
- - ô
{{type.getGlyph()}} - ô +
}
diff --git a/platform/commonUI/general/res/templates/label.html b/platform/commonUI/general/res/templates/label.html index da63abd07a..61905cb7bf 100644 --- a/platform/commonUI/general/res/templates/label.html +++ b/platform/commonUI/general/res/templates/label.html @@ -23,10 +23,11 @@ {{type.getGlyph()}} - - ô - - + + {{model.name}} From 40e85b718dc64796964b93a9826e1bb77a75bf45 Mon Sep 17 00:00:00 2001 From: larkin Date: Tue, 30 Jun 2015 10:55:23 -0700 Subject: [PATCH 07/84] [Creation] Store location of new objects The creation service stores the location (the full path) to the domain object as "model.location" --- .../browse/src/creation/CreationService.js | 25 ++++++++++++++++++ .../test/creation/CreationServiceSpec.js | 26 ++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/platform/commonUI/browse/src/creation/CreationService.js b/platform/commonUI/browse/src/creation/CreationService.js index 015573c8bd..78c0cbebbd 100644 --- a/platform/commonUI/browse/src/creation/CreationService.js +++ b/platform/commonUI/browse/src/creation/CreationService.js @@ -112,12 +112,37 @@ define( return $q.when( uuid() ).then(function (id) { + model = addLocationToModel(id, model, parent); return doPersist(persistence.getSpace(), id, model); }).then(function (id) { return addToComposition(id, parent, persistence); }); } + // Store the location of an object relative to it's parent. + function addLocationToModel(modelId, model, parent) { + var context = parent.getCapability("context"), + pathObjects, + pathIds; + + if (!context) { + $log.warn('No parent context, location will not be set.'); + return model; + } + + pathObjects = context.getPath(); + if (!pathObjects || !pathObjects.length) { + pathObjects = []; + } + pathIds = pathObjects.map(function (object) { + return object.getId(); + }); + pathIds.push(modelId); + + model.location = pathIds.join('/'); + return model; + } + return { /** * Create a new domain object with the provided model, as diff --git a/platform/commonUI/browse/test/creation/CreationServiceSpec.js b/platform/commonUI/browse/test/creation/CreationServiceSpec.js index 277b195eaf..85868974b0 100644 --- a/platform/commonUI/browse/test/creation/CreationServiceSpec.js +++ b/platform/commonUI/browse/test/creation/CreationServiceSpec.js @@ -38,6 +38,7 @@ define( mockMutationCapability, mockPersistenceCapability, mockCompositionCapability, + mockContextCapability, mockCapabilities, creationService; @@ -87,16 +88,30 @@ define( "composition", ["invoke"] ); + mockContextCapability = jasmine.createSpyObj( + "context", + ["getPath"] + ); mockCapabilities = { mutation: mockMutationCapability, persistence: mockPersistenceCapability, - composition: mockCompositionCapability + composition: mockCompositionCapability, + context: mockContextCapability }; mockPersistenceService.createObject.andReturn( mockPromise(true) ); + mockContextCapability.getPath.andReturn([ + { + getId: function () { return 'root'; } + }, + { + getId: function () { return 'parent'; } + } + ]); + mockParentObject.getCapability.andCallFake(function (key) { return mockCapabilities[key]; }); @@ -194,6 +209,15 @@ define( expect(mockLog.error).toHaveBeenCalled(); }); + it("stores location on new domainObjects", function() { + var model = { name: "my model" }; + var objectPromise = creationService.createObject( + model, + mockParentObject + ); + expect(model.location).toBeDefined(); + expect(model.location.indexOf('root/parent')).toBe(0); + }); }); } From 9ea1d241216c7e68a4a9d663ad5b03a6ddff9220 Mon Sep 17 00:00:00 2001 From: larkin Date: Tue, 30 Jun 2015 11:41:15 -0700 Subject: [PATCH 08/84] [Entanglement] Add LocationCapability DomainObjects with a context capability also gain a LocationCapability. This capability allows you to determine the location of the current instance of a domain object, and also provides methods for determining if the current instance of a domain object is a link, or if it is an original. --- platform/entanglement/bundle.json | 6 ++ .../src/capabilities/LocationCapability.js | 66 +++++++++++++++ .../capabilities/LocationCapabilitySpec.js | 81 +++++++++++++++++++ platform/entanglement/test/suite.json | 3 +- 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 platform/entanglement/src/capabilities/LocationCapability.js create mode 100644 platform/entanglement/test/capabilities/LocationCapabilitySpec.js diff --git a/platform/entanglement/bundle.json b/platform/entanglement/bundle.json index 7220669988..2bcf82a72b 100644 --- a/platform/entanglement/bundle.json +++ b/platform/entanglement/bundle.json @@ -37,6 +37,12 @@ "controllers": [ ], "capabilities": [ + { + "key": "location", + "name": "Location Capability", + "description": "Provides a capability for retrieving the location of an object based upon it's context.", + "implementation": "capabilities/LocationCapability" + } ], "services": [ { diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js new file mode 100644 index 0000000000..67dc02a626 --- /dev/null +++ b/platform/entanglement/src/capabilities/LocationCapability.js @@ -0,0 +1,66 @@ +/*global define */ + +define( + + function () { + + function LocationCapability(domainObject) { + this.domainObject = domainObject; + } + + /** + * Return the current location of the current domain object. Only + * valid for domain objects that have a context capability. + */ + LocationCapability.prototype.getLocation = function () { + var context = this.domainObject.getCapability("context"), + pathObjects, + pathIds; + + if (!context) { + return this.domainObject.getId(); + } + + pathObjects = context.getPath(); + if (!pathObjects) { + pathObjects = []; + } + + pathIds = pathObjects.map(function (object) { + return object.getId(); + }); + + return pathIds.join('/'); + }; + + /** + * Returns true if the domainObject is a link, false if it's an + * original. + */ + LocationCapability.prototype.isLink = function () { + var model = this.domainObject.getModel(); + + return model.location !== this.getLocation(); + }; + + /** + * Returns true if the domainObject is an original, false if it's a + * link. + */ + LocationCapability.prototype.isOriginal = function () { + var model = this.domainObject.getModel(); + + return model.location === this.getLocation(); + }; + + /** + * Return true if the LocationCapability can apply to a given + * domainObject, otherwise return false. + */ + LocationCapability.appliesTo = function (domainObject) { + return domainObject.hasCapability('context'); + }; + + return LocationCapability; + } +); diff --git a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js new file mode 100644 index 0000000000..61b3e767f2 --- /dev/null +++ b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js @@ -0,0 +1,81 @@ +/*global define,describe,it,expect,beforeEach */ + +define( + [ + '../../src/capabilities/LocationCapability', + '../DomainObjectFactory' + ], + function (LocationCapability, domainObjectFactory) { + + describe("LocationCapability", function () { + + + it("applies to objects with a context capability", function () { + var domainObject = domainObjectFactory({ + capabilities: { + context: true + } + }); + expect(LocationCapability.appliesTo(domainObject)).toBe(true); + }); + + it("does not apply to objects without context capability", function () { + var domainObject = domainObjectFactory(); + expect(LocationCapability.appliesTo(domainObject)).toBe(false); + }); + + describe("instantiated with domain object", function () { + var locationCapability, + domainObject; + + beforeEach(function () { + domainObject = domainObjectFactory({ + capabilities: { + context: { + getPath: function() { + return [ + { + getId: function () { + return 'root'; + } + }, + { + getId: function () { + return 'parent'; + } + }, + { + getId: function () { + return 'me'; + } + } + ]; + } + } + } + }); + + locationCapability = new LocationCapability(domainObject); + }); + + it("returns location", function () { + expect(locationCapability.getLocation()) + .toBe('root/parent/me'); + }); + + it("knows when the object is an original", function () { + domainObject.model.location = 'root/parent/me'; + expect(locationCapability.isOriginal()).toBe(true); + expect(locationCapability.isLink()).toBe(false); + }); + + it("knows when the object is a link.", function () { + domainObject.model.location = 'root/another/location/me'; + expect(locationCapability.isLink()).toBe(true); + expect(locationCapability.isOriginal()).toBe(false); + }); + + }); + }); + } +); diff --git a/platform/entanglement/test/suite.json b/platform/entanglement/test/suite.json index 40c300e213..5c7f786174 100644 --- a/platform/entanglement/test/suite.json +++ b/platform/entanglement/test/suite.json @@ -5,5 +5,6 @@ "services/CopyService", "services/LinkService", "services/MoveService", - "services/LocationService" + "services/LocationService", + "capabilities/LocationCapability" ] From 449db4f3a9b028339c90b3a94043baf1705e1ab1 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 14:52:42 -0700 Subject: [PATCH 09/84] [Templates] Add stubs for link indicator Update templates to use the location capability to show an indicator. --- platform/commonUI/general/bundle.json | 2 +- .../commonUI/general/res/templates/label.html | 7 +++- .../general/res/templates/tree-node.html | 32 +++++++++---------- 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/platform/commonUI/general/bundle.json b/platform/commonUI/general/bundle.json index 2b8f63c243..33242ccdcf 100644 --- a/platform/commonUI/general/bundle.json +++ b/platform/commonUI/general/bundle.json @@ -196,7 +196,7 @@ { "key": "label", "templateUrl": "templates/label.html", - "uses": [ "type" ], + "uses": [ "type", "location" ], "gestures": [ "drag", "menu", "info" ] }, { diff --git a/platform/commonUI/general/res/templates/label.html b/platform/commonUI/general/res/templates/label.html index bfa7bd56ff..a11ad42646 100644 --- a/platform/commonUI/general/res/templates/label.html +++ b/platform/commonUI/general/res/templates/label.html @@ -24,5 +24,10 @@ {{type.getGlyph()}} - {{model.name}} + + {{model.name}} + {{model.location}} + {{location.getLocation()}} + (link) + diff --git a/platform/commonUI/general/res/templates/tree-node.html b/platform/commonUI/general/res/templates/tree-node.html index f584befb1a..1228604b2e 100644 --- a/platform/commonUI/general/res/templates/tree-node.html +++ b/platform/commonUI/general/res/templates/tree-node.html @@ -22,29 +22,29 @@ + class="tree-item menus-to-left" + ng-class="{selected: treeNode.isSelected()}" + > + class='ui-symbol view-control' + ng-click="toggle.toggle(); treeNode.trackExpansion()" + ng-if="model.composition !== undefined" + > {{toggle.isActive() ? "v" : ">"}} + key="'label'" + mct-object="domainObject" + ng-model="ngModel" + ng-click="ngModel.selectedObject = domainObject" + > + class="tree-item-subtree" + ng-show="toggle.isActive()" + ng-if="model.composition !== undefined" + > Date: Thu, 6 Aug 2015 14:53:59 -0700 Subject: [PATCH 10/84] [Test] add a synchronous controlled promise for testing Add ControlledPromise, a synchronous promise that can be controlled, allowing for easier testing of promise resolution flow. --- .../entanglement/test/ControlledPromise.js | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 platform/entanglement/test/ControlledPromise.js diff --git a/platform/entanglement/test/ControlledPromise.js b/platform/entanglement/test/ControlledPromise.js new file mode 100644 index 0000000000..428bb18d10 --- /dev/null +++ b/platform/entanglement/test/ControlledPromise.js @@ -0,0 +1,78 @@ +/*global define,spyOn */ + +define( + function () { + + /** + * An instrumented promise implementation for better control of promises + * during tests. + * + */ + function ControlledPromise() { + this.resolveHandlers = []; + this.rejectHandlers = []; + spyOn(this, 'then').andCallThrough(); + } + + + /** + * Resolve the promise, passing the supplied value to all resolve + * handlers. + */ + ControlledPromise.prototype.resolve = function(value) { + this.resolveHandlers.forEach(function(handler) { + handler(value); + }); + }; + + /** + * Reject the promise, passing the supplied value to all rejection + * handlers. + */ + ControlledPromise.prototype.reject = function(value) { + this.rejectHandlers.forEach(function(handler) { + handler(value); + }); + }; + + /** + * Standard promise.then, returns a promise that support chaining. + * TODO: Need to support resolve/reject handlers that return promises. + */ + ControlledPromise.prototype.then = function (onResolve, onReject) { + var returnPromise = new ControlledPromise(); + + if (onResolve) { + this.resolveHandlers.push(function(resolveWith) { + var chainResult = onResolve(resolveWith); + if (chainResult && chainResult.then) { + // chainResult is a promise, resolve when it resolves. + chainResult.then(function(pipedResult) { + return returnPromise.resolve(pipedResult); + }); + } else { + returnPromise.resolve(chainResult); + } + }); + } + + if (onReject) { + this.rejectHandlers.push(function(rejectWith) { + var chainResult = onReject(rejectWith); + if (chainResult && chainResult.then) { + chainResult.then(function(pipedResult) { + returnPromise.reject(pipedResult); + }); + } else { + returnPromise.reject(chainResult); + } + }); + } + + return returnPromise; + }; + + return ControlledPromise; + + } +); From 4a755e259f2ca12b8dd3d7c9ba4c479b6d8206fd Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 14:55:50 -0700 Subject: [PATCH 11/84] [Entanglement] Link service returns object in new context The link service return the object in the new context. --- .../entanglement/src/services/LinkService.js | 11 ++++++++ .../test/services/LinkServiceSpec.js | 8 +++++- .../test/services/MockLinkService.js | 27 ++++++------------- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/platform/entanglement/src/services/LinkService.js b/platform/entanglement/src/services/LinkService.js index acecab3b8d..da9a2f92da 100644 --- a/platform/entanglement/src/services/LinkService.js +++ b/platform/entanglement/src/services/LinkService.js @@ -66,6 +66,17 @@ define( } }).then(function () { return parentObject.getCapability('persistence').persist(); + }).then(function getObjectWithNewContext() { + return parentObject + .useCapability('composition') + .then(function (children) { + var i; + for (i = 0; i < children.length; i += 1) { + if (children[i].getId() === object.getId()) { + return children[i]; + } + } + }); }); } }; diff --git a/platform/entanglement/test/services/LinkServiceSpec.js b/platform/entanglement/test/services/LinkServiceSpec.js index 0551256277..80094db519 100644 --- a/platform/entanglement/test/services/LinkServiceSpec.js +++ b/platform/entanglement/test/services/LinkServiceSpec.js @@ -25,7 +25,8 @@ define( [ '../../src/services/LinkService', - '../DomainObjectFactory' + '../DomainObjectFactory', + '../ControlledPromise' ], function (LinkService, domainObjectFactory) { "use strict"; @@ -177,6 +178,11 @@ define( expect(persistenceCapability.persist).toHaveBeenCalled(); }); + + it("returns object representing new link", function () { + linkService.perform(object, parentObject); + + }); }); }); } diff --git a/platform/entanglement/test/services/MockLinkService.js b/platform/entanglement/test/services/MockLinkService.js index 58a82333d3..d4b25b566f 100644 --- a/platform/entanglement/test/services/MockLinkService.js +++ b/platform/entanglement/test/services/MockLinkService.js @@ -23,7 +23,10 @@ /*global define,jasmine */ define( - function () { + [ + '../ControlledPromise' + ], + function (ControlledPromise) { "use strict"; /** @@ -67,26 +70,12 @@ define( callExtensions, spy; - performPromise = jasmine.createSpyObj( - 'performPromise', - ['then'] - ); + performPromise = new ControlledPromise(); - callExtensions = { - promise: performPromise, - resolve: function (resolveWith) { - performPromise.then.calls.forEach(function (call) { - call.args[0](resolveWith); - }); - } - }; + this.perform.mostRecentCall.promise = performPromise; + this.perform.calls[this.perform.calls.length - 1].promise = + performPromise; - spy = this.perform; - - Object.keys(callExtensions).forEach(function (key) { - spy.mostRecentCall[key] = callExtensions[key]; - spy.calls[spy.calls.length - 1][key] = callExtensions[key]; - }); return performPromise; }); From 3783ed69d7ac4f2c3e4d3dfc9f2b69d085239b35 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 15:03:08 -0700 Subject: [PATCH 12/84] [Entanglement] Move updates location of originals When moving original objects, the location is updated to match the new location. --- .../src/capabilities/LocationCapability.js | 20 ++++++++++++++++--- .../entanglement/src/services/MoveService.js | 16 +++++++++++++++ .../test/services/MoveServiceSpec.js | 18 +++++++++++++---- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js index 67dc02a626..99e8a63f59 100644 --- a/platform/entanglement/src/capabilities/LocationCapability.js +++ b/platform/entanglement/src/capabilities/LocationCapability.js @@ -6,6 +6,7 @@ define( function LocationCapability(domainObject) { this.domainObject = domainObject; + return this; } /** @@ -38,6 +39,9 @@ define( * original. */ LocationCapability.prototype.isLink = function () { + if (this.getId() === "mine") { + return false; + } var model = this.domainObject.getModel(); return model.location !== this.getLocation(); @@ -48,19 +52,29 @@ define( * link. */ LocationCapability.prototype.isOriginal = function () { + if (this.getId() === "mine") { + return true; + } var model = this.domainObject.getModel(); return model.location === this.getLocation(); }; + function createLocationCapability(domainObject) { + return new LocationCapability(domainObject); + } + /** * Return true if the LocationCapability can apply to a given * domainObject, otherwise return false. */ - LocationCapability.appliesTo = function (domainObject) { - return domainObject.hasCapability('context'); + createLocationCapability.appliesTo = function (domainObject) { + // if (!domainObject.hasCapability) { + // return false; + // } + // return domainObject.hasCapability('context'); }; - return LocationCapability; + return createLocationCapability; } ); diff --git a/platform/entanglement/src/services/MoveService.js b/platform/entanglement/src/services/MoveService.js index e91d381453..1099821aa9 100644 --- a/platform/entanglement/src/services/MoveService.js +++ b/platform/entanglement/src/services/MoveService.js @@ -69,6 +69,22 @@ define( perform: function (object, parentObject) { return linkService .perform(object, parentObject) + .then(function setOriginalLocation(objectInNewContext) { + var locationCapability = + object.getCapability('location'); + + if (!locationCapability.isOriginal()) { + return objectInNewContext; + } + + return objectInNewContext.useCapability( + 'mutation', + function (model) { + model.location = + locationCapability.getLocation(); + } + ); + }) .then(function () { return object .getCapability('action') diff --git a/platform/entanglement/test/services/MoveServiceSpec.js b/platform/entanglement/test/services/MoveServiceSpec.js index d1ffb52bc1..2cf82c48ac 100644 --- a/platform/entanglement/test/services/MoveServiceSpec.js +++ b/platform/entanglement/test/services/MoveServiceSpec.js @@ -25,7 +25,8 @@ define( [ '../../src/services/MoveService', '../services/MockLinkService', - '../DomainObjectFactory' + '../DomainObjectFactory', + '../ControlledPromise' ], function (MoveService, MockLinkService, domainObjectFactory) { "use strict"; @@ -141,7 +142,8 @@ define( var object, parentObject, - actionCapability; + actionCapability, + locationCapability; beforeEach(function () { actionCapability = jasmine.createSpyObj( @@ -149,10 +151,16 @@ define( ['perform'] ); + locationCapability = jasmine.createSpyObj( + 'locationCapability', + ['isOriginal'] + ); + object = domainObjectFactory({ name: 'object', capabilities: { - action: actionCapability + action: actionCapability, + location: locationCapability } }); @@ -175,8 +183,9 @@ define( .toHaveBeenCalledWith(jasmine.any(Function)); }); + it("removes object when link is completed", function () { - linkService.perform.mostRecentCall.resolve(); + linkService.perform.mostRecentCall.promise.resolve() expect(object.getCapability) .toHaveBeenCalledWith('action'); expect(actionCapability.perform) @@ -185,5 +194,6 @@ define( }); }); + } ); From 5ab26df4c9b4c662548548ffb40dd3ba6333f441 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Tue, 4 Aug 2015 11:56:53 -0700 Subject: [PATCH 13/84] [Scripts] Add script to run karma continuously Add a script (to be executed with `npm run-script watch`) that runs karma and watches for changes; rerunning tests whenever a file is changed. Useful for local development. --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1216935f21..4370b80a30 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "start": "node app.js", "test": "karma start --single-run", "jshint": "jshint platform example || exit 0", - "jsdoc": "jsdoc -c jsdoc.json -r -d docs" + "jsdoc": "jsdoc -c jsdoc.json -r -d docs", + "watch": "karma start" }, "repository": { "type": "git", From 1d162888dde291f8c31dfc6bab11670ac96e508f Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 15:05:00 -0700 Subject: [PATCH 14/84] [Tests] Fix location capability tests --- .../src/capabilities/LocationCapability.js | 4 +- .../capabilities/LocationCapabilitySpec.js | 44 +++++++------------ 2 files changed, 18 insertions(+), 30 deletions(-) diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js index 99e8a63f59..be55509791 100644 --- a/platform/entanglement/src/capabilities/LocationCapability.js +++ b/platform/entanglement/src/capabilities/LocationCapability.js @@ -39,7 +39,7 @@ define( * original. */ LocationCapability.prototype.isLink = function () { - if (this.getId() === "mine") { + if (this.domainObject.getId() === "mine") { return false; } var model = this.domainObject.getModel(); @@ -52,7 +52,7 @@ define( * link. */ LocationCapability.prototype.isOriginal = function () { - if (this.getId() === "mine") { + if (this.domainObject.getId() === "mine") { return true; } var model = this.domainObject.getModel(); diff --git a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js index 61b3e767f2..cec26520e5 100644 --- a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js +++ b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js @@ -10,19 +10,19 @@ define( describe("LocationCapability", function () { - it("applies to objects with a context capability", function () { - var domainObject = domainObjectFactory({ - capabilities: { - context: true - } - }); - expect(LocationCapability.appliesTo(domainObject)).toBe(true); - }); - - it("does not apply to objects without context capability", function () { - var domainObject = domainObjectFactory(); - expect(LocationCapability.appliesTo(domainObject)).toBe(false); - }); + // xit("applies to objects with a context capability", function () { + // var domainObject = domainObjectFactory({ + // capabilities: { + // context: true + // } + // }); + // expect(LocationCapability.appliesTo(domainObject)).toBe(true); + // }); + // + // xit("does not apply to objects without context capability", function () { + // var domainObject = domainObjectFactory(); + // expect(LocationCapability.appliesTo(domainObject)).toBe(false); + // }); describe("instantiated with domain object", function () { var locationCapability, @@ -34,21 +34,9 @@ define( context: { getPath: function() { return [ - { - getId: function () { - return 'root'; - } - }, - { - getId: function () { - return 'parent'; - } - }, - { - getId: function () { - return 'me'; - } - } + domainObjectFactory({id: 'root'}), + domainObjectFactory({id: 'parent'}), + domainObjectFactory({id: 'me'}) ]; } } From 197ec0eb2c841bac2ef473c56fb1eab161f957d1 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 15:05:42 -0700 Subject: [PATCH 15/84] [Tests] Update Link Service Tests --- .../test/services/LinkServiceSpec.js | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/platform/entanglement/test/services/LinkServiceSpec.js b/platform/entanglement/test/services/LinkServiceSpec.js index 80094db519..1d4f6670c3 100644 --- a/platform/entanglement/test/services/LinkServiceSpec.js +++ b/platform/entanglement/test/services/LinkServiceSpec.js @@ -28,7 +28,7 @@ define( '../DomainObjectFactory', '../ControlledPromise' ], - function (LinkService, domainObjectFactory) { + function (LinkService, domainObjectFactory, ControlledPromise) { "use strict"; describe("LinkService", function () { @@ -51,7 +51,6 @@ define( validate; beforeEach(function () { - object = domainObjectFactory({ name: 'object' }); @@ -119,20 +118,29 @@ define( describe("perform", function () { var object, + linkedObject, parentModel, parentObject, mutationPromise, + compositionPromise, + persistencePromise, + compositionCapability, persistenceCapability; beforeEach(function () { - mutationPromise = jasmine.createSpyObj( - 'promise', - ['then'] - ); + mutationPromise = new ControlledPromise(); + compositionPromise = new ControlledPromise(); + persistencePromise = new ControlledPromise(); persistenceCapability = jasmine.createSpyObj( 'persistenceCapability', ['persist'] ); + persistenceCapability.persist.andReturn(persistencePromise); + compositionCapability = jasmine.createSpyObj( + 'compositionCapability', + ['invoke'] + ); + compositionCapability.invoke.andReturn(compositionPromise); parentModel = { composition: [] }; @@ -146,7 +154,8 @@ define( return mutationPromise; } }, - persistence: persistenceCapability + persistence: persistenceCapability, + composition: compositionCapability } }); @@ -155,7 +164,11 @@ define( id: 'xyz' }); - parentObject.getCapability.andReturn(persistenceCapability); + linkedObject = domainObjectFactory({ + name: 'object-link', + id: 'xyz' + }); + }); @@ -172,16 +185,22 @@ define( it("persists parent", function () { linkService.perform(object, parentObject); expect(mutationPromise.then).toHaveBeenCalled(); - mutationPromise.then.calls[0].args[0](); + mutationPromise.resolve(); expect(parentObject.getCapability) .toHaveBeenCalledWith('persistence'); - expect(persistenceCapability.persist).toHaveBeenCalled(); }); it("returns object representing new link", function () { - linkService.perform(object, parentObject); + var returnPromise, whenComplete; + returnPromise = linkService.perform(object, parentObject); + whenComplete = jasmine.createSpy('whenComplete'); + returnPromise.then(whenComplete); + mutationPromise.resolve(); + persistencePromise.resolve(); + compositionPromise.resolve([linkedObject]); + expect(whenComplete).toHaveBeenCalledWith(linkedObject) }); }); }); From 3fb4296d237084f57f5e7b2663bdb57d0bf76c7e Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Tue, 4 Aug 2015 13:13:00 -0700 Subject: [PATCH 16/84] [Testing] MockLinkService returns linked object MockLinkService.perform returns a promise for the linked domainObject. When resolving the promise and not specifying an object to resolve it with, it will resolve it with the domainObject that was originally passed to it. --- .../test/services/MockLinkService.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/platform/entanglement/test/services/MockLinkService.js b/platform/entanglement/test/services/MockLinkService.js index d4b25b566f..cb4f346082 100644 --- a/platform/entanglement/test/services/MockLinkService.js +++ b/platform/entanglement/test/services/MockLinkService.js @@ -50,7 +50,7 @@ define( * var whenLinked = jasmine.createSpy('whenLinked'); * linkService.perform(object, parentObject).then(whenLinked); * expect(whenLinked).not.toHaveBeenCalled(); - * linkService.perform.mostRecentCall.resolve('someArg'); + * linkService.perform.mostRecentCall.promise.resolve('someArg'); * expect(whenLinked).toHaveBeenCalledWith('someArg'); * ``` */ @@ -65,19 +65,19 @@ define( ] ); - mockLinkService.perform.andCallFake(function () { - var performPromise, - callExtensions, - spy; - - performPromise = new ControlledPromise(); + mockLinkService.perform.andCallFake(function (object, newParent) { + var performPromise = new ControlledPromise(); this.perform.mostRecentCall.promise = performPromise; this.perform.calls[this.perform.calls.length - 1].promise = performPromise; - - return performPromise; + return performPromise.then(function (overrideObject) { + if (overrideObject) { + return overrideObject; + } + return object; + }); }); return mockLinkService; From 10ec30ba7621913754d34041764d5cdc72aa9614 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Tue, 4 Aug 2015 13:18:05 -0700 Subject: [PATCH 17/84] [Entanglement] MoveService updates the location of moved objects The move service updates the location of moved objects when those objects are originals. --- .../entanglement/src/services/MoveService.js | 13 +- .../test/services/MoveServiceSpec.js | 174 ++++++++++++++++-- 2 files changed, 170 insertions(+), 17 deletions(-) diff --git a/platform/entanglement/src/services/MoveService.js b/platform/entanglement/src/services/MoveService.js index 1099821aa9..e94d607c5b 100644 --- a/platform/entanglement/src/services/MoveService.js +++ b/platform/entanglement/src/services/MoveService.js @@ -77,13 +77,20 @@ define( return objectInNewContext; } + // TODO: recursively map new objects to old objects, use old object to determine if object was originally a link, and update new object if it was not. + return objectInNewContext.useCapability( 'mutation', function (model) { - model.location = - locationCapability.getLocation(); + model.location = objectInNewContext + .getCapability('location') + .getLocation(); } - ); + ).then(function() { + return objectInNewContext + .getCapability('persistence') + .persist(); + }); }) .then(function () { return object diff --git a/platform/entanglement/test/services/MoveServiceSpec.js b/platform/entanglement/test/services/MoveServiceSpec.js index 2cf82c48ac..bc3d7f08ad 100644 --- a/platform/entanglement/test/services/MoveServiceSpec.js +++ b/platform/entanglement/test/services/MoveServiceSpec.js @@ -28,7 +28,12 @@ define( '../DomainObjectFactory', '../ControlledPromise' ], - function (MoveService, MockLinkService, domainObjectFactory) { + function ( + MoveService, + MockLinkService, + domainObjectFactory, + ControlledPromise + ) { "use strict"; describe("MoveService", function () { @@ -141,9 +146,13 @@ define( describe("perform", function () { var object, - parentObject, + newParent, actionCapability, - locationCapability; + locationCapability, + persistenceCapability, + persistencePromise, + mutationPromise, + moveResult; beforeEach(function () { actionCapability = jasmine.createSpyObj( @@ -153,28 +162,47 @@ define( locationCapability = jasmine.createSpyObj( 'locationCapability', - ['isOriginal'] + [ + 'isOriginal', + 'getLocation' + ] ); + persistenceCapability = jasmine.createSpyObj( + 'persistenceCapability', + ['persist'] + ); + + persistencePromise = new ControlledPromise(); + persistenceCapability.persist.andReturn(persistencePromise); + + mutationPromise = new ControlledPromise(); + object = domainObjectFactory({ name: 'object', capabilities: { action: actionCapability, + mutation: { + invoke: function (mutator) { + mutator(object.model); + return mutationPromise; + } + }, + persistence: persistenceCapability, location: locationCapability + }, + model: { + location: 'otherThing' } }); - parentObject = domainObjectFactory({ - name: 'parentObject' - }); - - moveService.perform(object, parentObject); + moveResult = moveService.perform(object, newParent); }); - it("links object to parentObject", function () { + it("links object to newParent", function () { expect(linkService.perform).toHaveBeenCalledWith( object, - parentObject + newParent ); }); @@ -183,17 +211,135 @@ define( .toHaveBeenCalledWith(jasmine.any(Function)); }); - it("removes object when link is completed", function () { - linkService.perform.mostRecentCall.promise.resolve() + linkService.perform.mostRecentCall.promise.resolve(); expect(object.getCapability) .toHaveBeenCalledWith('action'); expect(actionCapability.perform) .toHaveBeenCalledWith('remove'); }); + describe("when moving an original", function() { + beforeEach(function () { + locationCapability.isOriginal.andReturn(true); + locationCapability.getLocation.andReturn('newParent'); + linkService.perform.mostRecentCall.promise.resolve(); + }); + + it("updates location", function() { + expect(object.model.location).toBe('newParent'); + }); + it("persists new model when mutation completes", function() { + mutationPromise.resolve(); + expect(persistenceCapability.persist) + .toHaveBeenCalled(); + }); + }); + + describe("when moving a link", function() { + beforeEach(function () { + locationCapability.isOriginal.andReturn(false); + locationCapability.getLocation.andReturn('newParent'); + linkService.perform.mostRecentCall.promise.resolve(); + }); + it("does not modify location", function() { + expect(object.model.location).toBe('otherThing'); + }); + it("does not call persistence", function() { + expect(persistenceCapability.persist) + .not + .toHaveBeenCalled(); + }); + }); + + describe("when moving an object with children", function() { + + var children; + + beforeEach(function () { + + var instantMutator = function (index) { + return { + invoke: function (mutator) { + mutator(children[index].model); + return { + then: function(callback) { + callback(); + } + }; + } + }; + }; + + children = [ + domainObjectFactory({ + id: 'childa', + capabilities: { + location: jasmine.createSpyObj( + 'childalocation', + ['isOriginal', 'getLocation'] + ), + mutation: instantMutator(0) + }, + model: { + location: 'childa-old-location' + } + }), + domainObjectFactory({ + id: 'childb', + capabilities: { + location: jasmine.createSpyObj( + 'childblocation', + ['isOriginal', 'getLocation'] + ), + mutation: instantMutator(1) + }, + model: { + location: 'childb-old-location' + } + }), + domainObjectFactory({ + id: 'childc', + capabilities: { + location: jasmine.createSpyObj( + 'childclocation', + ['isOriginal', 'getLocation'] + ), + mutation: instantMutator(2) + }, + model: { + location: 'childc-old-location' + } + }) + ]; + + children[0].capabilities.location.isOriginal.andReturn(true); + children[0].capabilities.location.getLocation.andReturn('childalocation'); + children[1].capabilities.location.isOriginal.andReturn(true); + children[1].capabilities.location.getLocation.andReturn('childblocation'); + children[2].capabilities.location.isOriginal.andReturn(false); + children[2].capabilities.location.getLocation.andReturn('childclocation'); + + object.capabilities.composition = { + invoke: function () { + return { + then: function (callback) { + callback(children); + } + }; + } + }; + linkService.perform.mostRecentCall.promise.resolve(); + }); + + + it("recursively updates the location of originals", function () { + expect(children[0].model.location).toBe('childalocation'); + expect(children[1].model.location).toBe('childblocation'); + expect(children[2].model.location).toBe('childc-old-location'); + }); + }); }); }); - } ); From f083d019a3a6b53eceab652faea8a03946b9b628 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 11:54:14 -0700 Subject: [PATCH 18/84] [Entanglement] Move service recursively updates locations When moving an object that supports composition, child objects which are originals must have their location updated as well. Children which are links should not have their location updated, nor should any of their children be updated. --- platform/entanglement/bundle.json | 2 +- .../entanglement/src/services/MoveService.js | 175 +++++++++++++++--- 2 files changed, 151 insertions(+), 26 deletions(-) diff --git a/platform/entanglement/bundle.json b/platform/entanglement/bundle.json index 2bcf82a72b..c50ac31baf 100644 --- a/platform/entanglement/bundle.json +++ b/platform/entanglement/bundle.json @@ -50,7 +50,7 @@ "name": "Move Service", "description": "Provides a service for moving objects", "implementation": "services/MoveService.js", - "depends": ["policyService", "linkService"] + "depends": ["policyService", "linkService", "$q"] }, { "key": "linkService", diff --git a/platform/entanglement/src/services/MoveService.js b/platform/entanglement/src/services/MoveService.js index e94d607c5b..d35e6a3a4f 100644 --- a/platform/entanglement/src/services/MoveService.js +++ b/platform/entanglement/src/services/MoveService.js @@ -25,13 +25,160 @@ define( function () { "use strict"; - /** * MoveService provides an interface for moving objects from one * location to another. It also provides a method for determining if * an object can be copied to a specific location. */ - function MoveService(policyService, linkService) { + function MoveService(policyService, linkService, $q) { + + + /** + * Returns a promise for a childSelector for a given object which + * returns all original children in that given object. + */ + function getOriginalsInObject(object) { + var originalChildren = {}; + return getOriginalChildren(object) + .then(function recurseChildren(children) { + var promises = []; + children.children.forEach(function(child) { + promises.push(getOriginalsInObject(child)); + originalChildren[child.getId()] = {}; + }); + return $q.all(promises); + }).then(function prepareResponse(childResponses) { + childResponses.forEach(function(childResp) { + Object.keys(childResp).forEach(function(childId) { + originalChildren[childId] = childResp[childId]; + }); + }); + var childSelector = {}; + childSelector[object.getId()] = originalChildren; + return childSelector; + }); + } + + /** + * Get the original children in an object. Returns a promise for an object + * with a single key (the object's key), the value of which is an array + * of original children in that object. + */ + function getOriginalChildren(object) { + if (!object.hasCapability('composition')) { + return $q.when({ + objectId: object.getId(), + children: [] + }); + } + return object.useCapability('composition') + .then(function filterToOriginal(children) { + return children.filter(function(child) { + if (child.hasCapability('location')) { + return child.getCapability('location') + .isOriginal(); + } + return false; + }); + }) + .then(function returnAsObject(children) { + return { + objectId: object.getId(), + children: children + }; + }); + } + + /** + * Persist an instance of an object as the original location of + * that object. + */ + function saveAsOriginal(newOriginal) { + return newOriginal.useCapability( + 'mutation', + function (model) { + model.location = newOriginal + .getCapability('location') + .getLocation(); + } + ).then(function() { + return newOriginal + .getCapability('persistence') + .persist(); + }); + } + + /** + * childrenSelector is an object where keys are childIds and values + * are childSelector objects. Returns all children in the object + * which have a key in the childSelector, plus all children from + * recursive childSelection. + */ + function getMatchingChildrenFromObject(object, childrenSelector) { + var selected = []; + if (!object.hasCapability('composition')) { + return $q.when(selected); + } + return object.useCapability('composition') + .then(function selectChildren(children) { + var promises = []; + children.forEach(function (child) { + if (!childrenSelector[child.getId()]) { + return; + } + selected.push(child); + promises.push(getMatchingChildrenFromObject( + child, + childrenSelector[child.getId()] + )); + }); + + return $q.all(promises) + .then(function reduceResults (results) { + return results.reduce(function(memo, result) { + return memo.concat(result); + }, selected); + }); + }); + } + + + /** + * Uses the original object to determine which objects are originals, + * and then returns a function which, when given the same object in the + * new context, will update the location of all originals in the leaf + * to match the new context. + */ + function updateOriginalLocation(object) { + var oldLocationCapability = object.getCapability('location'); + if (!oldLocationCapability.isOriginal()) { + return function (objectInNewContext) { + return objectInNewContext; + }; + } + return function setOriginalLocation(objectInNewContext) { + return saveAsOriginal(objectInNewContext) + .then(function () { + if (!object.hasCapability('composition')) { + return objectInNewContext; + } + getOriginalsInObject(object) + .then(function(childSelector) { + return getMatchingChildrenFromObject( + objectInNewContext, + childSelector[object.getId()] + ); + }).then(function(originalChildren) { + return $q.all( + originalChildren.map(saveAsOriginal) + ); + }).then(function() { + return objectInNewContext; + }); + }); + }; + } + return { /** * Returns `true` if `object` can be moved into @@ -69,29 +216,7 @@ define( perform: function (object, parentObject) { return linkService .perform(object, parentObject) - .then(function setOriginalLocation(objectInNewContext) { - var locationCapability = - object.getCapability('location'); - - if (!locationCapability.isOriginal()) { - return objectInNewContext; - } - - // TODO: recursively map new objects to old objects, use old object to determine if object was originally a link, and update new object if it was not. - - return objectInNewContext.useCapability( - 'mutation', - function (model) { - model.location = objectInNewContext - .getCapability('location') - .getLocation(); - } - ).then(function() { - return objectInNewContext - .getCapability('persistence') - .persist(); - }); - }) + .then(updateOriginalLocation(object)) .then(function () { return object .getCapability('action') From f72f88adfaab5a1e2b59d79cb939a747a9924de7 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 14:41:32 -0700 Subject: [PATCH 19/84] [Location] Use parent id as location Use the parent id as the location for a model. This greatly reduces the recursive work that must be done during move operations to keep the location accurate. Additionally, the locationService now implements a method `persistLocation` which can be used to persist the current object location as it's original location. --- .../browse/src/creation/CreationService.js | 19 +-- .../test/creation/CreationServiceSpec.js | 17 +- .../src/capabilities/LocationCapability.js | 41 +++-- .../entanglement/src/services/MoveService.js | 158 ++--------------- .../capabilities/LocationCapabilitySpec.js | 78 ++++++--- .../test/services/MoveServiceSpec.js | 159 +++--------------- 6 files changed, 112 insertions(+), 360 deletions(-) diff --git a/platform/commonUI/browse/src/creation/CreationService.js b/platform/commonUI/browse/src/creation/CreationService.js index 78c0cbebbd..f89ac0e909 100644 --- a/platform/commonUI/browse/src/creation/CreationService.js +++ b/platform/commonUI/browse/src/creation/CreationService.js @@ -121,25 +121,8 @@ define( // Store the location of an object relative to it's parent. function addLocationToModel(modelId, model, parent) { - var context = parent.getCapability("context"), - pathObjects, - pathIds; + model.location = parent.getId(); - if (!context) { - $log.warn('No parent context, location will not be set.'); - return model; - } - - pathObjects = context.getPath(); - if (!pathObjects || !pathObjects.length) { - pathObjects = []; - } - pathIds = pathObjects.map(function (object) { - return object.getId(); - }); - pathIds.push(modelId); - - model.location = pathIds.join('/'); return model; } diff --git a/platform/commonUI/browse/test/creation/CreationServiceSpec.js b/platform/commonUI/browse/test/creation/CreationServiceSpec.js index 85868974b0..bb26b1ccd9 100644 --- a/platform/commonUI/browse/test/creation/CreationServiceSpec.js +++ b/platform/commonUI/browse/test/creation/CreationServiceSpec.js @@ -103,21 +103,13 @@ define( mockPromise(true) ); - mockContextCapability.getPath.andReturn([ - { - getId: function () { return 'root'; } - }, - { - getId: function () { return 'parent'; } - } - ]); - mockParentObject.getCapability.andCallFake(function (key) { return mockCapabilities[key]; }); mockParentObject.useCapability.andCallFake(function (key, value) { return mockCapabilities[key].invoke(value); }); + mockParentObject.getId.andReturn('parentId'); mockPersistenceCapability.persist.andReturn( mockPromise(true) @@ -209,16 +201,15 @@ define( expect(mockLog.error).toHaveBeenCalled(); }); - it("stores location on new domainObjects", function() { + it("stores location on new domainObjects", function () { var model = { name: "my model" }; var objectPromise = creationService.createObject( model, mockParentObject ); - expect(model.location).toBeDefined(); - expect(model.location.indexOf('root/parent')).toBe(0); + expect(model.location).toBe('parentId'); }); }); } -); \ No newline at end of file +); diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js index be55509791..66593c7130 100644 --- a/platform/entanglement/src/capabilities/LocationCapability.js +++ b/platform/entanglement/src/capabilities/LocationCapability.js @@ -9,6 +9,23 @@ define( return this; } + /** + * Persist the current location of the current domain object as it's + * primary location. Returns a promise. + */ + LocationCapability.prototype.persistLocation = function () { + return this.domainObject.useCapability( + 'mutation', + function (model) { + model.location = this.getLocation(); + }.bind(this) + ).then(function () { + return this.domainObject + .getCapability('persistence') + .persist(); + }.bind(this)); + }; + /** * Return the current location of the current domain object. Only * valid for domain objects that have a context capability. @@ -19,19 +36,10 @@ define( pathIds; if (!context) { - return this.domainObject.getId(); + return ''; } - pathObjects = context.getPath(); - if (!pathObjects) { - pathObjects = []; - } - - pathIds = pathObjects.map(function (object) { - return object.getId(); - }); - - return pathIds.join('/'); + return context.getParent().getId(); }; /** @@ -64,17 +72,6 @@ define( return new LocationCapability(domainObject); } - /** - * Return true if the LocationCapability can apply to a given - * domainObject, otherwise return false. - */ - createLocationCapability.appliesTo = function (domainObject) { - // if (!domainObject.hasCapability) { - // return false; - // } - // return domainObject.hasCapability('context'); - }; - return createLocationCapability; } ); diff --git a/platform/entanglement/src/services/MoveService.js b/platform/entanglement/src/services/MoveService.js index d35e6a3a4f..7ee5876e4a 100644 --- a/platform/entanglement/src/services/MoveService.js +++ b/platform/entanglement/src/services/MoveService.js @@ -32,153 +32,6 @@ define( */ function MoveService(policyService, linkService, $q) { - - /** - * Returns a promise for a childSelector for a given object which - * returns all original children in that given object. - */ - function getOriginalsInObject(object) { - var originalChildren = {}; - return getOriginalChildren(object) - .then(function recurseChildren(children) { - var promises = []; - children.children.forEach(function(child) { - promises.push(getOriginalsInObject(child)); - originalChildren[child.getId()] = {}; - }); - return $q.all(promises); - }).then(function prepareResponse(childResponses) { - childResponses.forEach(function(childResp) { - Object.keys(childResp).forEach(function(childId) { - originalChildren[childId] = childResp[childId]; - }); - }); - var childSelector = {}; - childSelector[object.getId()] = originalChildren; - return childSelector; - }); - } - - /** - * Get the original children in an object. Returns a promise for an object - * with a single key (the object's key), the value of which is an array - * of original children in that object. - */ - function getOriginalChildren(object) { - if (!object.hasCapability('composition')) { - return $q.when({ - objectId: object.getId(), - children: [] - }); - } - return object.useCapability('composition') - .then(function filterToOriginal(children) { - return children.filter(function(child) { - if (child.hasCapability('location')) { - return child.getCapability('location') - .isOriginal(); - } - return false; - }); - }) - .then(function returnAsObject(children) { - return { - objectId: object.getId(), - children: children - }; - }); - } - - /** - * Persist an instance of an object as the original location of - * that object. - */ - function saveAsOriginal(newOriginal) { - return newOriginal.useCapability( - 'mutation', - function (model) { - model.location = newOriginal - .getCapability('location') - .getLocation(); - } - ).then(function() { - return newOriginal - .getCapability('persistence') - .persist(); - }); - } - - /** - * childrenSelector is an object where keys are childIds and values - * are childSelector objects. Returns all children in the object - * which have a key in the childSelector, plus all children from - * recursive childSelection. - */ - function getMatchingChildrenFromObject(object, childrenSelector) { - var selected = []; - if (!object.hasCapability('composition')) { - return $q.when(selected); - } - return object.useCapability('composition') - .then(function selectChildren(children) { - var promises = []; - children.forEach(function (child) { - if (!childrenSelector[child.getId()]) { - return; - } - selected.push(child); - promises.push(getMatchingChildrenFromObject( - child, - childrenSelector[child.getId()] - )); - }); - - return $q.all(promises) - .then(function reduceResults (results) { - return results.reduce(function(memo, result) { - return memo.concat(result); - }, selected); - }); - }); - } - - - /** - * Uses the original object to determine which objects are originals, - * and then returns a function which, when given the same object in the - * new context, will update the location of all originals in the leaf - * to match the new context. - */ - function updateOriginalLocation(object) { - var oldLocationCapability = object.getCapability('location'); - if (!oldLocationCapability.isOriginal()) { - return function (objectInNewContext) { - return objectInNewContext; - }; - } - return function setOriginalLocation(objectInNewContext) { - return saveAsOriginal(objectInNewContext) - .then(function () { - if (!object.hasCapability('composition')) { - return objectInNewContext; - } - getOriginalsInObject(object) - .then(function(childSelector) { - return getMatchingChildrenFromObject( - objectInNewContext, - childSelector[object.getId()] - ); - }).then(function(originalChildren) { - return $q.all( - originalChildren.map(saveAsOriginal) - ); - }).then(function() { - return objectInNewContext; - }); - }); - }; - } - return { /** * Returns `true` if `object` can be moved into @@ -216,7 +69,16 @@ define( perform: function (object, parentObject) { return linkService .perform(object, parentObject) - .then(updateOriginalLocation(object)) + .then(function (objectInNewContext) { + if (!object.hasCapability('location')) { + return; + } + if (object.getCapability('location').isOriginal()) { + return objectInNewContext + .getCapability('location') + .persistLocation(); + } + }) .then(function () { return object .getCapability('action') diff --git a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js index cec26520e5..e707a34590 100644 --- a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js +++ b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js @@ -3,66 +3,90 @@ define( [ '../../src/capabilities/LocationCapability', - '../DomainObjectFactory' + '../DomainObjectFactory', + '../ControlledPromise' ], - function (LocationCapability, domainObjectFactory) { + function (LocationCapability, domainObjectFactory, ControlledPromise) { describe("LocationCapability", function () { - - // xit("applies to objects with a context capability", function () { - // var domainObject = domainObjectFactory({ - // capabilities: { - // context: true - // } - // }); - // expect(LocationCapability.appliesTo(domainObject)).toBe(true); - // }); - // - // xit("does not apply to objects without context capability", function () { - // var domainObject = domainObjectFactory(); - // expect(LocationCapability.appliesTo(domainObject)).toBe(false); - // }); - describe("instantiated with domain object", function () { var locationCapability, + persistencePromise, + mutationPromise, domainObject; beforeEach(function () { domainObject = domainObjectFactory({ capabilities: { context: { - getPath: function() { - return [ - domainObjectFactory({id: 'root'}), - domainObjectFactory({id: 'parent'}), - domainObjectFactory({id: 'me'}) - ]; + getParent: function() { + return domainObjectFactory({id: 'root'}); } - } + }, + persistence: jasmine.createSpyObj( + 'persistenceCapability', + ['persist'] + ), + mutation: jasmine.createSpyObj( + 'mutationCapability', + ['invoke'] + ) } }); + persistencePromise = new ControlledPromise(); + domainObject.capabilities.persistence.persist.andReturn( + persistencePromise + ); + + mutationPromise = new ControlledPromise(); + domainObject.capabilities.mutation.invoke.andCallFake( + function (mutator) { + return mutationPromise.then(function () { + mutator(domainObject.model); + }); + } + ); + locationCapability = new LocationCapability(domainObject); }); it("returns location", function () { expect(locationCapability.getLocation()) - .toBe('root/parent/me'); + .toBe('root'); }); it("knows when the object is an original", function () { - domainObject.model.location = 'root/parent/me'; + domainObject.model.location = 'root'; expect(locationCapability.isOriginal()).toBe(true); expect(locationCapability.isLink()).toBe(false); }); it("knows when the object is a link.", function () { - domainObject.model.location = 'root/another/location/me'; + domainObject.model.location = 'different-root'; expect(locationCapability.isLink()).toBe(true); expect(locationCapability.isOriginal()).toBe(false); }); + it("can persist location", function () { + var persistResult = locationCapability.persistLocation(), + whenComplete = jasmine.createSpy('whenComplete'); + + persistResult.then(whenComplete); + + expect(domainObject.model.location).not.toBeDefined(); + mutationPromise.resolve(); + expect(domainObject.model.location).toBe('root'); + + expect(whenComplete).not.toHaveBeenCalled(); + expect(domainObject.capabilities.persistence.persist) + .toHaveBeenCalled(); + + persistencePromise.resolve(); + expect(whenComplete).toHaveBeenCalled(); + }); + }); }); } diff --git a/platform/entanglement/test/services/MoveServiceSpec.js b/platform/entanglement/test/services/MoveServiceSpec.js index bc3d7f08ad..b48dd4e66e 100644 --- a/platform/entanglement/test/services/MoveServiceSpec.js +++ b/platform/entanglement/test/services/MoveServiceSpec.js @@ -149,9 +149,7 @@ define( newParent, actionCapability, locationCapability, - persistenceCapability, - persistencePromise, - mutationPromise, + locationPromise, moveResult; beforeEach(function () { @@ -164,35 +162,18 @@ define( 'locationCapability', [ 'isOriginal', - 'getLocation' + 'persistLocation' ] ); - persistenceCapability = jasmine.createSpyObj( - 'persistenceCapability', - ['persist'] - ); - - persistencePromise = new ControlledPromise(); - persistenceCapability.persist.andReturn(persistencePromise); - - mutationPromise = new ControlledPromise(); + locationPromise = new ControlledPromise(); + locationCapability.persistLocation.andReturn(locationPromise); object = domainObjectFactory({ name: 'object', capabilities: { action: actionCapability, - mutation: { - invoke: function (mutator) { - mutator(object.model); - return mutationPromise; - } - }, - persistence: persistenceCapability, location: locationCapability - }, - model: { - location: 'otherThing' } }); @@ -211,134 +192,48 @@ define( .toHaveBeenCalledWith(jasmine.any(Function)); }); - it("removes object when link is completed", function () { - linkService.perform.mostRecentCall.promise.resolve(); - expect(object.getCapability) - .toHaveBeenCalledWith('action'); - expect(actionCapability.perform) - .toHaveBeenCalledWith('remove'); - }); - - describe("when moving an original", function() { + describe("when moving an original", function () { beforeEach(function () { locationCapability.isOriginal.andReturn(true); - locationCapability.getLocation.andReturn('newParent'); linkService.perform.mostRecentCall.promise.resolve(); }); - it("updates location", function() { - expect(object.model.location).toBe('newParent'); - }); - it("persists new model when mutation completes", function() { - mutationPromise.resolve(); - expect(persistenceCapability.persist) + it("updates location", function () { + expect(locationCapability.persistLocation) .toHaveBeenCalled(); }); + + describe("after location update", function () { + beforeEach(function () { + locationPromise.resolve(); + }); + + it("removes object from parent", function () { + expect(actionCapability.perform) + .toHaveBeenCalledWith('remove'); + }); + }); + }); - describe("when moving a link", function() { + describe("when moving a link", function () { beforeEach(function () { locationCapability.isOriginal.andReturn(false); - locationCapability.getLocation.andReturn('newParent'); linkService.perform.mostRecentCall.promise.resolve(); }); - it("does not modify location", function() { - expect(object.model.location).toBe('otherThing'); - }); - it("does not call persistence", function() { - expect(persistenceCapability.persist) + + it("does not update location", function () { + expect(locationCapability.persistLocation) .not .toHaveBeenCalled(); }); - }); - describe("when moving an object with children", function() { - - var children; - - beforeEach(function () { - - var instantMutator = function (index) { - return { - invoke: function (mutator) { - mutator(children[index].model); - return { - then: function(callback) { - callback(); - } - }; - } - }; - }; - - children = [ - domainObjectFactory({ - id: 'childa', - capabilities: { - location: jasmine.createSpyObj( - 'childalocation', - ['isOriginal', 'getLocation'] - ), - mutation: instantMutator(0) - }, - model: { - location: 'childa-old-location' - } - }), - domainObjectFactory({ - id: 'childb', - capabilities: { - location: jasmine.createSpyObj( - 'childblocation', - ['isOriginal', 'getLocation'] - ), - mutation: instantMutator(1) - }, - model: { - location: 'childb-old-location' - } - }), - domainObjectFactory({ - id: 'childc', - capabilities: { - location: jasmine.createSpyObj( - 'childclocation', - ['isOriginal', 'getLocation'] - ), - mutation: instantMutator(2) - }, - model: { - location: 'childc-old-location' - } - }) - ]; - - children[0].capabilities.location.isOriginal.andReturn(true); - children[0].capabilities.location.getLocation.andReturn('childalocation'); - children[1].capabilities.location.isOriginal.andReturn(true); - children[1].capabilities.location.getLocation.andReturn('childblocation'); - children[2].capabilities.location.isOriginal.andReturn(false); - children[2].capabilities.location.getLocation.andReturn('childclocation'); - - object.capabilities.composition = { - invoke: function () { - return { - then: function (callback) { - callback(children); - } - }; - } - }; - linkService.perform.mostRecentCall.promise.resolve(); - }); - - - it("recursively updates the location of originals", function () { - expect(children[0].model.location).toBe('childalocation'); - expect(children[1].model.location).toBe('childblocation'); - expect(children[2].model.location).toBe('childc-old-location'); + it("removes object from parent", function () { + expect(actionCapability.perform) + .toHaveBeenCalledWith('remove'); }); }); + }); }); } From ec62c27f360f4a9a3bff57449684c8d00cf428a4 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 09:49:50 -0700 Subject: [PATCH 20/84] [Representations] grid-item and label display links grid-item and label representations now use the "location" capability to determine whether or not to show a link indicator. --- platform/commonUI/browse/bundle.json | 8 ++++---- .../commonUI/browse/res/templates/items/grid-item.html | 9 ++++----- platform/commonUI/general/res/templates/label.html | 7 +++---- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/platform/commonUI/browse/bundle.json b/platform/commonUI/browse/bundle.json index 7355a6b69c..6e166edb02 100644 --- a/platform/commonUI/browse/bundle.json +++ b/platform/commonUI/browse/bundle.json @@ -69,8 +69,8 @@ { "key": "grid-item", "templateUrl": "templates/items/grid-item.html", - "uses": [ "type", "action" ], - "gestures": [ "info","menu" ] + "uses": [ "type", "action", "location" ], + "gestures": [ "info", "menu" ] }, { "key": "object-header", @@ -88,12 +88,12 @@ { "key": "navigationService", "implementation": "navigation/NavigationService.js" - }, + }, { "key": "creationService", "implementation": "creation/CreationService.js", "depends": [ "persistenceService", "$q", "$log" ] - } + } ], "actions": [ { diff --git a/platform/commonUI/browse/res/templates/items/grid-item.html b/platform/commonUI/browse/res/templates/items/grid-item.html index 6d041b48b9..64282a9ee1 100644 --- a/platform/commonUI/browse/res/templates/items/grid-item.html +++ b/platform/commonUI/browse/res/templates/items/grid-item.html @@ -34,11 +34,10 @@
{{type.getGlyph()}} - + class="ui-symbol icon l-icon-link" title="This object is a link" + ng-show="location.isLink()" + >
}
@@ -51,4 +50,4 @@ - \ No newline at end of file + diff --git a/platform/commonUI/general/res/templates/label.html b/platform/commonUI/general/res/templates/label.html index 61905cb7bf..7ca73bb026 100644 --- a/platform/commonUI/general/res/templates/label.html +++ b/platform/commonUI/general/res/templates/label.html @@ -22,11 +22,10 @@ {{type.getGlyph()}} - + class='ui-symbol icon l-icon-link' + ng-show="location.isLink()" + > From c80e9bfa26e1cdaa5a50d7740b86d27de5368481 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 15:16:16 -0700 Subject: [PATCH 21/84] [Style] JSLint Compliance --- .../commonUI/browse/src/creation/CreationService.js | 13 ++++++------- .../browse/test/creation/CreationServiceSpec.js | 11 ++++++----- .../src/capabilities/LocationCapability.js | 2 +- .../test/capabilities/LocationCapabilitySpec.js | 2 +- .../entanglement/test/services/LinkServiceSpec.js | 2 +- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/platform/commonUI/browse/src/creation/CreationService.js b/platform/commonUI/browse/src/creation/CreationService.js index f89ac0e909..17cc5ce6b3 100644 --- a/platform/commonUI/browse/src/creation/CreationService.js +++ b/platform/commonUI/browse/src/creation/CreationService.js @@ -93,6 +93,12 @@ define( }); } + // Store the location of an object relative to it's parent. + function addLocationToModel(modelId, model, parent) { + model.location = parent.getId(); + return model; + } + // Create a new domain object with the provided model as a // member of the specified parent's composition function createObject(model, parent) { @@ -119,13 +125,6 @@ define( }); } - // Store the location of an object relative to it's parent. - function addLocationToModel(modelId, model, parent) { - model.location = parent.getId(); - - return model; - } - return { /** * Create a new domain object with the provided model, as diff --git a/platform/commonUI/browse/test/creation/CreationServiceSpec.js b/platform/commonUI/browse/test/creation/CreationServiceSpec.js index bb26b1ccd9..7f15afe061 100644 --- a/platform/commonUI/browse/test/creation/CreationServiceSpec.js +++ b/platform/commonUI/browse/test/creation/CreationServiceSpec.js @@ -202,11 +202,12 @@ define( }); it("stores location on new domainObjects", function () { - var model = { name: "my model" }; - var objectPromise = creationService.createObject( - model, - mockParentObject - ); + var model = { name: "my model" }, + objectPromise = creationService.createObject( + model, + mockParentObject + ); + expect(model.location).toBe('parentId'); }); diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js index 66593c7130..3b26c5d58e 100644 --- a/platform/entanglement/src/capabilities/LocationCapability.js +++ b/platform/entanglement/src/capabilities/LocationCapability.js @@ -1,8 +1,8 @@ /*global define */ define( - function () { + "use strict"; function LocationCapability(domainObject) { this.domainObject = domainObject; diff --git a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js index e707a34590..83f166cbec 100644 --- a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js +++ b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js @@ -1,4 +1,4 @@ -/*global define,describe,it,expect,beforeEach */ +/*global define,describe,it,expect,beforeEach,jasmine */ define( [ diff --git a/platform/entanglement/test/services/LinkServiceSpec.js b/platform/entanglement/test/services/LinkServiceSpec.js index 1d4f6670c3..b9bbe62c58 100644 --- a/platform/entanglement/test/services/LinkServiceSpec.js +++ b/platform/entanglement/test/services/LinkServiceSpec.js @@ -200,7 +200,7 @@ define( mutationPromise.resolve(); persistencePromise.resolve(); compositionPromise.resolve([linkedObject]); - expect(whenComplete).toHaveBeenCalledWith(linkedObject) + expect(whenComplete).toHaveBeenCalledWith(linkedObject); }); }); }); From 62f335573a0792cd7d82ddd8f61c73866f547cbf Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 15:41:49 -0700 Subject: [PATCH 22/84] [Build] Bump PhantomJS Version Bump PhantomJS version to latest (for ES5 support) and upgrade dependencies as necessary. --- .../test/lib/run_jasmine_test.coffee | 53 ------------------- .../framework/test/lib/run_jasmine_test.js | 46 ++++++++++++++++ pom.xml | 6 +-- 3 files changed, 49 insertions(+), 56 deletions(-) delete mode 100644 platform/framework/test/lib/run_jasmine_test.coffee create mode 100644 platform/framework/test/lib/run_jasmine_test.js diff --git a/platform/framework/test/lib/run_jasmine_test.coffee b/platform/framework/test/lib/run_jasmine_test.coffee deleted file mode 100644 index 9d9148a0fd..0000000000 --- a/platform/framework/test/lib/run_jasmine_test.coffee +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/local/bin/phantomjs - -# Runs a Jasmine Suite from an html page -# @page is a PhantomJs page object -# @exit_func is the function to call in order to exit the script - -class PhantomJasmineRunner - constructor: (@page, @exit_func = phantom.exit) -> - @tries = 0 - @max_tries = 10 - - get_status: -> @page.evaluate(-> console_reporter.status) - - terminate: -> - switch @get_status() - when "success" then @exit_func 0 - when "fail" then @exit_func 1 - else @exit_func 2 - -# Script Begin -if phantom.args.length == 0 - console.log "Need a url as the argument" - phantom.exit 1 - -page = new WebPage() - -runner = new PhantomJasmineRunner(page) - -# Don't supress console output -page.onConsoleMessage = (msg) -> - console.log msg - - # Terminate when the reporter singals that testing is over. - # We cannot use a callback function for this (because page.evaluate is sandboxed), - # so we have to *observe* the website. - if msg == "ConsoleReporter finished" - if phantom.args.length > 1 - filename = phantom.args[1] - fs = require('fs'); - try - fs.write(filename, page.content) - catch e - console.log "Failed to write test page content." - runner.terminate() - -address = phantom.args[0] - -page.open address, (status) -> - if status != "success" - console.log "Can't load the address!" - phantom.exit 1 - - # Now we wait until onConsoleMessage reads the termination signal from the log. diff --git a/platform/framework/test/lib/run_jasmine_test.js b/platform/framework/test/lib/run_jasmine_test.js new file mode 100644 index 0000000000..c8645f5503 --- /dev/null +++ b/platform/framework/test/lib/run_jasmine_test.js @@ -0,0 +1,46 @@ +var htmlrunner, + resultdir, + page, + fs; + +var system = require('system'); + +if ( system.args.length !== 3 ) { + console.log("Usage: phantom_test_runner.js HTML_RUNNER RESULT_DIR"); + phantom.exit(); +} else { + htmlrunner = system.args[1]; + resultdir = system.args[2]; + page = require("webpage").create(); + fs = require("fs"); + + // Echo the output of the tests to the Standard Output, report status + // when console runner completes. + page.onConsoleMessage = function(msg, source, linenumber) { + console.log(msg); + if (msg === "ConsoleReporter finished") { + var status = page.evaluate(function () { + return console_reporter.status; + }); + if (status === "success") { + phantom.exit(0); + console.log("Test Success"); + } else if (status === "fail") { + phantom.exit(1); + console.log("Test Fail"); + } else { + phantom.exit(2); + console.log("Unexpected test result"); + } + } + }; + + page.open(htmlrunner, function(status) { + if (status === "success") { + console.log("phantomjs> Successfully loaded '" + htmlrunner + "'."); + } else { + console.log("phantomjs> Could not load '" + htmlrunner + "'."); + phantom.exit(1); + } + }); +} diff --git a/pom.xml b/pom.xml index 8ca3cd6edb..9d6508bc97 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ com.github.klieber phantomjs-maven-plugin - 0.2.1 + 0.7 @@ -93,7 +93,7 @@ - 1.9.2 + 2.0.0 @@ -115,7 +115,7 @@ . - platform/framework/test/lib/run_jasmine_test.coffee + platform/framework/test/lib/run_jasmine_test.js test.html ${project.build.directory}/platform-test-results.html From b0a23590d4d783207465bae5b04ebee9d3b0c71c Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 16:53:42 -0700 Subject: [PATCH 23/84] Revert "[Build] Bump PhantomJS Version" This reverts commit 62f335573a0792cd7d82ddd8f61c73866f547cbf. --- .../test/lib/run_jasmine_test.coffee | 53 +++++++++++++++++++ .../framework/test/lib/run_jasmine_test.js | 46 ---------------- pom.xml | 6 +-- 3 files changed, 56 insertions(+), 49 deletions(-) create mode 100644 platform/framework/test/lib/run_jasmine_test.coffee delete mode 100644 platform/framework/test/lib/run_jasmine_test.js diff --git a/platform/framework/test/lib/run_jasmine_test.coffee b/platform/framework/test/lib/run_jasmine_test.coffee new file mode 100644 index 0000000000..9d9148a0fd --- /dev/null +++ b/platform/framework/test/lib/run_jasmine_test.coffee @@ -0,0 +1,53 @@ +#!/usr/local/bin/phantomjs + +# Runs a Jasmine Suite from an html page +# @page is a PhantomJs page object +# @exit_func is the function to call in order to exit the script + +class PhantomJasmineRunner + constructor: (@page, @exit_func = phantom.exit) -> + @tries = 0 + @max_tries = 10 + + get_status: -> @page.evaluate(-> console_reporter.status) + + terminate: -> + switch @get_status() + when "success" then @exit_func 0 + when "fail" then @exit_func 1 + else @exit_func 2 + +# Script Begin +if phantom.args.length == 0 + console.log "Need a url as the argument" + phantom.exit 1 + +page = new WebPage() + +runner = new PhantomJasmineRunner(page) + +# Don't supress console output +page.onConsoleMessage = (msg) -> + console.log msg + + # Terminate when the reporter singals that testing is over. + # We cannot use a callback function for this (because page.evaluate is sandboxed), + # so we have to *observe* the website. + if msg == "ConsoleReporter finished" + if phantom.args.length > 1 + filename = phantom.args[1] + fs = require('fs'); + try + fs.write(filename, page.content) + catch e + console.log "Failed to write test page content." + runner.terminate() + +address = phantom.args[0] + +page.open address, (status) -> + if status != "success" + console.log "Can't load the address!" + phantom.exit 1 + + # Now we wait until onConsoleMessage reads the termination signal from the log. diff --git a/platform/framework/test/lib/run_jasmine_test.js b/platform/framework/test/lib/run_jasmine_test.js deleted file mode 100644 index c8645f5503..0000000000 --- a/platform/framework/test/lib/run_jasmine_test.js +++ /dev/null @@ -1,46 +0,0 @@ -var htmlrunner, - resultdir, - page, - fs; - -var system = require('system'); - -if ( system.args.length !== 3 ) { - console.log("Usage: phantom_test_runner.js HTML_RUNNER RESULT_DIR"); - phantom.exit(); -} else { - htmlrunner = system.args[1]; - resultdir = system.args[2]; - page = require("webpage").create(); - fs = require("fs"); - - // Echo the output of the tests to the Standard Output, report status - // when console runner completes. - page.onConsoleMessage = function(msg, source, linenumber) { - console.log(msg); - if (msg === "ConsoleReporter finished") { - var status = page.evaluate(function () { - return console_reporter.status; - }); - if (status === "success") { - phantom.exit(0); - console.log("Test Success"); - } else if (status === "fail") { - phantom.exit(1); - console.log("Test Fail"); - } else { - phantom.exit(2); - console.log("Unexpected test result"); - } - } - }; - - page.open(htmlrunner, function(status) { - if (status === "success") { - console.log("phantomjs> Successfully loaded '" + htmlrunner + "'."); - } else { - console.log("phantomjs> Could not load '" + htmlrunner + "'."); - phantom.exit(1); - } - }); -} diff --git a/pom.xml b/pom.xml index 9d6508bc97..8ca3cd6edb 100644 --- a/pom.xml +++ b/pom.xml @@ -84,7 +84,7 @@ com.github.klieber phantomjs-maven-plugin - 0.7 + 0.2.1 @@ -93,7 +93,7 @@ - 2.0.0 + 1.9.2 @@ -115,7 +115,7 @@ . - platform/framework/test/lib/run_jasmine_test.js + platform/framework/test/lib/run_jasmine_test.coffee test.html ${project.build.directory}/platform-test-results.html From 058a0d393def0b127bbb067a7ae5c694e9c43d60 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Thu, 6 Aug 2015 16:55:15 -0700 Subject: [PATCH 24/84] [Compatibility] Store reference instead of binding --- .../entanglement/src/capabilities/LocationCapability.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js index 3b26c5d58e..c40a3810c1 100644 --- a/platform/entanglement/src/capabilities/LocationCapability.js +++ b/platform/entanglement/src/capabilities/LocationCapability.js @@ -14,16 +14,17 @@ define( * primary location. Returns a promise. */ LocationCapability.prototype.persistLocation = function () { + var capability = this; return this.domainObject.useCapability( 'mutation', function (model) { - model.location = this.getLocation(); - }.bind(this) + model.location = capability.getLocation(); + } ).then(function () { - return this.domainObject + return capability.domainObject .getCapability('persistence') .persist(); - }.bind(this)); + }); }; /** From 1558c9d1bd47ad090d80241e98e945866945ab95 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 7 Aug 2015 11:24:52 -0700 Subject: [PATCH 25/84] [JSDoc] Add script to add annotations WTD-1482 --- jsdocify.js | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 jsdocify.js diff --git a/jsdocify.js b/jsdocify.js new file mode 100644 index 0000000000..c432d4cd47 --- /dev/null +++ b/jsdocify.js @@ -0,0 +1,85 @@ +(function () { + "use strict"; + + var glob = require("glob"), + split = require("split"), + fs = require("fs"), + stream = require("stream"); + + function bundleName(file) { + return file.substr(0, file.indexOf('/src')); + } + + function className(file) { + return file.substr(file.lastIndexOf('/') + 1).replace(/\.js$/, ""); + } + + function qualifiedName(file) { + return bundleName(file) + '.' + className(file); + } + + function spaces(count) { + return count < 1 ? '' : (spaces(count - 1) + " "); + } + + function jsdocRewriter(filename) { + var rewriter = new stream.Transform(), + reachedConstructor = false, + inMember = false, + starDepth = 0; + + rewriter._transform = function (chunk, encoding, done) { + var data = String(chunk); + if (!reachedConstructor) { + if (data.match(/^ *\* @constructor/)) { + // Track position to detect inner methods + starDepth = data.indexOf("*"); + reachedConstructor = true; + // Add a @memberof annotation + this.push([ + spaces(starDepth), + "* @memberof ", + bundleName(filename), + "\n" + ].join("")); + } + } else if (!inMember) { + // Start of JSdoc for a member + if (data.match(/^ *\/\*\*/) && data.indexOf('/') > starDepth) { + inMember = true; + } + } else { + // End of JSdoc for a member + if (data.match(/^ *\*\//)) { + this.push([ + spaces(data.indexOf('*')), + "* @memberof ", + qualifiedName(filename), + "#\n" + ].join("")); + inMember = false; + } + } + this.push(data + '\n'); + done(); + }; + + return rewriter; + } + + + glob("platform/**/src/**/*.js", function (err, files) { + files.forEach(function (file) { + var tmp = file + '.tmp'; + fs.createReadStream(file, { encoding: 'utf8' }) + .pipe(split()) + .pipe(jsdocRewriter(file)) + .pipe(fs.createWriteStream(tmp, { encoding: 'utf8' })) + .on('close', function () { + fs.renameSync(tmp, file); + }); + }); + }); + + +}()); \ No newline at end of file From 2f793232640adc1c4f9b235859004bdefbf2d11f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 7 Aug 2015 11:41:02 -0700 Subject: [PATCH 26/84] [JSDoc] Handle missing @constructor WTD-1482 --- jsdocify.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/jsdocify.js b/jsdocify.js index c432d4cd47..881e27e9c6 100644 --- a/jsdocify.js +++ b/jsdocify.js @@ -31,7 +31,20 @@ rewriter._transform = function (chunk, encoding, done) { var data = String(chunk); if (!reachedConstructor) { - if (data.match(/^ *\* @constructor/)) { + // First, check for constructors missing @constructor + if (data.match(/^ *\*\//) && data.indexOf("*") > 3) { + // Track position to detect inner methods + starDepth = data.indexOf("*"); + reachedConstructor = true; + // Add a @memberof annotation + this.push(spaces(starDepth) + "* @constructor\n"); + this.push([ + spaces(starDepth), + "* @memberof ", + bundleName(filename), + "\n" + ].join("")); + } else if (data.match(/^ *\* @constructor/)) { // Track position to detect inner methods starDepth = data.indexOf("*"); reachedConstructor = true; From 14f97eae9c141e7f134ce0870b39a20eed9dc37b Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 7 Aug 2015 11:43:47 -0700 Subject: [PATCH 27/84] [JSDoc] Exclude examples WTD-1482 --- jsdoc.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jsdoc.json b/jsdoc.json index ed0fddcf31..4164aa3577 100644 --- a/jsdoc.json +++ b/jsdoc.json @@ -1,10 +1,9 @@ { "source": { "include": [ - "example/", "platform/" ], - "includePattern": "(example|platform)/.+\\.js$", + "includePattern": "platform/.+\\.js$", "excludePattern": ".+\\Spec\\.js$|lib/.+" } } \ No newline at end of file From c08a460d308439a4d6b8c8667ed2f5b8d3d0805c Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 7 Aug 2015 11:44:54 -0700 Subject: [PATCH 28/84] [JSDoc] Add annotations Bulk-add JSDoc annotations, WTD-1482. --- platform/commonUI/about/src/AboutController.js | 5 ++++- platform/commonUI/about/src/LicenseController.js | 4 +++- platform/commonUI/about/src/LogoController.js | 4 +++- platform/commonUI/browse/src/BrowseController.js | 2 ++ .../commonUI/browse/src/BrowseObjectController.js | 2 ++ .../commonUI/browse/src/MenuArrowController.js | 3 ++- .../commonUI/browse/src/creation/CreateAction.js | 5 ++++- .../browse/src/creation/CreateActionProvider.js | 4 +++- .../browse/src/creation/CreateMenuController.js | 3 ++- .../commonUI/browse/src/creation/CreateWizard.js | 7 ++++++- .../browse/src/creation/CreationService.js | 3 +++ .../browse/src/creation/LocatorController.js | 2 ++ .../browse/src/navigation/NavigateAction.js | 4 +++- .../browse/src/navigation/NavigationService.js | 7 ++++++- .../browse/src/windowing/FullscreenAction.js | 5 ++++- .../commonUI/browse/src/windowing/NewTabAction.js | 3 ++- .../commonUI/browse/src/windowing/WindowTitler.js | 3 ++- platform/commonUI/dialog/src/DialogService.js | 5 ++++- platform/commonUI/dialog/src/OverlayService.js | 4 +++- platform/commonUI/edit/src/actions/CancelAction.js | 5 ++++- platform/commonUI/edit/src/actions/EditAction.js | 4 +++- platform/commonUI/edit/src/actions/LinkAction.js | 5 ++++- .../commonUI/edit/src/actions/PropertiesAction.js | 3 +++ .../commonUI/edit/src/actions/PropertiesDialog.js | 6 +++++- platform/commonUI/edit/src/actions/RemoveAction.js | 8 +++++++- platform/commonUI/edit/src/actions/SaveAction.js | 5 ++++- .../capabilities/EditableCompositionCapability.js | 4 +++- .../src/capabilities/EditableContextCapability.js | 4 +++- .../src/capabilities/EditableLookupCapability.js | 4 +++- .../capabilities/EditablePersistenceCapability.js | 4 +++- .../capabilities/EditableRelationshipCapability.js | 4 +++- .../edit/src/capabilities/EditorCapability.js | 7 ++++++- .../edit/src/controllers/EditActionController.js | 3 ++- .../edit/src/controllers/EditController.js | 5 ++++- .../edit/src/controllers/EditPanesController.js | 4 +++- .../edit/src/directives/MCTBeforeUnload.js | 3 ++- .../edit/src/objects/EditableDomainObject.js | 4 +++- .../edit/src/objects/EditableDomainObjectCache.js | 8 ++++++++ .../edit/src/objects/EditableModelCache.js | 4 +++- .../commonUI/edit/src/policies/EditActionPolicy.js | 4 +++- .../edit/src/policies/EditableViewPolicy.js | 4 +++- .../edit/src/representers/EditRepresenter.js | 5 ++++- .../commonUI/edit/src/representers/EditToolbar.js | 6 ++++++ .../src/representers/EditToolbarRepresenter.js | 5 ++++- .../edit/src/representers/EditToolbarSelection.js | 9 ++++++++- platform/commonUI/general/src/StyleSheetLoader.js | 3 ++- .../src/controllers/ActionGroupController.js | 3 ++- .../general/src/controllers/BottomBarController.js | 4 +++- .../general/src/controllers/ClickAwayController.js | 6 +++++- .../src/controllers/ContextMenuController.js | 3 ++- .../src/controllers/GetterSetterController.js | 3 ++- .../general/src/controllers/SelectorController.js | 7 ++++++- .../general/src/controllers/SplitPaneController.js | 6 +++++- .../general/src/controllers/ToggleController.js | 6 +++++- .../general/src/controllers/TreeNodeController.js | 6 +++++- .../src/controllers/ViewSwitcherController.js | 2 ++ .../general/src/directives/MCTContainer.js | 3 ++- .../commonUI/general/src/directives/MCTDrag.js | 2 ++ .../commonUI/general/src/directives/MCTResize.js | 3 ++- .../commonUI/general/src/directives/MCTScroll.js | 3 ++- .../general/src/directives/MCTSplitPane.js | 2 ++ .../commonUI/general/src/directives/MCTSplitter.js | 2 ++ .../commonUI/general/src/services/UrlService.js | 6 +++++- platform/commonUI/inspect/src/InfoConstants.js | 2 +- .../commonUI/inspect/src/gestures/InfoGesture.js | 3 +++ .../commonUI/inspect/src/services/InfoService.js | 3 +++ platform/containment/src/CapabilityTable.js | 5 ++++- platform/containment/src/ComposeActionPolicy.js | 5 ++++- platform/containment/src/CompositionModelPolicy.js | 5 ++++- .../containment/src/CompositionMutabilityPolicy.js | 4 +++- platform/containment/src/CompositionPolicy.js | 5 ++++- platform/containment/src/ContainmentTable.js | 5 ++++- platform/core/src/actions/ActionAggregator.js | 4 +++- platform/core/src/actions/ActionCapability.js | 5 ++++- platform/core/src/actions/ActionProvider.js | 4 +++- .../core/src/actions/LoggingActionDecorator.js | 4 +++- .../core/src/capabilities/CompositionCapability.js | 4 +++- .../core/src/capabilities/ContextCapability.js | 6 +++++- .../src/capabilities/ContextualDomainObject.js | 3 ++- .../src/capabilities/CoreCapabilityProvider.js | 3 +++ .../core/src/capabilities/DelegationCapability.js | 5 ++++- .../core/src/capabilities/MetadataCapability.js | 4 ++++ .../core/src/capabilities/MutationCapability.js | 5 +++++ .../core/src/capabilities/PersistenceCapability.js | 6 +++++- .../src/capabilities/RelationshipCapability.js | 5 ++++- platform/core/src/models/CachingModelDecorator.js | 4 +++- platform/core/src/models/MissingModelDecorator.js | 3 +++ platform/core/src/models/ModelAggregator.js | 4 +++- platform/core/src/models/PersistedModelProvider.js | 4 +++- platform/core/src/models/RootModelProvider.js | 4 +++- platform/core/src/models/StaticModelProvider.js | 4 +++- platform/core/src/objects/DomainObject.js | 8 +++++++- platform/core/src/objects/DomainObjectProvider.js | 4 +++- platform/core/src/services/Now.js | 5 ++++- platform/core/src/services/Throttle.js | 4 ++++ platform/core/src/services/Topic.js | 4 ++++ platform/core/src/types/MergeModels.js | 4 +++- platform/core/src/types/TypeCapability.js | 3 ++- platform/core/src/types/TypeImpl.js | 13 ++++++++++++- platform/core/src/types/TypeProperty.js | 6 +++++- platform/core/src/types/TypePropertyConversion.js | 4 +++- platform/core/src/types/TypeProvider.js | 5 ++++- platform/core/src/views/ViewCapability.js | 4 +++- platform/core/src/views/ViewProvider.js | 4 +++- platform/entanglement/src/actions/CopyAction.js | 3 +++ platform/entanglement/src/actions/LinkAction.js | 3 +++ platform/entanglement/src/actions/MoveAction.js | 3 +++ platform/entanglement/src/services/CopyService.js | 6 ++++++ platform/entanglement/src/services/LinkService.js | 5 +++++ .../entanglement/src/services/LocationService.js | 4 ++++ platform/entanglement/src/services/MoveService.js | 5 +++++ platform/execution/src/WorkerService.js | 3 +++ platform/features/events/src/DomainColumn.js | 5 ++++- .../features/events/src/EventListController.js | 2 ++ platform/features/events/src/EventListPopulator.js | 2 +- platform/features/events/src/RangeColumn.js | 5 ++++- .../features/events/src/directives/MCTDataTable.js | 2 +- .../events/src/policies/MessagesViewPolicy.js | 4 +++- .../imagery/src/controllers/ImageryController.js | 8 ++++++++ .../imagery/src/directives/MCTBackgroundImage.js | 3 +++ .../imagery/src/policies/ImageryViewPolicy.js | 3 +++ platform/features/layout/src/FixedController.js | 9 +++++++++ platform/features/layout/src/FixedDragHandle.js | 7 ++++++- platform/features/layout/src/FixedProxy.js | 4 +++- .../features/layout/src/LayoutCompositionPolicy.js | 4 ++++ platform/features/layout/src/LayoutController.js | 6 ++++++ platform/features/layout/src/LayoutDrag.js | 5 ++++- .../layout/src/elements/AccessorMutator.js | 3 ++- platform/features/layout/src/elements/BoxProxy.js | 4 +++- .../features/layout/src/elements/ElementFactory.js | 4 +++- .../features/layout/src/elements/ElementProxies.js | 2 +- .../features/layout/src/elements/ElementProxy.js | 12 +++++++++++- .../features/layout/src/elements/ImageProxy.js | 4 +++- .../features/layout/src/elements/LineHandle.js | 5 ++++- platform/features/layout/src/elements/LineProxy.js | 12 +++++++++++- .../features/layout/src/elements/ResizeHandle.js | 5 ++++- .../features/layout/src/elements/TelemetryProxy.js | 3 ++- platform/features/layout/src/elements/TextProxy.js | 5 ++++- .../features/pages/src/EmbeddedPageController.js | 5 ++++- platform/features/plot/src/Canvas2DChart.js | 7 ++++++- platform/features/plot/src/GLChart.js | 7 ++++++- platform/features/plot/src/MCTChart.js | 2 ++ platform/features/plot/src/PlotController.js | 13 +++++++++++++ platform/features/plot/src/SubPlot.js | 14 ++++++++++++++ platform/features/plot/src/SubPlotFactory.js | 4 +++- platform/features/plot/src/elements/PlotAxis.js | 5 ++++- .../features/plot/src/elements/PlotLimitTracker.js | 3 ++- platform/features/plot/src/elements/PlotLine.js | 4 +++- .../features/plot/src/elements/PlotLineBuffer.js | 10 ++++++++++ platform/features/plot/src/elements/PlotPalette.js | 3 ++- .../features/plot/src/elements/PlotPanZoomStack.js | 11 ++++++++++- .../plot/src/elements/PlotPanZoomStackGroup.js | 8 +++++++- .../features/plot/src/elements/PlotPosition.js | 6 +++++- .../features/plot/src/elements/PlotPreparer.js | 7 ++++++- .../features/plot/src/elements/PlotSeriesWindow.js | 4 +++- .../plot/src/elements/PlotTickGenerator.js | 5 ++++- platform/features/plot/src/elements/PlotUpdater.js | 8 ++++++++ .../features/plot/src/modes/PlotModeOptions.js | 7 ++++++- .../features/plot/src/modes/PlotOverlayMode.js | 7 ++++++- platform/features/plot/src/modes/PlotStackMode.js | 8 +++++++- .../features/plot/src/policies/PlotViewPolicy.js | 3 +++ platform/features/rtevents/src/DomainColumn.js | 4 ++++ .../features/rtevents/src/RTEventListController.js | 2 ++ platform/features/rtevents/src/RangeColumn.js | 4 ++++ .../rtevents/src/directives/MCTRTDataTable.js | 2 +- .../rtevents/src/policies/RTMessagesViewPolicy.js | 4 +++- platform/features/rtscrolling/src/DomainColumn.js | 4 ++++ platform/features/rtscrolling/src/NameColumn.js | 4 ++++ .../rtscrolling/src/RTScrollingListController.js | 2 ++ platform/features/rtscrolling/src/RangeColumn.js | 4 ++++ platform/features/scrolling/src/DomainColumn.js | 5 ++++- platform/features/scrolling/src/NameColumn.js | 5 ++++- platform/features/scrolling/src/RangeColumn.js | 5 ++++- .../scrolling/src/ScrollingListController.js | 2 ++ .../scrolling/src/ScrollingListPopulator.js | 5 +++++ platform/forms/src/MCTControl.js | 4 +++- platform/forms/src/MCTForm.js | 3 ++- platform/forms/src/MCTToolbar.js | 3 ++- platform/forms/src/controllers/ColorController.js | 2 +- .../forms/src/controllers/CompositeController.js | 4 +++- .../forms/src/controllers/DateTimeController.js | 2 ++ .../src/controllers/DialogButtonController.js | 4 +++- platform/forms/src/controllers/FormController.js | 3 ++- platform/framework/src/Constants.js | 2 +- platform/framework/src/FrameworkInitializer.js | 3 ++- platform/framework/src/LogLevel.js | 4 +++- platform/framework/src/Main.js | 2 +- .../src/bootstrap/ApplicationBootstrapper.js | 4 +++- platform/framework/src/load/Bundle.js | 13 ++++++++++++- platform/framework/src/load/BundleLoader.js | 4 +++- platform/framework/src/load/Extension.js | 11 ++++++++++- .../framework/src/register/CustomRegistrars.js | 3 ++- .../framework/src/register/ExtensionRegistrar.js | 4 +++- platform/framework/src/register/ExtensionSorter.js | 4 +++- .../framework/src/register/PartialConstructor.js | 3 ++- .../framework/src/register/ServiceCompositor.js | 4 +++- platform/framework/src/resolve/BundleResolver.js | 5 ++++- .../framework/src/resolve/ExtensionResolver.js | 4 +++- .../framework/src/resolve/ImplementationLoader.js | 4 +++- .../framework/src/resolve/RequireConfigurator.js | 4 +++- .../cache/src/CachingPersistenceDecorator.js | 9 ++++++++- platform/persistence/couch/src/CouchDocument.js | 3 ++- platform/persistence/couch/src/CouchIndicator.js | 8 +++++++- .../couch/src/CouchPersistenceProvider.js | 9 ++++++++- .../persistence/elastic/src/ElasticIndicator.js | 8 +++++++- .../elastic/src/ElasticPersistenceProvider.js | 9 ++++++++- .../queue/src/PersistenceFailureConstants.js | 2 +- .../queue/src/PersistenceFailureController.js | 6 +++++- .../queue/src/PersistenceFailureDialog.js | 4 +++- .../queue/src/PersistenceFailureHandler.js | 4 +++- platform/persistence/queue/src/PersistenceQueue.js | 4 +++- .../queue/src/PersistenceQueueHandler.js | 5 ++++- .../persistence/queue/src/PersistenceQueueImpl.js | 5 ++++- .../queue/src/QueuingPersistenceCapability.js | 4 +++- .../src/QueuingPersistenceCapabilityDecorator.js | 4 +++- platform/policy/src/PolicyActionDecorator.js | 5 ++++- platform/policy/src/PolicyProvider.js | 4 +++- platform/policy/src/PolicyViewDecorator.js | 5 ++++- platform/representation/src/MCTInclude.js | 2 ++ platform/representation/src/MCTRepresentation.js | 2 ++ .../src/actions/ContextMenuAction.js | 3 ++- .../src/gestures/ContextMenuGesture.js | 4 +++- .../representation/src/gestures/DragGesture.js | 4 +++- .../representation/src/gestures/DropGesture.js | 4 +++- .../src/gestures/GestureConstants.js | 4 +++- .../representation/src/gestures/GestureProvider.js | 4 +++- .../src/gestures/GestureRepresenter.js | 6 +++++- platform/representation/src/services/DndService.js | 6 +++++- platform/telemetry/src/TelemetryAggregator.js | 5 ++++- platform/telemetry/src/TelemetryCapability.js | 5 +++++ platform/telemetry/src/TelemetryController.js | 9 ++++++++- platform/telemetry/src/TelemetryDelegator.js | 5 ++++- platform/telemetry/src/TelemetryFormatter.js | 5 ++++- platform/telemetry/src/TelemetryHandle.js | 6 +++++- platform/telemetry/src/TelemetryHandler.js | 3 ++- platform/telemetry/src/TelemetryQueue.js | 6 +++++- platform/telemetry/src/TelemetrySubscriber.js | 4 +++- platform/telemetry/src/TelemetrySubscription.js | 9 +++++++++ platform/telemetry/src/TelemetryTable.js | 6 +++++- 239 files changed, 939 insertions(+), 185 deletions(-) diff --git a/platform/commonUI/about/src/AboutController.js b/platform/commonUI/about/src/AboutController.js index 7fc61c8cc2..b2fce0bdfd 100644 --- a/platform/commonUI/about/src/AboutController.js +++ b/platform/commonUI/about/src/AboutController.js @@ -29,6 +29,7 @@ define( /** * The AboutController provides information to populate the * About dialog. + * @memberof platform/commonUI/about * @constructor * @param {object[]} versions an array of version extensions; * injected from `versions[]` @@ -42,6 +43,7 @@ define( * as a line-item in the version information listing. * @memberof AboutController# * @returns {object[]} version information + * @memberof platform/commonUI/about.AboutController# */ versions: function () { return versions; @@ -50,6 +52,7 @@ define( * Open a new window (or tab, depending on browser * configuration) containing open source licenses. * @memberof AboutController# + * @memberof platform/commonUI/about.AboutController# */ openLicenses: function () { // Open a new browser window at the licenses route @@ -60,4 +63,4 @@ define( return AboutController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/about/src/LicenseController.js b/platform/commonUI/about/src/LicenseController.js index 1d996596aa..a2e7463b37 100644 --- a/platform/commonUI/about/src/LicenseController.js +++ b/platform/commonUI/about/src/LicenseController.js @@ -29,6 +29,7 @@ define( /** * Provides extension-introduced licenses information to the * licenses route. + * @memberof platform/commonUI/about * @constructor */ function LicenseController(licenses) { @@ -36,6 +37,7 @@ define( /** * Get license information. * @returns {Array} license extensions + * @memberof platform/commonUI/about.LicenseController# */ licenses: function () { return licenses; @@ -45,4 +47,4 @@ define( return LicenseController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/about/src/LogoController.js b/platform/commonUI/about/src/LogoController.js index a688e96acf..f151900df5 100644 --- a/platform/commonUI/about/src/LogoController.js +++ b/platform/commonUI/about/src/LogoController.js @@ -29,6 +29,7 @@ define( /** * The LogoController provides functionality to the application * logo in the bottom-right of the user interface. + * @memberof platform/commonUI/about * @constructor * @param {OverlayService} overlayService the overlay service */ @@ -37,6 +38,7 @@ define( /** * Display the About dialog. * @memberof LogoController# + * @memberof platform/commonUI/about.LogoController# */ showAboutDialog: function () { overlayService.createOverlay("overlay-about"); @@ -46,4 +48,4 @@ define( return LogoController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/browse/src/BrowseController.js b/platform/commonUI/browse/src/BrowseController.js index 3ec38057fc..7d65db507d 100644 --- a/platform/commonUI/browse/src/BrowseController.js +++ b/platform/commonUI/browse/src/BrowseController.js @@ -39,6 +39,7 @@ define( * which Angular templates first have access to the domain object * hierarchy. * + * @memberof platform/commonUI/browse * @constructor */ function BrowseController($scope, $route, $location, objectService, navigationService, urlService) { @@ -157,3 +158,4 @@ define( return BrowseController; } ); + diff --git a/platform/commonUI/browse/src/BrowseObjectController.js b/platform/commonUI/browse/src/BrowseObjectController.js index 1826120458..b1af9f29a7 100644 --- a/platform/commonUI/browse/src/BrowseObjectController.js +++ b/platform/commonUI/browse/src/BrowseObjectController.js @@ -29,6 +29,7 @@ define( /** * Controller for the `browse-object` representation of a domain * object (the right-hand side of Browse mode.) + * @memberof platform/commonUI/browse * @constructor */ function BrowseObjectController($scope, $location, $route) { @@ -71,3 +72,4 @@ define( return BrowseObjectController; } ); + diff --git a/platform/commonUI/browse/src/MenuArrowController.js b/platform/commonUI/browse/src/MenuArrowController.js index 86cad25c0e..f3894df03c 100644 --- a/platform/commonUI/browse/src/MenuArrowController.js +++ b/platform/commonUI/browse/src/MenuArrowController.js @@ -33,6 +33,7 @@ define( * A left-click on the menu arrow should display a * context menu. This controller launches the context * menu. + * @memberof platform/commonUI/browse * @constructor */ function MenuArrowController($scope) { @@ -48,4 +49,4 @@ define( return MenuArrowController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/browse/src/creation/CreateAction.js b/platform/commonUI/browse/src/creation/CreateAction.js index ce0d6d5cd4..e30ff06d05 100644 --- a/platform/commonUI/browse/src/creation/CreateAction.js +++ b/platform/commonUI/browse/src/creation/CreateAction.js @@ -34,6 +34,7 @@ define( * domain objects of a specific type. This is the action that * is performed when a user uses the Create menu. * + * @memberof platform/commonUI/browse * @constructor * @param {Type} type the type of domain object to create * @param {DomainObject} parent the domain object that should @@ -95,6 +96,7 @@ define( * This will prompt for user input first. * @method * @memberof CreateAction + * @memberof platform/commonUI/browse.CreateAction# */ perform: perform, @@ -107,6 +109,7 @@ define( * * `context`: The context in which this action will be performed. * * @return {object} metadata about the create action + * @memberof platform/commonUI/browse.CreateAction# */ getMetadata: function () { return { @@ -123,4 +126,4 @@ define( return CreateAction; } -); \ No newline at end of file +); diff --git a/platform/commonUI/browse/src/creation/CreateActionProvider.js b/platform/commonUI/browse/src/creation/CreateActionProvider.js index dcc98b8e95..1078089d3f 100644 --- a/platform/commonUI/browse/src/creation/CreateActionProvider.js +++ b/platform/commonUI/browse/src/creation/CreateActionProvider.js @@ -33,6 +33,7 @@ define( * The CreateActionProvider is an ActionProvider which introduces * a Create action for each creatable domain object type. * + * @memberof platform/commonUI/browse * @constructor * @param {TypeService} typeService the type service, used to discover * available types @@ -51,6 +52,7 @@ define( * @memberof CreateActionProvider * @method * @returns {CreateAction[]} + * @memberof platform/commonUI/browse.CreateActionProvider# */ getActions: function (actionContext) { var context = actionContext || {}, @@ -84,4 +86,4 @@ define( return CreateActionProvider; } -); \ No newline at end of file +); diff --git a/platform/commonUI/browse/src/creation/CreateMenuController.js b/platform/commonUI/browse/src/creation/CreateMenuController.js index 2dace415df..624764c2e4 100644 --- a/platform/commonUI/browse/src/creation/CreateMenuController.js +++ b/platform/commonUI/browse/src/creation/CreateMenuController.js @@ -34,6 +34,7 @@ define( * set of Create actions based on the currently-selected * domain object. * + * @memberof platform/commonUI/browse * @constructor */ function CreateMenuController($scope) { @@ -55,4 +56,4 @@ define( return CreateMenuController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/browse/src/creation/CreateWizard.js b/platform/commonUI/browse/src/creation/CreateWizard.js index 29fe953e18..a0e21b102d 100644 --- a/platform/commonUI/browse/src/creation/CreateWizard.js +++ b/platform/commonUI/browse/src/creation/CreateWizard.js @@ -37,6 +37,7 @@ define( * @param {TypeImpl} type the type of domain object to be created * @param {DomainObject} parent the domain object to serve as * the initial parent for the created object, in the dialog + * @memberof platform/commonUI/browse * @constructor * @memberof module:core/action/create-wizard */ @@ -62,6 +63,7 @@ define( * * @return {FormModel} formModel the form model to * show in the create dialog + * @memberof platform/commonUI/browse.CreateWizard# */ getFormStructure: function () { var sections = []; @@ -100,6 +102,7 @@ define( * in the structure. * * @returns {object} the initial value of the form + * @memberof platform/commonUI/browse.CreateWizard# */ getInitialFormValue: function () { // Start with initial values for properties @@ -116,6 +119,7 @@ define( * Based on a populated form, get the domain object which * should be used as a parent for the newly-created object. * @return {DomainObject} + * @memberof platform/commonUI/browse.CreateWizard# */ getLocation: function (formValue) { return formValue.createParent || parent; @@ -124,6 +128,7 @@ define( * Create the domain object model for a newly-created object, * based on user input read from a formModel. * @return {object} the domain object' model + * @memberof platform/commonUI/browse.CreateWizard# */ createModel: function (formValue) { // Clone @@ -146,4 +151,4 @@ define( return CreateWizard; } -); \ No newline at end of file +); diff --git a/platform/commonUI/browse/src/creation/CreationService.js b/platform/commonUI/browse/src/creation/CreationService.js index 015573c8bd..a4dffdd8e4 100644 --- a/platform/commonUI/browse/src/creation/CreationService.js +++ b/platform/commonUI/browse/src/creation/CreationService.js @@ -39,6 +39,7 @@ define( * persisting new domain objects. Handles all actual object * mutation and persistence associated with domain object * creation. + * @memberof platform/commonUI/browse * @constructor */ function CreationService(persistenceService, $q, $log) { @@ -131,6 +132,7 @@ define( * @param {DomainObject} parent the domain object which * should contain the newly-created domain object * in its composition + * @memberof platform/commonUI/browse.CreationService# */ createObject: createObject }; @@ -139,3 +141,4 @@ define( return CreationService; } ); + diff --git a/platform/commonUI/browse/src/creation/LocatorController.js b/platform/commonUI/browse/src/creation/LocatorController.js index c7104956ea..d6335f9bd1 100644 --- a/platform/commonUI/browse/src/creation/LocatorController.js +++ b/platform/commonUI/browse/src/creation/LocatorController.js @@ -30,6 +30,7 @@ define( * Controller for the "locator" control, which provides the * user with the ability to select a domain object as the * destination for a newly-created object in the Create menu. + * @memberof platform/commonUI/browse * @constructor */ function LocatorController($scope) { @@ -79,3 +80,4 @@ define( return LocatorController; } ); + diff --git a/platform/commonUI/browse/src/navigation/NavigateAction.js b/platform/commonUI/browse/src/navigation/NavigateAction.js index 779a83044a..04ada63690 100644 --- a/platform/commonUI/browse/src/navigation/NavigateAction.js +++ b/platform/commonUI/browse/src/navigation/NavigateAction.js @@ -31,6 +31,7 @@ define( /** * The navigate action navigates to a specific domain object. + * @memberof platform/commonUI/browse * @constructor */ function NavigateAction(navigationService, $q, context) { @@ -46,6 +47,7 @@ define( * Navigate to the object described in the context. * @returns {Promise} a promise that is resolved once the * navigation has been updated + * @memberof platform/commonUI/browse.NavigateAction# */ perform: perform }; @@ -64,4 +66,4 @@ define( return NavigateAction; } -); \ No newline at end of file +); diff --git a/platform/commonUI/browse/src/navigation/NavigationService.js b/platform/commonUI/browse/src/navigation/NavigationService.js index c8c76857b8..cd2ab1b206 100644 --- a/platform/commonUI/browse/src/navigation/NavigationService.js +++ b/platform/commonUI/browse/src/navigation/NavigationService.js @@ -32,6 +32,7 @@ define( /** * The navigation service maintains the application's current * navigation state, and allows listening for changes thereto. + * @memberof platform/commonUI/browse * @constructor */ function NavigationService() { @@ -68,12 +69,14 @@ define( return { /** * Get the current navigation state. + * @memberof platform/commonUI/browse.NavigationService# */ getNavigation: getNavigation, /** * Set the current navigation state. Thiswill invoke listeners. * @param {DomainObject} value the domain object to navigate * to + * @memberof platform/commonUI/browse.NavigationService# */ setNavigation: setNavigation, /** @@ -82,6 +85,7 @@ define( * this changes. * @param {function} callback the callback to invoke when * navigation state changes + * @memberof platform/commonUI/browse.NavigationService# */ addListener: addListener, /** @@ -89,6 +93,7 @@ define( * @param {function} callback the callback which should * no longer be invoked when navigation state * changes + * @memberof platform/commonUI/browse.NavigationService# */ removeListener: removeListener }; @@ -96,4 +101,4 @@ define( return NavigationService; } -); \ No newline at end of file +); diff --git a/platform/commonUI/browse/src/windowing/FullscreenAction.js b/platform/commonUI/browse/src/windowing/FullscreenAction.js index efba99520b..cea492f892 100644 --- a/platform/commonUI/browse/src/windowing/FullscreenAction.js +++ b/platform/commonUI/browse/src/windowing/FullscreenAction.js @@ -35,12 +35,14 @@ define( /** * The fullscreen action toggles between fullscreen display * and regular in-window display. + * @memberof platform/commonUI/browse * @constructor */ function FullscreenAction(context) { return { /** * Toggle full screen state + * @memberof platform/commonUI/browse.FullscreenAction# */ perform: function () { screenfull.toggle(); @@ -48,6 +50,7 @@ define( /** * Get metadata about this action, including the * applicable glyph to display. + * @memberof platform/commonUI/browse.FullscreenAction# */ getMetadata: function () { // We override getMetadata, because the glyph and @@ -67,4 +70,4 @@ define( return FullscreenAction; } -); \ No newline at end of file +); diff --git a/platform/commonUI/browse/src/windowing/NewTabAction.js b/platform/commonUI/browse/src/windowing/NewTabAction.js index 8616a89711..8d38f994e2 100644 --- a/platform/commonUI/browse/src/windowing/NewTabAction.js +++ b/platform/commonUI/browse/src/windowing/NewTabAction.js @@ -33,6 +33,7 @@ define( /** * The new tab action allows a domain object to be opened * into a new browser tab. + * @memberof platform/commonUI/browse * @constructor */ function NewTabAction(urlService, $window, context) { @@ -64,4 +65,4 @@ define( return NewTabAction; } -); \ No newline at end of file +); diff --git a/platform/commonUI/browse/src/windowing/WindowTitler.js b/platform/commonUI/browse/src/windowing/WindowTitler.js index 9db65e5b0e..4ce448cb1e 100644 --- a/platform/commonUI/browse/src/windowing/WindowTitler.js +++ b/platform/commonUI/browse/src/windowing/WindowTitler.js @@ -29,6 +29,7 @@ define( /** * Updates the title of the current window to reflect the name * of the currently navigated-to domain object. + * @memberof platform/commonUI/browse * @constructor */ function WindowTitler(navigationService, $rootScope, $document) { @@ -49,4 +50,4 @@ define( return WindowTitler; } -); \ No newline at end of file +); diff --git a/platform/commonUI/dialog/src/DialogService.js b/platform/commonUI/dialog/src/DialogService.js index d0c2c83f42..a435d287e5 100644 --- a/platform/commonUI/dialog/src/DialogService.js +++ b/platform/commonUI/dialog/src/DialogService.js @@ -32,6 +32,7 @@ define( * The dialog service is responsible for handling window-modal * communication with the user, such as displaying forms for user * input. + * @memberof platform/commonUI/dialog * @constructor */ function DialogService(overlayService, $q, $log) { @@ -142,6 +143,7 @@ define( * user has supplied; this may be rejected if * user input cannot be obtained (for instance, * because the user cancelled the dialog) + * @memberof platform/commonUI/dialog.DialogService# */ getUserInput: getUserInput, /** @@ -149,6 +151,7 @@ define( * which will be shown as buttons. * * @param dialogModel a description of the dialog to show + * @memberof platform/commonUI/dialog.DialogService# */ getUserChoice: getUserChoice }; @@ -156,4 +159,4 @@ define( return DialogService; } -); \ No newline at end of file +); diff --git a/platform/commonUI/dialog/src/OverlayService.js b/platform/commonUI/dialog/src/OverlayService.js index b66bffa7dc..4611a96148 100644 --- a/platform/commonUI/dialog/src/OverlayService.js +++ b/platform/commonUI/dialog/src/OverlayService.js @@ -43,6 +43,7 @@ define( * particularly where a multiple-overlay effect is not specifically * desired). * + * @memberof platform/commonUI/dialog * @constructor */ function OverlayService($document, $compile, $rootScope) { @@ -89,6 +90,7 @@ define( * @param {object} overlayModel the model to pass to the * included overlay template (this will be passed * in via ng-model) + * @memberof platform/commonUI/dialog.OverlayService# */ createOverlay: createOverlay }; @@ -96,4 +98,4 @@ define( return OverlayService; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/actions/CancelAction.js b/platform/commonUI/edit/src/actions/CancelAction.js index 725f6ee6a7..7b2f28538d 100644 --- a/platform/commonUI/edit/src/actions/CancelAction.js +++ b/platform/commonUI/edit/src/actions/CancelAction.js @@ -29,6 +29,8 @@ define( * The "Cancel" action; the action triggered by clicking Cancel from * Edit Mode. Exits the editing user interface and invokes object * capabilities to persist the changes that have been made. + * @constructor + * @memberof platform/commonUI/edit */ function CancelAction($location, urlService, context) { var domainObject = context.domainObject; @@ -62,6 +64,7 @@ define( * * @returns {Promise} a promise that will be fulfilled when * cancellation has completed + * @memberof platform/commonUI/edit.CancelAction# */ perform: function () { return doCancel(getEditorCapability()) @@ -84,4 +87,4 @@ define( return CancelAction; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/actions/EditAction.js b/platform/commonUI/edit/src/actions/EditAction.js index 38260469ae..2559d0488d 100644 --- a/platform/commonUI/edit/src/actions/EditAction.js +++ b/platform/commonUI/edit/src/actions/EditAction.js @@ -42,6 +42,7 @@ define( * mode (typically triggered by the Edit button.) This will * show the user interface for editing (by way of a change in * route) + * @memberof platform/commonUI/edit * @constructor */ function EditAction($location, navigationService, $log, context) { @@ -63,6 +64,7 @@ define( return { /** * Enter edit mode. + * @memberof platform/commonUI/edit.EditAction# */ perform: function () { navigationService.setNavigation(domainObject); @@ -87,4 +89,4 @@ define( return EditAction; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/actions/LinkAction.js b/platform/commonUI/edit/src/actions/LinkAction.js index f7d0087646..b0c2e35e31 100644 --- a/platform/commonUI/edit/src/actions/LinkAction.js +++ b/platform/commonUI/edit/src/actions/LinkAction.js @@ -29,6 +29,8 @@ define( /** * Add one domain object to another's composition. + * @constructor + * @memberof platform/commonUI/edit */ function LinkAction(context) { var domainObject = (context || {}).domainObject, @@ -58,6 +60,7 @@ define( return { /** * Perform this action. + * @memberof platform/commonUI/edit.LinkAction# */ perform: function () { return selectedId && doLink(); @@ -67,4 +70,4 @@ define( return LinkAction; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/actions/PropertiesAction.js b/platform/commonUI/edit/src/actions/PropertiesAction.js index bb37727c0e..0cab34a879 100644 --- a/platform/commonUI/edit/src/actions/PropertiesAction.js +++ b/platform/commonUI/edit/src/actions/PropertiesAction.js @@ -38,6 +38,7 @@ define( * @param {DialogService} dialogService a service which will show the dialog * @param {DomainObject} object the object to be edited * @param {ActionContext} context the context in which this action is performed + * @memberof platform/commonUI/edit * @constructor */ function PropertiesAction(dialogService, context) { @@ -77,6 +78,7 @@ define( * Perform this action. * @return {Promise} a promise which will be * fulfilled when the action has completed. + * @memberof platform/commonUI/edit.PropertiesAction# */ perform: function () { var type = object.getCapability('type'); @@ -106,3 +108,4 @@ define( ); + diff --git a/platform/commonUI/edit/src/actions/PropertiesDialog.js b/platform/commonUI/edit/src/actions/PropertiesDialog.js index 8319efc315..9d7c6ddcb4 100644 --- a/platform/commonUI/edit/src/actions/PropertiesDialog.js +++ b/platform/commonUI/edit/src/actions/PropertiesDialog.js @@ -37,6 +37,7 @@ define( * @param {TypeImpl} type the type of domain object for which properties * will be specified * @param {DomainObject} the object for which properties will be set + * @memberof platform/commonUI/edit * @constructor * @memberof module:common/actions/properties-dialog */ @@ -47,6 +48,7 @@ define( /** * Get sections provided by this dialog. * @return {FormStructure} the structure of this form + * @memberof platform/commonUI/edit.PropertiesDialog# */ getFormStructure: function () { return { @@ -66,6 +68,7 @@ define( * Get the initial state of the form shown by this dialog * (based on the object model) * @returns {object} initial state of the form + * @memberof platform/commonUI/edit.PropertiesDialog# */ getInitialFormValue: function () { // Start with initial values for properties @@ -77,6 +80,7 @@ define( }, /** * Update a domain object model based on the value of a form. + * @memberof platform/commonUI/edit.PropertiesDialog# */ updateModel: function (model, formValue) { // Update all properties @@ -91,4 +95,4 @@ define( return PropertiesDialog; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/actions/RemoveAction.js b/platform/commonUI/edit/src/actions/RemoveAction.js index fbf47d22d9..b19dff31a2 100644 --- a/platform/commonUI/edit/src/actions/RemoveAction.js +++ b/platform/commonUI/edit/src/actions/RemoveAction.js @@ -37,6 +37,7 @@ define( * * @param {DomainObject} object the object to be removed * @param {ActionContext} context the context in which this action is performed + * @memberof platform/commonUI/edit * @constructor * @memberof module:editor/actions/remove-action */ @@ -47,6 +48,7 @@ define( * Check whether an object ID matches the ID of the object being * removed (used to filter a parent's composition to handle the * removal.) + * @memberof platform/commonUI/edit.RemoveAction# */ function isNotObject(otherObjectId) { return otherObjectId !== object.getId(); @@ -55,6 +57,7 @@ define( /** * Mutate a parent object such that it no longer contains the object * which is being removed. + * @memberof platform/commonUI/edit.RemoveAction# */ function doMutate(model) { model.composition = model.composition.filter(isNotObject); @@ -63,6 +66,7 @@ define( /** * Invoke persistence on a domain object. This will be called upon * the removed object's parent (as its composition will have changed.) + * @memberof platform/commonUI/edit.RemoveAction# */ function doPersist(domainObject) { var persistence = domainObject.getCapability('persistence'); @@ -74,6 +78,7 @@ define( * capability. * @param {ContextCapability} contextCapability the "context" capability * of the domain object being removed. + * @memberof platform/commonUI/edit.RemoveAction# */ function removeFromContext(contextCapability) { var parent = contextCapability.getParent(); @@ -89,6 +94,7 @@ define( * Perform this action. * @return {module:core/promises.Promise} a promise which will be * fulfilled when the action has completed. + * @memberof platform/commonUI/edit.RemoveAction# */ perform: function () { return $q.when(object.getCapability('context')) @@ -113,4 +119,4 @@ define( return RemoveAction; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js index d5db593742..428f825837 100644 --- a/platform/commonUI/edit/src/actions/SaveAction.js +++ b/platform/commonUI/edit/src/actions/SaveAction.js @@ -30,6 +30,8 @@ define( * The "Save" action; the action triggered by clicking Save from * Edit Mode. Exits the editing user interface and invokes object * capabilities to persist the changes that have been made. + * @constructor + * @memberof platform/commonUI/edit */ function SaveAction($location, urlService, context) { var domainObject = context.domainObject; @@ -57,6 +59,7 @@ define( * * @returns {Promise} a promise that will be fulfilled when * cancellation has completed + * @memberof platform/commonUI/edit.SaveAction# */ perform: function () { return doSave().then(returnToBrowse); @@ -78,4 +81,4 @@ define( return SaveAction; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js b/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js index 02276639d2..462a95ec18 100644 --- a/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js @@ -35,6 +35,8 @@ define( * Meant specifically for use by EditableDomainObject and the * associated cache; the constructor signature is particular * to a pattern used there and may contain unused arguments. + * @constructor + * @memberof platform/commonUI/edit */ return function EditableCompositionCapability( contextCapability, @@ -54,4 +56,4 @@ define( ); }; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/capabilities/EditableContextCapability.js b/platform/commonUI/edit/src/capabilities/EditableContextCapability.js index 34ea3ee465..3d61bdd8a3 100644 --- a/platform/commonUI/edit/src/capabilities/EditableContextCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditableContextCapability.js @@ -35,6 +35,8 @@ define( * Meant specifically for use by EditableDomainObject and the * associated cache; the constructor signature is particular * to a pattern used there and may contain unused arguments. + * @constructor + * @memberof platform/commonUI/edit */ return function EditableContextCapability( contextCapability, @@ -72,4 +74,4 @@ define( return capability; }; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js b/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js index 5571072b25..727a569a15 100644 --- a/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js @@ -35,6 +35,8 @@ define( * Meant specifically for use by EditableDomainObject and the * associated cache; the constructor signature is particular * to a pattern used there and may contain unused arguments. + * @constructor + * @memberof platform/commonUI/edit */ return function EditableLookupCapability( contextCapability, @@ -115,4 +117,4 @@ define( return capability; }; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js b/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js index 5252ef1d44..5f702d71b8 100644 --- a/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js @@ -35,6 +35,8 @@ define( * Meant specifically for use by EditableDomainObject and the * associated cache; the constructor signature is particular * to a pattern used there and may contain unused arguments. + * @constructor + * @memberof platform/commonUI/edit */ function EditablePersistenceCapability( persistenceCapability, @@ -62,4 +64,4 @@ define( return EditablePersistenceCapability; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js b/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js index f61a54176c..7567143436 100644 --- a/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js @@ -35,6 +35,8 @@ define( * Meant specifically for use by EditableDomainObject and the * associated cache; the constructor signature is particular * to a pattern used there and may contain unused arguments. + * @constructor + * @memberof platform/commonUI/edit */ return function EditableRelationshipCapability( relationshipCapability, @@ -54,4 +56,4 @@ define( ); }; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/capabilities/EditorCapability.js b/platform/commonUI/edit/src/capabilities/EditorCapability.js index e59fbcae8c..70dfa44dde 100644 --- a/platform/commonUI/edit/src/capabilities/EditorCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditorCapability.js @@ -39,6 +39,8 @@ define( * Meant specifically for use by EditableDomainObject and the * associated cache; the constructor signature is particular * to a pattern used there and may contain unused arguments. + * @constructor + * @memberof platform/commonUI/edit */ return function EditorCapability( persistenceCapability, @@ -83,6 +85,7 @@ define( * object (and not other objects with associated changes) * @returns {Promise} a promise that will be fulfilled after * persistence has completed. + * @memberof platform/commonUI/edit.EditorCapability# */ save: function (nonrecursive) { return nonrecursive ? @@ -95,6 +98,7 @@ define( * been retrieved and modified during the editing session) * @returns {Promise} a promise that will be fulfilled after * cancellation has completed. + * @memberof platform/commonUI/edit.EditorCapability# */ cancel: function () { return resolvePromise(undefined); @@ -102,6 +106,7 @@ define( /** * Check if there are any unsaved changes. * @returns {boolean} true if there are unsaved changes + * @memberof platform/commonUI/edit.EditorCapability# */ dirty: function () { return cache.dirty(); @@ -109,4 +114,4 @@ define( }; }; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/controllers/EditActionController.js b/platform/commonUI/edit/src/controllers/EditActionController.js index 43c173b098..4ea38f9bb5 100644 --- a/platform/commonUI/edit/src/controllers/EditActionController.js +++ b/platform/commonUI/edit/src/controllers/EditActionController.js @@ -33,6 +33,7 @@ define( /** * Controller which supplies action instances for Save/Cancel. + * @memberof platform/commonUI/edit * @constructor */ function EditActionController($scope) { @@ -51,4 +52,4 @@ define( return EditActionController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/controllers/EditController.js b/platform/commonUI/edit/src/controllers/EditController.js index 34cabd0b0b..f0f2822207 100644 --- a/platform/commonUI/edit/src/controllers/EditController.js +++ b/platform/commonUI/edit/src/controllers/EditController.js @@ -33,6 +33,7 @@ define( * Controller which is responsible for populating the scope for * Edit mode; introduces an editable version of the currently * navigated domain object into the scope. + * @memberof platform/commonUI/edit * @constructor */ function EditController($scope, $q, navigationService) { @@ -55,6 +56,7 @@ define( /** * Get the domain object which is navigated-to. * @returns {DomainObject} the domain object that is navigated-to + * @memberof platform/commonUI/edit.EditController# */ navigatedObject: function () { return navigatedObject; @@ -64,6 +66,7 @@ define( * away from Edit mode while unsaved changes are present. * @returns {string} the warning to show, or undefined if * there are no unsaved changes + * @memberof platform/commonUI/edit.EditController# */ getUnloadWarning: function () { var editorCapability = navigatedObject && @@ -79,4 +82,4 @@ define( return EditController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/controllers/EditPanesController.js b/platform/commonUI/edit/src/controllers/EditPanesController.js index 4bfc91002c..258286216f 100644 --- a/platform/commonUI/edit/src/controllers/EditPanesController.js +++ b/platform/commonUI/edit/src/controllers/EditPanesController.js @@ -28,6 +28,7 @@ define( /** * Supports the Library and Elements panes in Edit mode. + * @memberof platform/commonUI/edit * @constructor */ function EditPanesController($scope) { @@ -56,6 +57,7 @@ define( * Get the root-level domain object, as reported by the * represented domain object. * @returns {DomainObject} the root object + * @memberof platform/commonUI/edit.EditPanesController# */ getRoot: function () { return root; @@ -65,4 +67,4 @@ define( return EditPanesController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/directives/MCTBeforeUnload.js b/platform/commonUI/edit/src/directives/MCTBeforeUnload.js index 60e825d1b0..3e7501c788 100644 --- a/platform/commonUI/edit/src/directives/MCTBeforeUnload.js +++ b/platform/commonUI/edit/src/directives/MCTBeforeUnload.js @@ -31,6 +31,7 @@ define( * to this attribute will be evaluated during page navigation events * and, if it returns a truthy value, will be used to populate a * prompt to the user to confirm this navigation. + * @memberof platform/commonUI/edit * @constructor * @param $window the window */ @@ -102,4 +103,4 @@ define( return MCTBeforeUnload; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/objects/EditableDomainObject.js b/platform/commonUI/edit/src/objects/EditableDomainObject.js index dce39bec87..47e10488ea 100644 --- a/platform/commonUI/edit/src/objects/EditableDomainObject.js +++ b/platform/commonUI/edit/src/objects/EditableDomainObject.js @@ -68,6 +68,8 @@ define( * which need to behave differently in edit mode, * and provides a "working copy" of the object's * model to allow changes to be easily cancelled. + * @constructor + * @memberof platform/commonUI/edit */ function EditableDomainObject(domainObject, $q) { // The cache will hold all domain objects reached from @@ -109,4 +111,4 @@ define( return EditableDomainObject; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js b/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js index a13a3e2360..9d69a9e364 100644 --- a/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js +++ b/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js @@ -51,6 +51,7 @@ define( * an argument, and returns an editable domain object as its * result. * @param $q Angular's $q, for promise handling + * @memberof platform/commonUI/edit * @constructor * @memberof module:editor/object/editable-domain-object-cache */ @@ -66,6 +67,7 @@ define( * * @param {DomainObject} domainObject the regular domain object * @returns {DomainObject} the domain object in an editable form + * @memberof platform/commonUI/edit.EditableDomainObjectCache# */ getEditableObject: function (domainObject) { var type = domainObject.getCapability('type'); @@ -94,6 +96,7 @@ define( * Check if a domain object is (effectively) the top-level * object in this editable subgraph. * @returns {boolean} true if it is the root + * @memberof platform/commonUI/edit.EditableDomainObjectCache# */ isRoot: function (domainObject) { return domainObject === root; @@ -104,6 +107,7 @@ define( * included in the bulk save invoked when editing completes. * * @param {DomainObject} domainObject the domain object + * @memberof platform/commonUI/edit.EditableDomainObjectCache# */ markDirty: function (domainObject) { dirty[domainObject.getId()] = domainObject; @@ -114,12 +118,14 @@ define( * save operation.) * * @param {DomainObject} domainObject the domain object + * @memberof platform/commonUI/edit.EditableDomainObjectCache# */ markClean: function (domainObject) { delete dirty[domainObject.getId()]; }, /** * Initiate a save on all objects that have been cached. + * @memberof platform/commonUI/edit.EditableDomainObjectCache# */ saveAll: function () { // Get a list of all dirty objects @@ -140,6 +146,7 @@ define( /** * Check if any objects have been marked dirty in this cache. * @returns {boolean} true if objects are dirty + * @memberof platform/commonUI/edit.EditableDomainObjectCache# */ dirty: function () { return Object.keys(dirty).length > 0; @@ -150,3 +157,4 @@ define( return EditableDomainObjectCache; } ); + diff --git a/platform/commonUI/edit/src/objects/EditableModelCache.js b/platform/commonUI/edit/src/objects/EditableModelCache.js index 3652f679f7..b20ba98c8a 100644 --- a/platform/commonUI/edit/src/objects/EditableModelCache.js +++ b/platform/commonUI/edit/src/objects/EditableModelCache.js @@ -31,6 +31,7 @@ define( * made editable, to support a group that can be saved all-at-once. * This is useful in Edit mode, which is launched for a specific * object but may contain changes across many objects. + * @memberof platform/commonUI/edit * @constructor */ function EditableModelCache() { @@ -47,6 +48,7 @@ define( * Get this domain object's model from the cache (or * place it in the cache if it isn't in the cache yet) * @returns a clone of the domain object's model + * @memberof platform/commonUI/edit.EditableModelCache# */ getCachedModel: function (domainObject) { var id = domainObject.getId(); @@ -60,4 +62,4 @@ define( return EditableModelCache; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/policies/EditActionPolicy.js b/platform/commonUI/edit/src/policies/EditActionPolicy.js index 3c47af43b8..825224317a 100644 --- a/platform/commonUI/edit/src/policies/EditActionPolicy.js +++ b/platform/commonUI/edit/src/policies/EditActionPolicy.js @@ -30,6 +30,7 @@ define( * Policy controlling when the `edit` and/or `properties` actions * can appear as applicable actions of the `view-control` category * (shown as buttons in the top-right of browse mode.) + * @memberof platform/commonUI/edit * @constructor */ function EditActionPolicy() { @@ -54,6 +55,7 @@ define( * @param {Action} action the action * @param context the context * @returns {boolean} true if not disallowed + * @memberof platform/commonUI/edit.EditActionPolicy# */ allow: function (action, context) { var key = action.getMetadata().key, @@ -79,4 +81,4 @@ define( return EditActionPolicy; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/policies/EditableViewPolicy.js b/platform/commonUI/edit/src/policies/EditableViewPolicy.js index c93072e861..92fa0b5256 100644 --- a/platform/commonUI/edit/src/policies/EditableViewPolicy.js +++ b/platform/commonUI/edit/src/policies/EditableViewPolicy.js @@ -28,6 +28,7 @@ define( /** * Policy controlling which views should be visible in Edit mode. + * @memberof platform/commonUI/edit * @constructor */ function EditableViewPolicy() { @@ -38,6 +39,7 @@ define( * @param {Action} action the action * @param domainObject the domain object which will be viewed * @returns {boolean} true if not disallowed + * @memberof platform/commonUI/edit.EditableViewPolicy# */ allow: function (view, domainObject) { // If a view is flagged as non-editable, only allow it @@ -54,4 +56,4 @@ define( return EditableViewPolicy; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/representers/EditRepresenter.js b/platform/commonUI/edit/src/representers/EditRepresenter.js index 96f6da332b..2cca2ee59f 100644 --- a/platform/commonUI/edit/src/representers/EditRepresenter.js +++ b/platform/commonUI/edit/src/representers/EditRepresenter.js @@ -41,6 +41,7 @@ define( * and may be reused for different domain objects and/or * representations resulting from changes there. * + * @memberof platform/commonUI/edit * @constructor */ function EditRepresenter($q, $log, scope) { @@ -113,10 +114,12 @@ define( * definition of the representation in use * @param {DomainObject} domainObject the domain object * being represented + * @memberof platform/commonUI/edit.EditRepresenter# */ represent: represent, /** * Release any resources associated with this representer. + * @memberof platform/commonUI/edit.EditRepresenter# */ destroy: destroy }; @@ -124,4 +127,4 @@ define( return EditRepresenter; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/representers/EditToolbar.js b/platform/commonUI/edit/src/representers/EditToolbar.js index 58dab7497e..81d95582aa 100644 --- a/platform/commonUI/edit/src/representers/EditToolbar.js +++ b/platform/commonUI/edit/src/representers/EditToolbar.js @@ -38,6 +38,7 @@ define( * * @param structure toolbar structure, as provided by view definition * @param {Function} commit callback to invoke after changes + * @memberof platform/commonUI/edit * @constructor */ function EditToolbar(structure, commit) { @@ -221,6 +222,7 @@ define( * Set the current selection. Visisbility of sections * and items in the toolbar will be updated to match this. * @param {Array} s the new selection + * @memberof platform/commonUI/edit.EditToolbar# */ setSelection: function (s) { selection = s; @@ -231,6 +233,7 @@ define( * Get the structure of the toolbar, as appropriate to * pass to `mct-toolbar`. * @returns the toolbar structure + * @memberof platform/commonUI/edit.EditToolbar# */ getStructure: function () { return toolbarStructure; @@ -239,6 +242,7 @@ define( * Get the current state of the toolbar, as appropriate * to two-way bind to the state handled by `mct-toolbar`. * @returns {Array} state of the toolbar + * @memberof platform/commonUI/edit.EditToolbar# */ getState: function () { return toolbarState; @@ -248,6 +252,7 @@ define( * @param {number} index the index of the corresponding * element in the state array * @param value the new value to convey to the selection + * @memberof platform/commonUI/edit.EditToolbar# */ updateState: function (index, value) { return updateProperties(properties[index], value); @@ -259,3 +264,4 @@ define( } ); + diff --git a/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js b/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js index f94ddcd7a8..a574fffc77 100644 --- a/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js +++ b/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js @@ -33,6 +33,7 @@ define( * The EditToolbarRepresenter populates the toolbar in Edit mode * based on a view's definition. * @param {Scope} scope the Angular scope of the representation + * @memberof platform/commonUI/edit * @constructor */ function EditToolbarRepresenter(scope, element, attrs) { @@ -136,10 +137,12 @@ define( * definition of the representation in use * @param {DomainObject} domainObject the domain object * being represented + * @memberof platform/commonUI/edit.EditToolbarRepresenter# */ represent: (attrs || {}).toolbar ? represent : noop, /** * Release any resources associated with this representer. + * @memberof platform/commonUI/edit.EditToolbarRepresenter# */ destroy: (attrs || {}).toolbar ? destroy : noop }; @@ -147,4 +150,4 @@ define( return EditToolbarRepresenter; } -); \ No newline at end of file +); diff --git a/platform/commonUI/edit/src/representers/EditToolbarSelection.js b/platform/commonUI/edit/src/representers/EditToolbarSelection.js index d88ad0da1a..87483a4bbb 100644 --- a/platform/commonUI/edit/src/representers/EditToolbarSelection.js +++ b/platform/commonUI/edit/src/representers/EditToolbarSelection.js @@ -37,6 +37,7 @@ define( * * The selection, for single selected elements within the * view. * + * @memberof platform/commonUI/edit * @constructor */ function EditToolbarSelection() { @@ -106,22 +107,26 @@ define( /** * Check if an object is currently selected. * @returns true if selected, otherwise false + * @memberof platform/commonUI/edit.EditToolbarSelection# */ selected: isSelected, /** * Select an object. * @param obj the object to select * @returns {boolean} true if selection changed + * @memberof platform/commonUI/edit.EditToolbarSelection# */ select: select, /** * Clear the current selection. * @returns {boolean} true if selection changed + * @memberof platform/commonUI/edit.EditToolbarSelection# */ deselect: deselect, /** * Get the currently-selected object. * @returns the currently selected object + * @memberof platform/commonUI/edit.EditToolbarSelection# */ get: get, /** @@ -129,6 +134,7 @@ define( * the view itself.) * @param [proxy] the view proxy (if setting) * @returns the current view proxy + * @memberof platform/commonUI/edit.EditToolbarSelection# */ proxy: proxy, /** @@ -136,6 +142,7 @@ define( * selection proxy. It is generally not advisable to * mutate this array directly. * @returns {Array} all selections + * @memberof platform/commonUI/edit.EditToolbarSelection# */ all: all }; @@ -143,4 +150,4 @@ define( return EditToolbarSelection; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/StyleSheetLoader.js b/platform/commonUI/general/src/StyleSheetLoader.js index 9775288b28..fe535df888 100644 --- a/platform/commonUI/general/src/StyleSheetLoader.js +++ b/platform/commonUI/general/src/StyleSheetLoader.js @@ -29,6 +29,7 @@ define( /** * The StyleSheetLoader adds links to style sheets exposed from * various bundles as extensions of category `stylesheets`. + * @memberof platform/commonUI/general * @constructor * @param {object[]} stylesheets stylesheet extension definitions * @param $document Angular's jqLite-wrapped document element @@ -62,4 +63,4 @@ define( return StyleSheetLoader; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/controllers/ActionGroupController.js b/platform/commonUI/general/src/controllers/ActionGroupController.js index 1675d2e611..0992b5e967 100644 --- a/platform/commonUI/general/src/controllers/ActionGroupController.js +++ b/platform/commonUI/general/src/controllers/ActionGroupController.js @@ -42,6 +42,7 @@ define( * * `ungrouped`: All actions which did not have a defined * group. * + * @memberof platform/commonUI/general * @constructor */ function ActionGroupController($scope) { @@ -102,4 +103,4 @@ define( return ActionGroupController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/controllers/BottomBarController.js b/platform/commonUI/general/src/controllers/BottomBarController.js index b33ce0fe7a..18e3e04dfc 100644 --- a/platform/commonUI/general/src/controllers/BottomBarController.js +++ b/platform/commonUI/general/src/controllers/BottomBarController.js @@ -29,6 +29,7 @@ define( /** * Controller for the bottombar template. Exposes * available indicators (of extension category "indicators") + * @memberof platform/commonUI/general * @constructor */ function BottomBarController(indicators) { @@ -49,6 +50,7 @@ define( * Get all indicators to display. * @returns {Indicator[]} all indicators * to display in the bottom bar. + * @memberof platform/commonUI/general.BottomBarController# */ getIndicators: function () { return indicators; @@ -58,4 +60,4 @@ define( return BottomBarController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/controllers/ClickAwayController.js b/platform/commonUI/general/src/controllers/ClickAwayController.js index 75b1d985da..390e24f50a 100644 --- a/platform/commonUI/general/src/controllers/ClickAwayController.js +++ b/platform/commonUI/general/src/controllers/ClickAwayController.js @@ -31,6 +31,7 @@ define( * menus) where clicking elsewhere in the document while the toggle * is in an active state is intended to dismiss the toggle. * + * @memberof platform/commonUI/general * @constructor * @param $scope the scope in which this controller is active * @param $document the document element, injected by Angular @@ -72,6 +73,7 @@ define( /** * Get the current state of the toggle. * @return {boolean} true if active + * @memberof platform/commonUI/general.ClickAwayController# */ isActive: function () { return state; @@ -79,6 +81,7 @@ define( /** * Set a new state for the toggle. * @return {boolean} true to activate + * @memberof platform/commonUI/general.ClickAwayController# */ setState: function (newState) { if (state !== newState) { @@ -88,6 +91,7 @@ define( /** * Toggle the current state; activate if it is inactive, * deactivate if it is active. + * @memberof platform/commonUI/general.ClickAwayController# */ toggle: function () { changeState(); @@ -98,4 +102,4 @@ define( return ClickAwayController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/controllers/ContextMenuController.js b/platform/commonUI/general/src/controllers/ContextMenuController.js index 4e1bcd3b8f..dece522682 100644 --- a/platform/commonUI/general/src/controllers/ContextMenuController.js +++ b/platform/commonUI/general/src/controllers/ContextMenuController.js @@ -33,6 +33,7 @@ define( * Controller for the context menu. Maintains an up-to-date * list of applicable actions (those from category "contextual") * + * @memberof platform/commonUI/general * @constructor */ function ContextMenuController($scope) { @@ -49,4 +50,4 @@ define( return ContextMenuController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/controllers/GetterSetterController.js b/platform/commonUI/general/src/controllers/GetterSetterController.js index 05d7b2f4ef..3d61c00116 100644 --- a/platform/commonUI/general/src/controllers/GetterSetterController.js +++ b/platform/commonUI/general/src/controllers/GetterSetterController.js @@ -54,6 +54,7 @@ define( * parameter it received.) Getter-setter functions are never the * target of a scope assignment and so avoid this problem. * + * @memberof platform/commonUI/general * @constructor * @param {Scope} $scope the controller's scope */ @@ -87,4 +88,4 @@ define( return GetterSetterController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/controllers/SelectorController.js b/platform/commonUI/general/src/controllers/SelectorController.js index 5b09f3423a..87f9b22b84 100644 --- a/platform/commonUI/general/src/controllers/SelectorController.js +++ b/platform/commonUI/general/src/controllers/SelectorController.js @@ -30,6 +30,7 @@ define( /** * Controller for the domain object selector control. + * @memberof platform/commonUI/general * @constructor * @param {ObjectService} objectService service from which to * read domain objects @@ -102,6 +103,7 @@ define( /** * Get the root object to show in the left-hand tree. * @returns {DomainObject} the root object + * @memberof platform/commonUI/general.SelectorController# */ root: function () { return rootObject; @@ -109,6 +111,7 @@ define( /** * Add a domain object to the list of selected objects. * @param {DomainObject} the domain object to select + * @memberof platform/commonUI/general.SelectorController# */ select: function (domainObject) { var id = domainObject && domainObject.getId(), @@ -122,6 +125,7 @@ define( /** * Remove a domain object from the list of selected objects. * @param {DomainObject} the domain object to select + * @memberof platform/commonUI/general.SelectorController# */ deselect: function (domainObject) { var id = domainObject && domainObject.getId(), @@ -140,6 +144,7 @@ define( /** * Get the currently-selected domain objects. * @returns {DomainObject[]} the current selection + * @memberof platform/commonUI/general.SelectorController# */ selected: function () { return selectedObjects; @@ -153,4 +158,4 @@ define( return SelectorController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/controllers/SplitPaneController.js b/platform/commonUI/general/src/controllers/SplitPaneController.js index c747f2f256..9eb9daa4c6 100644 --- a/platform/commonUI/general/src/controllers/SplitPaneController.js +++ b/platform/commonUI/general/src/controllers/SplitPaneController.js @@ -32,6 +32,7 @@ define( /** * Controller for the splitter in Browse mode. Current implementation * uses many hard-coded constants; this could be generalized. + * @memberof platform/commonUI/general * @constructor */ function SplitPaneController() { @@ -44,6 +45,7 @@ define( * Get the current position of the splitter, in pixels * from the left edge. * @returns {number} position of the splitter, in pixels + * @memberof platform/commonUI/general.SplitPaneController# */ state: function (defaultState) { // Set the state to the desired default, if we don't have a @@ -58,6 +60,7 @@ define( * Begin moving the splitter; this will note the splitter's * current position, which is necessary for correct * interpretation of deltas provided by mct-drag. + * @memberof platform/commonUI/general.SplitPaneController# */ startMove: function () { start = current; @@ -68,6 +71,7 @@ define( * This movement is relative to the position of the * splitter when startMove was last invoked. * @param {number} delta number of pixels to move + * @memberof platform/commonUI/general.SplitPaneController# */ move: function (delta, minimum, maximum) { // Ensure defaults for minimum/maximum @@ -87,4 +91,4 @@ define( return SplitPaneController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/controllers/ToggleController.js b/platform/commonUI/general/src/controllers/ToggleController.js index 0d3bd664ca..d6e73414a1 100644 --- a/platform/commonUI/general/src/controllers/ToggleController.js +++ b/platform/commonUI/general/src/controllers/ToggleController.js @@ -30,6 +30,7 @@ define( * A ToggleController is used to activate/deactivate things. * A common usage is for "twistie" * + * @memberof platform/commonUI/general * @constructor */ function ToggleController() { @@ -39,6 +40,7 @@ define( /** * Get the current state of the toggle. * @return {boolean} true if active + * @memberof platform/commonUI/general.ToggleController# */ isActive: function () { return state; @@ -46,6 +48,7 @@ define( /** * Set a new state for the toggle. * @return {boolean} true to activate + * @memberof platform/commonUI/general.ToggleController# */ setState: function (newState) { state = newState; @@ -53,6 +56,7 @@ define( /** * Toggle the current state; activate if it is inactive, * deactivate if it is active. + * @memberof platform/commonUI/general.ToggleController# */ toggle: function () { state = !state; @@ -63,4 +67,4 @@ define( return ToggleController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/controllers/TreeNodeController.js b/platform/commonUI/general/src/controllers/TreeNodeController.js index 77124bb6e3..3310bf2ae0 100644 --- a/platform/commonUI/general/src/controllers/TreeNodeController.js +++ b/platform/commonUI/general/src/controllers/TreeNodeController.js @@ -48,6 +48,7 @@ define( * node expansion when this tree node's _subtree_ will contain * the navigated object (recursively, this becomes an * expand-to-show-navigated-object behavior.) + * @memberof platform/commonUI/general * @constructor */ function TreeNodeController($scope, $timeout, $rootScope) { @@ -148,11 +149,13 @@ define( * 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. + * @memberof platform/commonUI/general.TreeNodeController# */ trackExpansion: trackExpansion, /** * Check if this not has ever been expanded. * @returns true if it has been expanded + * @memberof platform/commonUI/general.TreeNodeController# */ hasBeenExpanded: function () { return hasBeenExpanded; @@ -163,6 +166,7 @@ define( * An object will be highlighted if it matches * ngModel.selectedObject * @returns true if this should be highlighted + * @memberof platform/commonUI/general.TreeNodeController# */ isSelected: function () { return isSelected; @@ -172,4 +176,4 @@ define( return TreeNodeController; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/controllers/ViewSwitcherController.js b/platform/commonUI/general/src/controllers/ViewSwitcherController.js index 69674013d5..a3ab2e7bc4 100644 --- a/platform/commonUI/general/src/controllers/ViewSwitcherController.js +++ b/platform/commonUI/general/src/controllers/ViewSwitcherController.js @@ -32,6 +32,7 @@ define( /** * Controller for the view switcher; populates and maintains a list * of applicable views for a represented domain object. + * @memberof platform/commonUI/general * @constructor */ function ViewSwitcherController($scope, $timeout) { @@ -71,3 +72,4 @@ define( return ViewSwitcherController; } ); + diff --git a/platform/commonUI/general/src/directives/MCTContainer.js b/platform/commonUI/general/src/directives/MCTContainer.js index 00b7b2b21a..f65cf0803d 100644 --- a/platform/commonUI/general/src/directives/MCTContainer.js +++ b/platform/commonUI/general/src/directives/MCTContainer.js @@ -39,6 +39,7 @@ define( * plain string attribute, instead of as an Angular * expression. * + * @memberof platform/commonUI/general * @constructor */ function MCTContainer(containers) { @@ -96,4 +97,4 @@ define( return MCTContainer; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/directives/MCTDrag.js b/platform/commonUI/general/src/directives/MCTDrag.js index f12aae5c5f..7bccccdf28 100644 --- a/platform/commonUI/general/src/directives/MCTDrag.js +++ b/platform/commonUI/general/src/directives/MCTDrag.js @@ -44,6 +44,7 @@ define( * and vertical pixel offset of the current mouse position * relative to the mouse position where dragging began. * + * @memberof platform/commonUI/general * @constructor * */ @@ -157,3 +158,4 @@ define( return MCTDrag; } ); + diff --git a/platform/commonUI/general/src/directives/MCTResize.js b/platform/commonUI/general/src/directives/MCTResize.js index 62ae977271..c78039627a 100644 --- a/platform/commonUI/general/src/directives/MCTResize.js +++ b/platform/commonUI/general/src/directives/MCTResize.js @@ -49,6 +49,7 @@ define( * This is an Angular expression, and it will be re-evaluated after * each interval. * + * @memberof platform/commonUI/general * @constructor * */ @@ -111,4 +112,4 @@ define( return MCTResize; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/directives/MCTScroll.js b/platform/commonUI/general/src/directives/MCTScroll.js index 3df79f23b2..6b9d480c66 100644 --- a/platform/commonUI/general/src/directives/MCTScroll.js +++ b/platform/commonUI/general/src/directives/MCTScroll.js @@ -37,6 +37,7 @@ define( * This is exposed as two directives in `bundle.json`; the difference * is handled purely by parameterization. * + * @memberof platform/commonUI/general * @constructor * @param $parse Angular's $parse * @param {string} property property to manage within the HTML element @@ -80,4 +81,4 @@ define( return MCTScroll; } -); \ No newline at end of file +); diff --git a/platform/commonUI/general/src/directives/MCTSplitPane.js b/platform/commonUI/general/src/directives/MCTSplitPane.js index 8d95ff2b69..688689d79f 100644 --- a/platform/commonUI/general/src/directives/MCTSplitPane.js +++ b/platform/commonUI/general/src/directives/MCTSplitPane.js @@ -91,6 +91,7 @@ define( * etc. can be set on that element to control the splitter's * allowable positions. * + * @memberof platform/commonUI/general * @constructor */ function MCTSplitPane($parse, $log) { @@ -213,3 +214,4 @@ define( } ); + diff --git a/platform/commonUI/general/src/directives/MCTSplitter.js b/platform/commonUI/general/src/directives/MCTSplitter.js index 0494830057..5216c69358 100644 --- a/platform/commonUI/general/src/directives/MCTSplitter.js +++ b/platform/commonUI/general/src/directives/MCTSplitter.js @@ -39,6 +39,7 @@ define( /** * Implements `mct-splitter` directive. + * @memberof platform/commonUI/general * @constructor */ function MCTSplitter() { @@ -88,3 +89,4 @@ define( } ); + diff --git a/platform/commonUI/general/src/services/UrlService.js b/platform/commonUI/general/src/services/UrlService.js index 4562059d0c..79931add04 100644 --- a/platform/commonUI/general/src/services/UrlService.js +++ b/platform/commonUI/general/src/services/UrlService.js @@ -32,6 +32,8 @@ define( /** * The url service handles calls for url paths * using domain objects. + * @constructor + * @memberof platform/commonUI/general */ function UrlService($location) { // Returns the url for the mode wanted @@ -73,6 +75,7 @@ define( * for the path * @param {DomainObject} value of the domain object * to get the path of + * @memberof platform/commonUI/general.UrlService# */ urlForNewTab: urlForNewTab, /** @@ -83,6 +86,7 @@ define( * for the path * @param {DomainObject} value of the domain object * to get the path of + * @memberof platform/commonUI/general.UrlService# */ urlForLocation: urlForLocation }; @@ -90,4 +94,4 @@ define( return UrlService; } -); \ No newline at end of file +); diff --git a/platform/commonUI/inspect/src/InfoConstants.js b/platform/commonUI/inspect/src/InfoConstants.js index 5e43a1b618..c5886cba92 100644 --- a/platform/commonUI/inspect/src/InfoConstants.js +++ b/platform/commonUI/inspect/src/InfoConstants.js @@ -33,4 +33,4 @@ define({ // Max width and margins allowed for bubbles; defined in /platform/commonUI/general/res/sass/_constants.scss BUBBLE_MARGIN_LR: 10, BUBBLE_MAX_WIDTH: 300 -}); \ No newline at end of file +}); diff --git a/platform/commonUI/inspect/src/gestures/InfoGesture.js b/platform/commonUI/inspect/src/gestures/InfoGesture.js index 879cc2ac36..a22c4515fa 100644 --- a/platform/commonUI/inspect/src/gestures/InfoGesture.js +++ b/platform/commonUI/inspect/src/gestures/InfoGesture.js @@ -30,6 +30,7 @@ define( * The `info` gesture displays domain object metadata in a * bubble on hover. * + * @memberof platform/commonUI/inspect * @constructor * @param $timeout Angular's `$timeout` * @param {InfoService} infoService a service which shows info bubbles @@ -103,6 +104,7 @@ define( * Detach any event handlers associated with this gesture. * @memberof InfoGesture * @method + * @memberof platform/commonUI/inspect.InfoGesture# */ destroy: function () { // Dismiss any active bubble... @@ -119,3 +121,4 @@ define( } ); + diff --git a/platform/commonUI/inspect/src/services/InfoService.js b/platform/commonUI/inspect/src/services/InfoService.js index b67192ba30..ed5bbfaa48 100644 --- a/platform/commonUI/inspect/src/services/InfoService.js +++ b/platform/commonUI/inspect/src/services/InfoService.js @@ -31,6 +31,7 @@ define( /** * Displays informative content ("info bubbles") for the user. + * @memberof platform/commonUI/inspect * @constructor */ function InfoService($compile, $document, $window, $rootScope) { @@ -85,6 +86,7 @@ define( * pixel coordinates. * @returns {Function} a function that may be invoked to * dismiss the info bubble + * @memberof platform/commonUI/inspect.InfoService# */ display: display }; @@ -93,3 +95,4 @@ define( return InfoService; } ); + diff --git a/platform/containment/src/CapabilityTable.js b/platform/containment/src/CapabilityTable.js index db14c0f20f..5a2374af5d 100644 --- a/platform/containment/src/CapabilityTable.js +++ b/platform/containment/src/CapabilityTable.js @@ -32,6 +32,8 @@ define( * which capabilities. This supports composition policy (rules * for which objects can contain which other objects) which * sometimes is determined based on the presence of capabilities. + * @constructor + * @memberof platform/containment */ function CapabilityTable(typeService, capabilityService) { var table = {}; @@ -64,6 +66,7 @@ define( /** * Check if a type is expected to expose a specific * capability. + * @memberof platform/containment.CapabilityTable# */ hasCapability: function (typeKey, capabilityKey) { return (table[capabilityKey] || {})[typeKey]; @@ -73,4 +76,4 @@ define( return CapabilityTable; } -); \ No newline at end of file +); diff --git a/platform/containment/src/ComposeActionPolicy.js b/platform/containment/src/ComposeActionPolicy.js index 6d3952b763..90c7983bc9 100644 --- a/platform/containment/src/ComposeActionPolicy.js +++ b/platform/containment/src/ComposeActionPolicy.js @@ -34,6 +34,8 @@ define( * since it's delegated to a different policy category. * To avoid a circular dependency, the service is obtained via * Angular's `$injector`. + * @constructor + * @memberof platform/containment */ function ComposeActionPolicy($injector) { var policyService; @@ -61,6 +63,7 @@ define( * Check whether or not a compose action should be allowed * in this context. * @returns {boolean} true if it may be allowed + * @memberof platform/containment.ComposeActionPolicy# */ allow: function (candidate, context) { if (candidate.getMetadata().key === 'compose') { @@ -77,4 +80,4 @@ define( return ComposeActionPolicy; } -); \ No newline at end of file +); diff --git a/platform/containment/src/CompositionModelPolicy.js b/platform/containment/src/CompositionModelPolicy.js index 74f1200530..0c76097ed4 100644 --- a/platform/containment/src/CompositionModelPolicy.js +++ b/platform/containment/src/CompositionModelPolicy.js @@ -8,12 +8,15 @@ define( /** * Policy allowing composition only for domain object types which * have a composition property. + * @constructor + * @memberof platform/containment */ function CompositionModelPolicy() { return { /** * Is the type identified by the candidate allowed to * contain the type described by the context? + * @memberof platform/containment.CompositionModelPolicy# */ allow: function (candidate, context) { return Array.isArray( @@ -25,4 +28,4 @@ define( return CompositionModelPolicy; } -); \ No newline at end of file +); diff --git a/platform/containment/src/CompositionMutabilityPolicy.js b/platform/containment/src/CompositionMutabilityPolicy.js index 9b3e12eb95..375f26e405 100644 --- a/platform/containment/src/CompositionMutabilityPolicy.js +++ b/platform/containment/src/CompositionMutabilityPolicy.js @@ -28,6 +28,7 @@ define( /** * Disallow composition changes to objects which are not mutable. + * @memberof platform/containment * @constructor */ function CompositionMutabilityPolicy() { @@ -36,6 +37,7 @@ define( * Is the type identified by the candidate allowed to * contain the type described by the context? * @param {Type} candidate the type of domain object + * @memberof platform/containment.CompositionMutabilityPolicy# */ allow: function (candidate) { // Equate creatability with mutability; that is, users @@ -48,4 +50,4 @@ define( return CompositionMutabilityPolicy; } -); \ No newline at end of file +); diff --git a/platform/containment/src/CompositionPolicy.js b/platform/containment/src/CompositionPolicy.js index 992fced49f..2fcd4e94a9 100644 --- a/platform/containment/src/CompositionPolicy.js +++ b/platform/containment/src/CompositionPolicy.js @@ -28,6 +28,8 @@ define( /** * Defines composition policy as driven by type metadata. + * @constructor + * @memberof platform/containment */ function CompositionPolicy($injector) { // We're really just wrapping the containment table and rephrasing @@ -45,6 +47,7 @@ define( /** * Is the type identified by the candidate allowed to * contain the type described by the context? + * @memberof platform/containment.CompositionPolicy# */ allow: function (candidate, context) { return getTable().canContain(candidate, context); @@ -54,4 +57,4 @@ define( return CompositionPolicy; } -); \ No newline at end of file +); diff --git a/platform/containment/src/ContainmentTable.js b/platform/containment/src/ContainmentTable.js index a3d7ab6ed4..a71570ca3a 100644 --- a/platform/containment/src/ContainmentTable.js +++ b/platform/containment/src/ContainmentTable.js @@ -37,6 +37,8 @@ define( * start time (plug-in support means this cannot be determined * prior to that, but we don't want to redo these calculations * every time policy is checked.) + * @constructor + * @memberof platform/containment */ function ContainmentTable(typeService, capabilityService) { var types = typeService.listTypes(), @@ -103,6 +105,7 @@ define( * Check if domain objects of one type can contain domain * objects of another type. * @returns {boolean} true if allowable + * @memberof platform/containment.ContainmentTable# */ canContain: function (containerType, containedType) { var set = table[containerType.getKey()] || {}; @@ -116,4 +119,4 @@ define( return ContainmentTable; } -); \ No newline at end of file +); diff --git a/platform/core/src/actions/ActionAggregator.js b/platform/core/src/actions/ActionAggregator.js index 4a9288a612..c12f3cf07d 100644 --- a/platform/core/src/actions/ActionAggregator.js +++ b/platform/core/src/actions/ActionAggregator.js @@ -31,6 +31,7 @@ define( * actions for a given context, results from all * services will be assembled and concatenated. * + * @memberof platform/core * @constructor * @param {ActionProvider[]} actionProviders an array * of action services @@ -65,6 +66,7 @@ define( * * @method * @memberof ActionAggregator + * @memberof platform/core.ActionAggregator# */ getActions: getActions }; @@ -72,4 +74,4 @@ define( return ActionAggregator; } -); \ No newline at end of file +); diff --git a/platform/core/src/actions/ActionCapability.js b/platform/core/src/actions/ActionCapability.js index 94b0706a0d..b5d055bcb0 100644 --- a/platform/core/src/actions/ActionCapability.js +++ b/platform/core/src/actions/ActionCapability.js @@ -45,6 +45,7 @@ define( * which the action will be performed (also, the * action which exposes the capability.) * + * @memberof platform/core * @constructor */ function ActionCapability($q, actionService, domainObject) { @@ -92,6 +93,7 @@ define( * @returns {Promise} the result of the action that was * performed, or undefined if no matching action * was found. + * @memberof platform/core.ActionCapability# */ perform: performAction, /** @@ -107,6 +109,7 @@ define( * be taken as the "key" field to match against * specific actions. * @returns {Action[]} an array of matching actions + * @memberof platform/core.ActionCapability# */ getActions: getActions }; @@ -114,4 +117,4 @@ define( return ActionCapability; } -); \ No newline at end of file +); diff --git a/platform/core/src/actions/ActionProvider.js b/platform/core/src/actions/ActionProvider.js index 5937f00fc2..67bc56520f 100644 --- a/platform/core/src/actions/ActionProvider.js +++ b/platform/core/src/actions/ActionProvider.js @@ -35,6 +35,7 @@ define( * of actions exposed via extension (specifically, the "actions" * category of extension.) * + * @memberof platform/core * @constructor */ function ActionProvider(actions) { @@ -145,6 +146,7 @@ define( * * @method * @memberof ActionProvider + * @memberof platform/core.ActionProvider# */ getActions: getActions }; @@ -152,4 +154,4 @@ define( return ActionProvider; } -); \ No newline at end of file +); diff --git a/platform/core/src/actions/LoggingActionDecorator.js b/platform/core/src/actions/LoggingActionDecorator.js index 3e9652d229..cb6efa245e 100644 --- a/platform/core/src/actions/LoggingActionDecorator.js +++ b/platform/core/src/actions/LoggingActionDecorator.js @@ -34,6 +34,7 @@ define( * the actions it exposes always emit a log message when they are * performed. * + * @memberof platform/core * @constructor */ function LoggingActionDecorator($log, actionService) { @@ -77,6 +78,7 @@ define( * * @method * @memberof LoggingActionDecorator + * @memberof platform/core.LoggingActionDecorator# */ getActions: function () { return actionService.getActions.apply( @@ -89,4 +91,4 @@ define( return LoggingActionDecorator; } -); \ No newline at end of file +); diff --git a/platform/core/src/capabilities/CompositionCapability.js b/platform/core/src/capabilities/CompositionCapability.js index 8049d5b3c4..88ed279dd7 100644 --- a/platform/core/src/capabilities/CompositionCapability.js +++ b/platform/core/src/capabilities/CompositionCapability.js @@ -37,6 +37,7 @@ define( * require consulting the object service (e.g. to trigger a database * query to retrieve the nested object models.) * + * @memberof platform/core * @constructor */ function CompositionCapability($injector, domainObject) { @@ -94,6 +95,7 @@ define( * Request the composition of this object. * @returns {Promise.} a list of all domain * objects which compose this domain object. + * @memberof platform/core.CompositionCapability# */ invoke: promiseComposition }; @@ -112,4 +114,4 @@ define( return CompositionCapability; } -); \ No newline at end of file +); diff --git a/platform/core/src/capabilities/ContextCapability.js b/platform/core/src/capabilities/ContextCapability.js index 9eeb00823b..d94c7ed3f6 100644 --- a/platform/core/src/capabilities/ContextCapability.js +++ b/platform/core/src/capabilities/ContextCapability.js @@ -36,6 +36,7 @@ define( * those whose `composition` capability was used to access this * object.) * + * @memberof platform/core * @constructor */ function ContextCapability(parentObject, domainObject) { @@ -50,6 +51,7 @@ define( * * @returns {DomainObject} the immediate parent of this * domain object. + * @memberof platform/core.ContextCapability# */ getParent: function () { return parentObject; @@ -72,6 +74,7 @@ define( * @returns {DomainObject[]} the full composition ancestry * of the domain object which exposed this * capability. + * @memberof platform/core.ContextCapability# */ getPath: function () { var parentPath = [], @@ -95,6 +98,7 @@ define( * * @returns {DomainObject} the deepest ancestor of the domain * object which exposed this capability. + * @memberof platform/core.ContextCapability# */ getRoot: function () { var parentContext = parentObject && @@ -109,4 +113,4 @@ define( return ContextCapability; } -); \ No newline at end of file +); diff --git a/platform/core/src/capabilities/ContextualDomainObject.js b/platform/core/src/capabilities/ContextualDomainObject.js index 0d042923a0..1475d3d384 100644 --- a/platform/core/src/capabilities/ContextualDomainObject.js +++ b/platform/core/src/capabilities/ContextualDomainObject.js @@ -42,6 +42,7 @@ define( * @param {DomainObject} parentObject the domain object from which * the wrapped object was retrieved * + * @memberof platform/core * @constructor */ function ContextualDomainObject(domainObject, parentObject) { @@ -63,4 +64,4 @@ define( return ContextualDomainObject; } -); \ No newline at end of file +); diff --git a/platform/core/src/capabilities/CoreCapabilityProvider.js b/platform/core/src/capabilities/CoreCapabilityProvider.js index 89660b72ee..a1148430f2 100644 --- a/platform/core/src/capabilities/CoreCapabilityProvider.js +++ b/platform/core/src/capabilities/CoreCapabilityProvider.js @@ -37,6 +37,7 @@ define( * of constructor functions for capabilities, as * exposed by extensions defined at the bundle level. * + * @memberof platform/core * @constructor */ function CoreCapabilityProvider(capabilities, $log) { @@ -84,6 +85,7 @@ define( * @returns {Object.} all * capabilities known to be valid for this model, as * key-value pairs + * @memberof platform/core.CoreCapabilityProvider# */ getCapabilities: getCapabilities }; @@ -92,3 +94,4 @@ define( return CoreCapabilityProvider; } ); + diff --git a/platform/core/src/capabilities/DelegationCapability.js b/platform/core/src/capabilities/DelegationCapability.js index 452b842452..2259e5c420 100644 --- a/platform/core/src/capabilities/DelegationCapability.js +++ b/platform/core/src/capabilities/DelegationCapability.js @@ -46,6 +46,7 @@ define( * capabilities to be delegated. * * @param domainObject + * @memberof platform/core * @constructor */ function DelegationCapability($q, domainObject) { @@ -96,6 +97,7 @@ define( * @param {string} the name of the delegated capability * @returns {DomainObject[]} the domain objects to which * responsibility for this capability is delegated. + * @memberof platform/core.DelegationCapability# */ invoke: getDelegates, /** @@ -105,6 +107,7 @@ define( * @param {string} the name of the delegated capability * @returns {DomainObject[]} the domain objects to which * responsibility for this capability is delegated. + * @memberof platform/core.DelegationCapability# */ getDelegates: getDelegates, doesDelegateCapability: doesDelegate @@ -115,4 +118,4 @@ define( return DelegationCapability; } -); \ No newline at end of file +); diff --git a/platform/core/src/capabilities/MetadataCapability.js b/platform/core/src/capabilities/MetadataCapability.js index 677dab0008..027c9ffe1d 100644 --- a/platform/core/src/capabilities/MetadataCapability.js +++ b/platform/core/src/capabilities/MetadataCapability.js @@ -11,6 +11,8 @@ define( * @property {string} name the human-readable name of this property * @property {string} value the human-readable value of this property, * for this specific domain object + * @constructor + * @memberof platform/core */ var TIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; @@ -82,6 +84,7 @@ define( /** * Get metadata about this object. * @returns {MetadataProperty[]} metadata about this object + * @memberof platform/core.MetadataCapability# */ invoke: getMetadata }; @@ -90,3 +93,4 @@ define( return MetadataCapability; } ); + diff --git a/platform/core/src/capabilities/MutationCapability.js b/platform/core/src/capabilities/MutationCapability.js index 4268f7c323..8ba11be13b 100644 --- a/platform/core/src/capabilities/MutationCapability.js +++ b/platform/core/src/capabilities/MutationCapability.js @@ -71,6 +71,7 @@ define( * * @param {DomainObject} domainObject the domain object * which will expose this capability + * @memberof platform/core * @constructor */ function MutationCapability(topic, now, domainObject) { @@ -118,6 +119,7 @@ define( return { /** * Alias of `mutate`, used to support useCapability. + * @memberof platform/core.MutationCapability# */ invoke: mutate, /** @@ -146,6 +148,7 @@ define( * used) * @returns {Promise.} a promise for the result * of the mutation; true if changes were made. + * @memberof platform/core.MutationCapability# */ mutate: mutate, /** @@ -155,6 +158,7 @@ define( * invoke the function returned by this method. * @param {Function} listener function to call on mutation * @returns {Function} a function to stop listening + * @memberof platform/core.MutationCapability# */ listen: listen }; @@ -163,3 +167,4 @@ define( return MutationCapability; } ); + diff --git a/platform/core/src/capabilities/PersistenceCapability.js b/platform/core/src/capabilities/PersistenceCapability.js index 68c3255412..de18b69222 100644 --- a/platform/core/src/capabilities/PersistenceCapability.js +++ b/platform/core/src/capabilities/PersistenceCapability.js @@ -40,6 +40,7 @@ define( * @param {DomainObject} the domain object which shall expose * this capability * + * @memberof platform/core * @constructor */ function PersistenceCapability(persistenceService, SPACE, domainObject) { @@ -80,6 +81,7 @@ define( * @returns {Promise} a promise which will be resolved * if persistence is successful, and rejected * if not. + * @memberof platform/core.PersistenceCapability# */ persist: function () { updatePersistenceTimestamp(); @@ -94,6 +96,7 @@ define( * persistence. * @returns {Promise} a promise which will be resolved * when the update is complete + * @memberof platform/core.PersistenceCapability# */ refresh: function () { var model = domainObject.getModel(); @@ -114,6 +117,7 @@ define( * * @returns {string} the name of the space which should * be used to persist this object + * @memberof platform/core.PersistenceCapability# */ getSpace: function () { return SPACE; @@ -123,4 +127,4 @@ define( return PersistenceCapability; } -); \ No newline at end of file +); diff --git a/platform/core/src/capabilities/RelationshipCapability.js b/platform/core/src/capabilities/RelationshipCapability.js index fc8729a9a1..3bbc210b36 100644 --- a/platform/core/src/capabilities/RelationshipCapability.js +++ b/platform/core/src/capabilities/RelationshipCapability.js @@ -38,6 +38,7 @@ define( * which are not intended to appear in the tree, but are instead * intended only for special, limited usage. * + * @memberof platform/core * @constructor */ function RelationshipCapability($injector, domainObject) { @@ -109,6 +110,7 @@ define( * List all types of relationships exposed by this * object. * @returns {string[]} a list of all relationship types + * @memberof platform/core.RelationshipCapability# */ listRelationships: listRelationships, /** @@ -118,6 +120,7 @@ define( * @param {string} key the type of relationship * @returns {Promise.} a promise for related * domain objects + * @memberof platform/core.RelationshipCapability# */ getRelatedObjects: promiseRelationships }; @@ -136,4 +139,4 @@ define( return RelationshipCapability; } -); \ No newline at end of file +); diff --git a/platform/core/src/models/CachingModelDecorator.js b/platform/core/src/models/CachingModelDecorator.js index d9d4ef6775..c74cea05f0 100644 --- a/platform/core/src/models/CachingModelDecorator.js +++ b/platform/core/src/models/CachingModelDecorator.js @@ -30,6 +30,7 @@ define( * The caching model decorator maintains a cache of loaded domain * object models, and ensures that duplicate models for the same * object are not provided. + * @memberof platform/core * @constructor */ function CachingModelDecorator(modelService) { @@ -114,6 +115,7 @@ define( * containing key-value pairs, where keys are * ids and values are models * @method + * @memberof platform/core.CachingModelDecorator# */ getModels: function (ids) { var neededIds = ids.filter(notCached); @@ -133,4 +135,4 @@ define( return CachingModelDecorator; } -); \ No newline at end of file +); diff --git a/platform/core/src/models/MissingModelDecorator.js b/platform/core/src/models/MissingModelDecorator.js index 3c82bd2726..fca716733e 100644 --- a/platform/core/src/models/MissingModelDecorator.js +++ b/platform/core/src/models/MissingModelDecorator.js @@ -30,6 +30,8 @@ define( * Adds placeholder domain object models for any models which * fail to load from the underlying model service. * @implements {ModelService} + * @constructor + * @memberof platform/core */ function MissingModelDecorator(modelService) { function missingModel(id) { @@ -57,3 +59,4 @@ define( return MissingModelDecorator; } ); + diff --git a/platform/core/src/models/ModelAggregator.js b/platform/core/src/models/ModelAggregator.js index 30b645ff86..437bba4ec3 100644 --- a/platform/core/src/models/ModelAggregator.js +++ b/platform/core/src/models/ModelAggregator.js @@ -33,6 +33,7 @@ define( * Allows multiple services which provide models for domain objects * to be treated as one. * + * @memberof platform/core * @constructor * @param {ModelProvider[]} providers the model providers to be * aggregated @@ -77,6 +78,7 @@ define( * containing key-value pairs, * where keys are object identifiers and values * are object models. + * @memberof platform/core.ModelAggregator# */ getModels: function (ids) { return $q.all(providers.map(function (provider) { @@ -90,4 +92,4 @@ define( return ModelAggregator; } -); \ No newline at end of file +); diff --git a/platform/core/src/models/PersistedModelProvider.js b/platform/core/src/models/PersistedModelProvider.js index add01ba654..311f40eeaa 100644 --- a/platform/core/src/models/PersistedModelProvider.js +++ b/platform/core/src/models/PersistedModelProvider.js @@ -33,6 +33,7 @@ define( * A model service which reads domain object models from an external * persistence service. * + * @memberof platform/core * @constructor * @param {PersistenceService} persistenceService the service in which * domain object models are persisted. @@ -83,6 +84,7 @@ define( * containing key-value pairs, * where keys are object identifiers and values * are object models. + * @memberof platform/core.PersistedModelProvider# */ getModels: promiseModels }; @@ -91,4 +93,4 @@ define( return PersistedModelProvider; } -); \ No newline at end of file +); diff --git a/platform/core/src/models/RootModelProvider.js b/platform/core/src/models/RootModelProvider.js index 804537ccf2..bf819d51ae 100644 --- a/platform/core/src/models/RootModelProvider.js +++ b/platform/core/src/models/RootModelProvider.js @@ -39,6 +39,7 @@ define( * exposes them all as composition of the root object ROOT, * whose model is also provided by this service. * + * @memberof platform/core * @constructor */ function RootModelProvider(roots, $q, $log) { @@ -68,6 +69,7 @@ define( * containing key-value pairs, * where keys are object identifiers and values * are object models. + * @memberof platform/core.RootModelProvider# */ getModels: function (ids) { return baseProvider.getModels(ids).then(addRoot); @@ -77,4 +79,4 @@ define( return RootModelProvider; } -); \ No newline at end of file +); diff --git a/platform/core/src/models/StaticModelProvider.js b/platform/core/src/models/StaticModelProvider.js index eb946d6d4b..68b76d6b43 100644 --- a/platform/core/src/models/StaticModelProvider.js +++ b/platform/core/src/models/StaticModelProvider.js @@ -31,6 +31,7 @@ define( /** * Loads static models, provided as declared extensions of bundles. + * @memberof platform/core * @constructor */ function StaticModelProvider(models, $q, $log) { @@ -69,6 +70,7 @@ define( * ids and values are models * @method * @memberof StaticModelProvider# + * @memberof platform/core.StaticModelProvider# */ getModels: function (ids) { var result = {}; @@ -82,4 +84,4 @@ define( return StaticModelProvider; } -); \ No newline at end of file +); diff --git a/platform/core/src/objects/DomainObject.js b/platform/core/src/objects/DomainObject.js index e3a10160a5..c36e5db516 100644 --- a/platform/core/src/objects/DomainObject.js +++ b/platform/core/src/objects/DomainObject.js @@ -37,6 +37,7 @@ define( * @param {object} model the "JSONifiable" state of the object * @param {Object.|function} capabilities all * capabilities to be exposed by this object + * @memberof platform/core * @constructor */ function DomainObject(id, model, capabilities) { @@ -45,6 +46,7 @@ define( * Get the unique identifier for this domain object. * @return {string} the domain object's unique identifier * @memberof DomainObject# + * @memberof platform/core.DomainObject# */ getId: function () { return id; @@ -59,6 +61,7 @@ define( * * @return {object} the domain object's persistent state * @memberof DomainObject# + * @memberof platform/core.DomainObject# */ getModel: function () { return model; @@ -73,6 +76,7 @@ define( * @return {Capability} the named capability, or undefined * if not present. * @memberof DomainObject# + * @memberof platform/core.DomainObject# */ getCapability: function (name) { var capability = capabilities[name]; @@ -87,6 +91,7 @@ define( * @param {string} name the name of the capability to * check for * @returns {boolean} true if provided + * @memberof platform/core.DomainObject# */ hasCapability: function hasCapability(name) { return this.getCapability(name) !== undefined; @@ -110,6 +115,7 @@ define( * @param {...*} [arguments] to pass to the invocation * @returns {*} * @memberof DomainObject# + * @memberof platform/core.DomainObject# */ useCapability: function (name) { // Get tail of args to pass to invoke @@ -125,4 +131,4 @@ define( return DomainObject; } -); \ No newline at end of file +); diff --git a/platform/core/src/objects/DomainObjectProvider.js b/platform/core/src/objects/DomainObjectProvider.js index 46e0fbea6a..852afd2847 100644 --- a/platform/core/src/objects/DomainObjectProvider.js +++ b/platform/core/src/objects/DomainObjectProvider.js @@ -38,6 +38,7 @@ define( * which provides capabilities (dynamic behavior) * for domain objects. * @param $q Angular's $q, for promise consolidation + * @memberof platform/core * @constructor */ function DomainObjectProvider(modelService, capabilityService, $q) { @@ -97,6 +98,7 @@ define( * are string identifiers for domain objects, and * values are the corresponding domain objects themselves. * @memberof module:core/object/object-provider.ObjectProvider# + * @memberof platform/core.DomainObjectProvider# */ getObjects: getObjects }; @@ -104,4 +106,4 @@ define( return DomainObjectProvider; } -); \ No newline at end of file +); diff --git a/platform/core/src/services/Now.js b/platform/core/src/services/Now.js index ea78cbd57a..b799d80391 100644 --- a/platform/core/src/services/Now.js +++ b/platform/core/src/services/Now.js @@ -31,12 +31,15 @@ define( * `Date.now()` which can be injected to support testability. * * @returns {Function} a function which returns current system time + * @constructor + * @memberof platform/core */ function Now() { /** * Get the current time. * @returns {number} current time, in milliseconds since * 1970-01-01 00:00:00Z + * @memberof platform/core.Now# */ return function () { return Date.now(); @@ -45,4 +48,4 @@ define( return Now; } -); \ No newline at end of file +); diff --git a/platform/core/src/services/Throttle.js b/platform/core/src/services/Throttle.js index c0493a733a..16b258ba13 100644 --- a/platform/core/src/services/Throttle.js +++ b/platform/core/src/services/Throttle.js @@ -42,6 +42,8 @@ define( * resolve to the returned value of `fn` whenever that is invoked. * * @returns {Function} + * @constructor + * @memberof platform/core */ function Throttle($timeout) { /** @@ -52,6 +54,7 @@ define( * @param {boolean} apply true if a `$apply` call should be * invoked after this function executes; defaults to * `false`. + * @memberof platform/core.Throttle# */ return function (fn, delay, apply) { var activeTimeout; @@ -82,3 +85,4 @@ define( return Throttle; } ); + diff --git a/platform/core/src/services/Topic.js b/platform/core/src/services/Topic.js index f1afafa843..cc57b4314c 100644 --- a/platform/core/src/services/Topic.js +++ b/platform/core/src/services/Topic.js @@ -44,6 +44,8 @@ define( * arguments) are private; each call returns a new instance. * * @returns {Function} + * @constructor + * @memberof platform/core */ function Topic() { var topics = {}; @@ -71,6 +73,7 @@ define( /** * Use and (if necessary) create a new topic. * @param {string} [key] name of the topic to use + * @memberof platform/core.Topic# */ return function (key) { if (arguments.length < 1) { @@ -85,3 +88,4 @@ define( return Topic; } ); + diff --git a/platform/core/src/types/MergeModels.js b/platform/core/src/types/MergeModels.js index 1b5639b823..b3df6d65ae 100644 --- a/platform/core/src/types/MergeModels.js +++ b/platform/core/src/types/MergeModels.js @@ -64,6 +64,8 @@ define( * @param b the second object to be merged * @param merger the merger, as described above * @returns {*} the result of merging `a` and `b` + * @constructor + * @memberof platform/core */ function mergeModels(a, b, merger) { var mergeFunction; @@ -102,4 +104,4 @@ define( return mergeModels; } -); \ No newline at end of file +); diff --git a/platform/core/src/types/TypeCapability.js b/platform/core/src/types/TypeCapability.js index d14cff5caf..ca311aab2a 100644 --- a/platform/core/src/types/TypeCapability.js +++ b/platform/core/src/types/TypeCapability.js @@ -34,6 +34,7 @@ define( * type directly available when working with that object, by way * of a `domainObject.getCapability('type')` invocation. * + * @memberof platform/core * @constructor * @param {TypeService} typeService the service which * provides type information @@ -51,4 +52,4 @@ define( return TypeCapability; } -); \ No newline at end of file +); diff --git a/platform/core/src/types/TypeImpl.js b/platform/core/src/types/TypeImpl.js index a6ddd8e8aa..9e5a52d37f 100644 --- a/platform/core/src/types/TypeImpl.js +++ b/platform/core/src/types/TypeImpl.js @@ -42,6 +42,8 @@ define( * key-value pairs describing a type and its * relationship to other types. * @memberof module:core/type/type-impl + * @constructor + * @memberof platform/core */ function TypeImpl(typeDef) { var inheritList = typeDef.inherits || [], @@ -60,6 +62,7 @@ define( * * @returns {string} the key which identifies this type * @memberof module:core/type/type-impl.TypeImpl# + * @memberof platform/core.TypeImpl# */ getKey: function () { return typeDef.key; @@ -71,6 +74,7 @@ define( * * @returns {string} the human-readable name of this type * @memberof module:core/type/type-impl.TypeImpl# + * @memberof platform/core.TypeImpl# */ getName: function () { return typeDef.name; @@ -82,6 +86,7 @@ define( * * @returns {string} the human-readable description of this type * @memberof module:core/type/type-impl.TypeImpl# + * @memberof platform/core.TypeImpl# */ getDescription: function () { return typeDef.description; @@ -94,6 +99,7 @@ define( * * @returns {string} the glyph to be displayed * @memberof module:core/type/type-impl.TypeImpl# + * @memberof platform/core.TypeImpl# */ getGlyph: function () { return typeDef.glyph; @@ -105,6 +111,7 @@ define( * * @return {Array} properties associated with * objects of this type + * @memberof platform/core.TypeImpl# */ getProperties: function () { return (typeDef.properties || []).map(TypeProperty); @@ -114,6 +121,7 @@ define( * this type. * * @return {object} initial domain object model + * @memberof platform/core.TypeImpl# */ getInitialModel: function () { return typeDef.model || {}; @@ -126,6 +134,7 @@ define( * * @returns {object} the raw definition for this type * @memberof module:core/type/type-impl.TypeImpl# + * @memberof platform/core.TypeImpl# */ getDefinition: function () { return typeDef; @@ -141,6 +150,7 @@ define( * object, which this * @returns {boolean} true * @memberof module:core/type/type-impl.TypeImpl# + * @memberof platform/core.TypeImpl# */ instanceOf: function instanceOf(key) { @@ -162,6 +172,7 @@ define( * the type definition's "feature" field. * @param {string} feature a string identifying the feature * @returns {boolean} true if the feature is supported + * @memberof platform/core.TypeImpl# */ hasFeature: function (feature) { return featureSet[feature] || false; @@ -171,4 +182,4 @@ define( return TypeImpl; } -); \ No newline at end of file +); diff --git a/platform/core/src/types/TypeProperty.js b/platform/core/src/types/TypeProperty.js index 50bd1621a1..fb58199c06 100644 --- a/platform/core/src/types/TypeProperty.js +++ b/platform/core/src/types/TypeProperty.js @@ -36,6 +36,7 @@ define( * Instantiate a property associated with domain objects of a * given type. This provides an interface by which * + * @memberof platform/core * @constructor * @memberof module:core/type/type-property */ @@ -114,6 +115,7 @@ define( /** * Retrieve the value associated with this property * from a given model. + * @memberof platform/core.TypeProperty# */ getValue: function (model) { var property = propertyDefinition.property || @@ -133,6 +135,7 @@ define( /** * Set a value associated with this property in * an object's model. + * @memberof platform/core.TypeProperty# */ setValue: function setValue(model, value) { var property = propertyDefinition.property || @@ -153,6 +156,7 @@ define( }, /** * Get the raw definition for this property. + * @memberof platform/core.TypeProperty# */ getDefinition: function () { return propertyDefinition; @@ -162,4 +166,4 @@ define( return TypeProperty; } -); \ No newline at end of file +); diff --git a/platform/core/src/types/TypePropertyConversion.js b/platform/core/src/types/TypePropertyConversion.js index b00df71c72..d390e74108 100644 --- a/platform/core/src/types/TypePropertyConversion.js +++ b/platform/core/src/types/TypePropertyConversion.js @@ -62,6 +62,8 @@ define( /** * Look up an appropriate conversion between form values and model * values, e.g. to numeric values. + * @constructor + * @memberof platform/core */ function TypePropertyConversion(name) { if (name && @@ -82,4 +84,4 @@ define( return TypePropertyConversion; } -); \ No newline at end of file +); diff --git a/platform/core/src/types/TypeProvider.js b/platform/core/src/types/TypeProvider.js index 79d8c8f800..f321cdc0ef 100644 --- a/platform/core/src/types/TypeProvider.js +++ b/platform/core/src/types/TypeProvider.js @@ -55,6 +55,7 @@ define( * * @param {Array} options.definitions the raw type * definitions for this type. + * @memberof platform/core * @constructor * @memberof module:core/type/type-provider */ @@ -154,6 +155,7 @@ define( * promise for an array of all type instances defined * by this service. * @memberof module:core/type/type-provider.TypeProvider# + * @memberof platform/core.TypeProvider# */ listTypes: function () { var self = this; @@ -176,6 +178,7 @@ define( * @returns {Promise} a * promise for a type object identified by this key. * @memberof module:core/type/type-provider.TypeProvider# + * @memberof platform/core.TypeProvider# */ getType: function (key) { return new TypeImpl(lookupTypeDef(key)); @@ -191,4 +194,4 @@ define( } -); \ No newline at end of file +); diff --git a/platform/core/src/views/ViewCapability.js b/platform/core/src/views/ViewCapability.js index 3653cf5ac5..8cdf7eaecb 100644 --- a/platform/core/src/views/ViewCapability.js +++ b/platform/core/src/views/ViewCapability.js @@ -35,6 +35,7 @@ define( * thereabout) which are applicable to a specific domain * object. * + * @memberof platform/core * @constructor */ function ViewCapability(viewService, domainObject) { @@ -44,6 +45,7 @@ define( * this object. * @returns {View[]} an array of view definitions * which are applicable to this object. + * @memberof platform/core.ViewCapability# */ invoke: function () { return viewService.getViews(domainObject); @@ -53,4 +55,4 @@ define( return ViewCapability; } -); \ No newline at end of file +); diff --git a/platform/core/src/views/ViewProvider.js b/platform/core/src/views/ViewProvider.js index 2b82f0f67d..e3e9e550d2 100644 --- a/platform/core/src/views/ViewProvider.js +++ b/platform/core/src/views/ViewProvider.js @@ -55,6 +55,7 @@ define( * The role of a view provider and of a view capability is to * describe what views are available, not how to instantiate them. * + * @memberof platform/core * @constructor * @param {View[]} an array of view definitions */ @@ -145,6 +146,7 @@ define( * @param {DomainObject} domainObject the domain object to view * @returns {View[]} all views which can be used to visualize * this domain object. + * @memberof platform/core.ViewProvider# */ getViews: getViews }; @@ -152,4 +154,4 @@ define( return ViewProvider; } -); \ No newline at end of file +); diff --git a/platform/entanglement/src/actions/CopyAction.js b/platform/entanglement/src/actions/CopyAction.js index aff8b94fb5..33fe826ace 100644 --- a/platform/entanglement/src/actions/CopyAction.js +++ b/platform/entanglement/src/actions/CopyAction.js @@ -31,6 +31,8 @@ define( * deep copy an object to another location of their choosing. * * @implements Action + * @constructor + * @memberof platform/entanglement */ function CopyAction(locationService, copyService, context) { @@ -90,3 +92,4 @@ define( return CopyAction; } ); + diff --git a/platform/entanglement/src/actions/LinkAction.js b/platform/entanglement/src/actions/LinkAction.js index c6b4be100f..42bc446758 100644 --- a/platform/entanglement/src/actions/LinkAction.js +++ b/platform/entanglement/src/actions/LinkAction.js @@ -30,6 +30,8 @@ define( * link an object to another location of their choosing. * * @implements Action + * @constructor + * @memberof platform/entanglement */ function LinkAction(locationService, linkService, context) { @@ -87,3 +89,4 @@ define( return LinkAction; } ); + diff --git a/platform/entanglement/src/actions/MoveAction.js b/platform/entanglement/src/actions/MoveAction.js index 63f1517c56..7a89279766 100644 --- a/platform/entanglement/src/actions/MoveAction.js +++ b/platform/entanglement/src/actions/MoveAction.js @@ -30,6 +30,8 @@ define( * move an object to another location of their choosing. * * @implements Action + * @constructor + * @memberof platform/entanglement */ function MoveAction(locationService, moveService, context) { @@ -88,3 +90,4 @@ define( return MoveAction; } ); + diff --git a/platform/entanglement/src/services/CopyService.js b/platform/entanglement/src/services/CopyService.js index 487568c475..2b6c4063f8 100644 --- a/platform/entanglement/src/services/CopyService.js +++ b/platform/entanglement/src/services/CopyService.js @@ -30,6 +30,8 @@ define( * CopyService provides an interface for deep copying objects from one * location to another. It also provides a method for determining if * an object can be copied to a specific location. + * @constructor + * @memberof platform/entanglement */ function CopyService($q, creationService, policyService) { @@ -46,6 +48,7 @@ define( * create the duplicate in. * @returns {Promise} A promise that is fulfilled when the * duplicate operation has completed. + * @memberof platform/entanglement.CopyService# */ function duplicateObject(domainObject, parent) { var model = JSON.parse(JSON.stringify(domainObject.getModel())); @@ -78,6 +81,7 @@ define( /** * Returns true if `object` can be copied into * `parentCandidate`'s composition. + * @memberof platform/entanglement.CopyService# */ validate: function (object, parentCandidate) { if (!parentCandidate || !parentCandidate.getId) { @@ -94,6 +98,7 @@ define( }, /** * Wrapper, @see {@link duplicateObject} for implementation. + * @memberof platform/entanglement.CopyService# */ perform: function (object, parentObject) { return duplicateObject(object, parentObject); @@ -104,3 +109,4 @@ define( return CopyService; } ); + diff --git a/platform/entanglement/src/services/LinkService.js b/platform/entanglement/src/services/LinkService.js index acecab3b8d..163e80e647 100644 --- a/platform/entanglement/src/services/LinkService.js +++ b/platform/entanglement/src/services/LinkService.js @@ -30,12 +30,15 @@ define( * LinkService provides an interface for linking objects to additional * locations. It also provides a method for determining if an object * can be copied to a specific location. + * @constructor + * @memberof platform/entanglement */ function LinkService(policyService) { return { /** * Returns `true` if `object` can be linked into * `parentCandidate`'s composition. + * @memberof platform/entanglement.LinkService# */ validate: function (object, parentCandidate) { if (!parentCandidate || !parentCandidate.getId) { @@ -58,6 +61,7 @@ define( * * @returns {Promise} A promise that is fulfilled when the * linking operation has completed. + * @memberof platform/entanglement.LinkService# */ perform: function (object, parentObject) { return parentObject.useCapability('mutation', function (model) { @@ -74,3 +78,4 @@ define( return LinkService; } ); + diff --git a/platform/entanglement/src/services/LocationService.js b/platform/entanglement/src/services/LocationService.js index 3e71011503..e4b54183b6 100644 --- a/platform/entanglement/src/services/LocationService.js +++ b/platform/entanglement/src/services/LocationService.js @@ -29,6 +29,8 @@ define( /** * The LocationService allows for easily prompting the user for a * location in the root tree. + * @constructor + * @memberof platform/entanglement */ function LocationService(dialogService) { return { @@ -43,6 +45,7 @@ define( * @param {domainObject} initialLocation - tree location to * display at start * @returns {Promise} promise for a domain object. + * @memberof platform/entanglement.LocationService# */ getLocationFromUser: function (title, label, validate, initialLocation) { var formStructure, @@ -81,3 +84,4 @@ define( return LocationService; } ); + diff --git a/platform/entanglement/src/services/MoveService.js b/platform/entanglement/src/services/MoveService.js index e91d381453..2fbe2d69bf 100644 --- a/platform/entanglement/src/services/MoveService.js +++ b/platform/entanglement/src/services/MoveService.js @@ -30,12 +30,15 @@ define( * MoveService provides an interface for moving objects from one * location to another. It also provides a method for determining if * an object can be copied to a specific location. + * @constructor + * @memberof platform/entanglement */ function MoveService(policyService, linkService) { return { /** * Returns `true` if `object` can be moved into * `parentCandidate`'s composition. + * @memberof platform/entanglement.MoveService# */ validate: function (object, parentCandidate) { var currentParent = object @@ -65,6 +68,7 @@ define( * * @returns {Promise} A promise that is fulfilled when the * move operation has completed. + * @memberof platform/entanglement.MoveService# */ perform: function (object, parentObject) { return linkService @@ -81,3 +85,4 @@ define( return MoveService; } ); + diff --git a/platform/execution/src/WorkerService.js b/platform/execution/src/WorkerService.js index b8f24ee614..616c268e60 100644 --- a/platform/execution/src/WorkerService.js +++ b/platform/execution/src/WorkerService.js @@ -28,6 +28,7 @@ define( /** * Handles the execution of WebWorkers. + * @memberof platform/execution * @constructor */ function WorkerService($window, workers) { @@ -55,6 +56,7 @@ define( * * @param {string} key symbolic identifier for the worker * @returns {Worker} the running Worker + * @memberof platform/execution.WorkerService# */ run: function (key) { var scriptUrl = workerUrls[key]; @@ -66,3 +68,4 @@ define( return WorkerService; } ); + diff --git a/platform/features/events/src/DomainColumn.js b/platform/features/events/src/DomainColumn.js index 95a6222553..c906b45624 100644 --- a/platform/features/events/src/DomainColumn.js +++ b/platform/features/events/src/DomainColumn.js @@ -33,6 +33,7 @@ define( * A column which will report telemetry domain values * (typically, timestamps.) Used by the ScrollingListController. * + * @memberof platform/features/events * @constructor * @param domainMetadata an object with the machine- and human- * readable names for this domain (in `key` and `name` @@ -45,6 +46,7 @@ define( /** * Get the title to display in this column's header. * @returns {string} the title to display + * @memberof platform/features/events.DomainColumn# */ getTitle: function () { return domainMetadata.name; @@ -53,6 +55,7 @@ define( * Get the text to display inside a row under this * column. * @returns {string} the text to display + * @memberof platform/features/events.DomainColumn# */ getValue: function (domainObject, data, index) { return telemetryFormatter.formatDomainValue( @@ -64,4 +67,4 @@ define( return DomainColumn; } -); \ No newline at end of file +); diff --git a/platform/features/events/src/EventListController.js b/platform/features/events/src/EventListController.js index 4b90c91b8e..c67e938776 100644 --- a/platform/features/events/src/EventListController.js +++ b/platform/features/events/src/EventListController.js @@ -36,6 +36,7 @@ define( /** * The EventListController is responsible for populating * the contents of the event list view. + * @memberof platform/features/events * @constructor */ function EventListController($scope, formatter) { @@ -131,3 +132,4 @@ define( return EventListController; } ); + diff --git a/platform/features/events/src/EventListPopulator.js b/platform/features/events/src/EventListPopulator.js index 3999fb1ebc..d4e7429d28 100644 --- a/platform/features/events/src/EventListPopulator.js +++ b/platform/features/events/src/EventListPopulator.js @@ -158,4 +158,4 @@ define( return EventListPopulator; } -); \ No newline at end of file +); diff --git a/platform/features/events/src/RangeColumn.js b/platform/features/events/src/RangeColumn.js index 2b11de43c7..56d9231a01 100644 --- a/platform/features/events/src/RangeColumn.js +++ b/platform/features/events/src/RangeColumn.js @@ -33,6 +33,7 @@ define( * A column which will report telemetry range values * (typically, measurements.) Used by the ScrollingListController. * + * @memberof platform/features/events * @constructor * @param rangeMetadata an object with the machine- and human- * readable names for this range (in `key` and `name` @@ -45,6 +46,7 @@ define( /** * Get the title to display in this column's header. * @returns {string} the title to display + * @memberof platform/features/events.RangeColumn# */ getTitle: function () { return rangeMetadata.name; @@ -53,6 +55,7 @@ define( * Get the text to display inside a row under this * column. * @returns {string} the text to display + * @memberof platform/features/events.RangeColumn# */ getValue: function (domainObject, data, index) { return telemetryFormatter.formatRangeValue( @@ -64,4 +67,4 @@ define( return RangeColumn; } -); \ No newline at end of file +); diff --git a/platform/features/events/src/directives/MCTDataTable.js b/platform/features/events/src/directives/MCTDataTable.js index c4cb9970e6..e830fbe885 100644 --- a/platform/features/events/src/directives/MCTDataTable.js +++ b/platform/features/events/src/directives/MCTDataTable.js @@ -71,4 +71,4 @@ define( return MCTDataTable; } -); \ No newline at end of file +); diff --git a/platform/features/events/src/policies/MessagesViewPolicy.js b/platform/features/events/src/policies/MessagesViewPolicy.js index 4426872b1e..1458b9d8eb 100644 --- a/platform/features/events/src/policies/MessagesViewPolicy.js +++ b/platform/features/events/src/policies/MessagesViewPolicy.js @@ -31,6 +31,7 @@ define( /** * Policy controlling when the Messages view should be avaliable. + * @memberof platform/features/events * @constructor */ function MessagesViewPolicy() { @@ -52,6 +53,7 @@ define( * @param {Action} action the action * @param domainObject the domain object which will be viewed * @returns {boolean} true if not disallowed + * @memberof platform/features/events.MessagesViewPolicy# */ allow: function (view, domainObject) { // This policy only applies for the Messages view @@ -71,4 +73,4 @@ define( return MessagesViewPolicy; } -); \ No newline at end of file +); diff --git a/platform/features/imagery/src/controllers/ImageryController.js b/platform/features/imagery/src/controllers/ImageryController.js index 72f72f39db..e3d1e3db2b 100644 --- a/platform/features/imagery/src/controllers/ImageryController.js +++ b/platform/features/imagery/src/controllers/ImageryController.js @@ -32,6 +32,8 @@ define( /** * Controller for the "Imagery" view of a domain object which * provides image telemetry. + * @constructor + * @memberof platform/features/imagery */ function ImageryController($scope, telemetryHandler) { var date = "", @@ -83,6 +85,7 @@ define( * Get the time portion (hours, minutes, seconds) of the * timestamp associated with the incoming image telemetry. * @returns {string} the time + * @memberof platform/features/imagery.ImageryController# */ getTime: function () { return time; @@ -91,6 +94,7 @@ define( * Get the date portion (month, year) of the * timestamp associated with the incoming image telemetry. * @returns {string} the date + * @memberof platform/features/imagery.ImageryController# */ getDate: function () { return date; @@ -100,6 +104,7 @@ define( * to the timestamp associated with the incoming image * telemetry. * @returns {string} the time + * @memberof platform/features/imagery.ImageryController# */ getZone: function () { return "UTC"; @@ -107,6 +112,7 @@ define( /** * Get the URL of the image telemetry to display. * @returns {string} URL for telemetry image + * @memberof platform/features/imagery.ImageryController# */ getImageUrl: function () { return imageUrl; @@ -116,6 +122,7 @@ define( * paused, false means not.) * @param {boolean} [state] the state to set * @returns {boolean} the current state + * @memberof platform/features/imagery.ImageryController# */ paused: function (state) { if (arguments.length > 0 && state !== paused) { @@ -131,3 +138,4 @@ define( return ImageryController; } ); + diff --git a/platform/features/imagery/src/directives/MCTBackgroundImage.js b/platform/features/imagery/src/directives/MCTBackgroundImage.js index 3218910db5..9100dce4b8 100644 --- a/platform/features/imagery/src/directives/MCTBackgroundImage.js +++ b/platform/features/imagery/src/directives/MCTBackgroundImage.js @@ -34,6 +34,8 @@ define( * * If `src` is falsy, no image will be displayed (immediately.) * + * @constructor + * @memberof platform/features/imagery */ function MCTBackgroundImage($document) { function link(scope, element, attrs) { @@ -87,3 +89,4 @@ define( return MCTBackgroundImage; } ); + diff --git a/platform/features/imagery/src/policies/ImageryViewPolicy.js b/platform/features/imagery/src/policies/ImageryViewPolicy.js index 40b74d96df..127174d50a 100644 --- a/platform/features/imagery/src/policies/ImageryViewPolicy.js +++ b/platform/features/imagery/src/policies/ImageryViewPolicy.js @@ -29,6 +29,8 @@ define( * Policy preventing the Imagery view from being made available for * domain objects which do not have associated image telemetry. * @implements {Policy} + * @constructor + * @memberof platform/features/imagery */ function ImageryViewPolicy() { function hasImageTelemetry(domainObject) { @@ -57,3 +59,4 @@ define( return ImageryViewPolicy; } ); + diff --git a/platform/features/layout/src/FixedController.js b/platform/features/layout/src/FixedController.js index 42e6b6dbce..4458e988ea 100644 --- a/platform/features/layout/src/FixedController.js +++ b/platform/features/layout/src/FixedController.js @@ -34,6 +34,7 @@ define( * Fixed Position view. It arranges frames according to saved * configuration and provides methods for updating these based on * mouse movement. + * @memberof platform/features/layout * @constructor * @param {Scope} $scope the controller's Angular scope */ @@ -290,6 +291,7 @@ define( * Get the size of the grid, in pixels. The returned array * is in the form `[x, y]`. * @returns {number[]} the grid size + * @memberof platform/features/layout.FixedController# */ getGridSize: function () { return gridSize; @@ -298,6 +300,7 @@ define( * Get an array of elements in this panel; these are * decorated proxies for both selection and display. * @returns {Array} elements in this panel + * @memberof platform/features/layout.FixedController# */ getElements: function () { return elementProxies; @@ -306,6 +309,7 @@ define( * Check if the element is currently selected, or (if no * argument is supplied) get the currently selected element. * @returns {boolean} true if selected + * @memberof platform/features/layout.FixedController# */ selected: function (element) { return selection && ((arguments.length > 0) ? @@ -314,10 +318,12 @@ define( /** * Set the active user selection in this view. * @param element the element to select + * @memberof platform/features/layout.FixedController# */ select: select, /** * Clear the current user selection. + * @memberof platform/features/layout.FixedController# */ clearSelection: function () { if (selection) { @@ -329,6 +335,7 @@ define( /** * Get drag handles. * @returns {Array} drag handles for the current selection + * @memberof platform/features/layout.FixedController# */ handles: function () { return handles; @@ -336,6 +343,7 @@ define( /** * Get the handle to handle dragging to reposition an element. * @returns {FixedDragHandle} the drag handle + * @memberof platform/features/layout.FixedController# */ moveHandle: function () { return moveHandle; @@ -347,3 +355,4 @@ define( return FixedController; } ); + diff --git a/platform/features/layout/src/FixedDragHandle.js b/platform/features/layout/src/FixedDragHandle.js index 7c26e8320b..a72bbbadb6 100644 --- a/platform/features/layout/src/FixedDragHandle.js +++ b/platform/features/layout/src/FixedDragHandle.js @@ -33,6 +33,7 @@ define( /** * Template-displayable drag handle for an element in fixed * position mode. + * @memberof platform/features/layout * @constructor */ function FixedDragHandle(elementHandle, gridSize, update, commit) { @@ -91,22 +92,26 @@ define( /** * Get a CSS style to position this drag handle. * @returns CSS style object (for `ng-style`) + * @memberof platform/features/layout.FixedDragHandle# */ style: getStyle, /** * Start a drag gesture. This should be called when a drag * begins to track initial state. + * @memberof platform/features/layout.FixedDragHandle# */ startDrag: startDrag, /** * Continue a drag gesture; update x/y positions. * @param {number[]} delta x/y pixel difference since drag * started + * @memberof platform/features/layout.FixedDragHandle# */ continueDrag: continueDrag, /** * End a drag gesture. This should be callled when a drag * concludes to trigger commit of changes. + * @memberof platform/features/layout.FixedDragHandle# */ endDrag: endDrag }; @@ -114,4 +119,4 @@ define( return FixedDragHandle; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/FixedProxy.js b/platform/features/layout/src/FixedProxy.js index f78b8711e9..b84985f9d8 100644 --- a/platform/features/layout/src/FixedProxy.js +++ b/platform/features/layout/src/FixedProxy.js @@ -28,6 +28,7 @@ define( /** * Proxy for configuring a fixed position view via the toolbar. + * @memberof platform/features/layout * @constructor * @param {Function} addElementCallback callback to invoke when * elements are created @@ -41,6 +42,7 @@ define( return { /** * Add a new visual element to this view. + * @memberof platform/features/layout.FixedProxy# */ add: function (type) { // Place a configured element into the view configuration @@ -64,4 +66,4 @@ define( return FixedProxy; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/LayoutCompositionPolicy.js b/platform/features/layout/src/LayoutCompositionPolicy.js index 2c46484498..8f9b6ccf31 100644 --- a/platform/features/layout/src/LayoutCompositionPolicy.js +++ b/platform/features/layout/src/LayoutCompositionPolicy.js @@ -29,12 +29,15 @@ define( /** * Defines composition policy for Display Layout objects. * They cannot contain folders. + * @constructor + * @memberof platform/features/layout */ function LayoutCompositionPolicy() { return { /** * Is the type identified by the candidate allowed to * contain the type described by the context? + * @memberof platform/features/layout.LayoutCompositionPolicy# */ allow: function (candidate, context) { var isFolderInLayout = @@ -50,3 +53,4 @@ define( return LayoutCompositionPolicy; } ); + diff --git a/platform/features/layout/src/LayoutController.js b/platform/features/layout/src/LayoutController.js index 643ed952a3..359646b5b7 100644 --- a/platform/features/layout/src/LayoutController.js +++ b/platform/features/layout/src/LayoutController.js @@ -35,6 +35,7 @@ define( * Layout view. It arranges frames according to saved configuration * and provides methods for updating these based on mouse * movement. + * @memberof platform/features/layout * @constructor * @param {Scope} $scope the controller's Angular scope */ @@ -178,6 +179,7 @@ define( * @param {string} id the object identifier * @returns {Object.} an object with * appropriate left, width, etc fields for positioning + * @memberof platform/features/layout.LayoutController# */ getFrameStyle: function (id) { // Called in a loop, so just look up; the "positions" @@ -203,6 +205,7 @@ define( * in the frame being manipulated * @param {number[]} posFactor the position factor * @param {number[]} dimFactor the dimensions factor + * @memberof platform/features/layout.LayoutController# */ startDrag: function (id, posFactor, dimFactor) { activeDragId = id; @@ -218,6 +221,7 @@ define( * @param {number[]} delta the offset, in pixels, * of the current pointer position, relative * to its position when the drag started + * @memberof platform/features/layout.LayoutController# */ continueDrag: function (delta) { if (activeDrag) { @@ -229,6 +233,7 @@ define( /** * End the active drag gesture. This will update the * view configuration. + * @memberof platform/features/layout.LayoutController# */ endDrag: function () { // Write to configuration; this is watched and @@ -254,3 +259,4 @@ define( return LayoutController; } ); + diff --git a/platform/features/layout/src/LayoutDrag.js b/platform/features/layout/src/LayoutDrag.js index cb3b4808be..45f1ad9856 100644 --- a/platform/features/layout/src/LayoutDrag.js +++ b/platform/features/layout/src/LayoutDrag.js @@ -50,6 +50,8 @@ define( * @param {number[]} posFactor the position factor * @param {number[]} dimFactor the dimensions factor * @param {number[]} the size of each grid element, in pixels + * @constructor + * @memberof platform/features/layout */ function LayoutDrag(rawPosition, posFactor, dimFactor, gridSize) { // Convert a delta from pixel coordinates to grid coordinates, @@ -103,6 +105,7 @@ define( * according to the factors supplied in the constructor. * @param {number[]} pixelDelta the offset from the * original position, in pixels + * @memberof platform/features/layout.LayoutDrag# */ getAdjustedPosition: getAdjustedPosition }; @@ -111,4 +114,4 @@ define( return LayoutDrag; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/AccessorMutator.js b/platform/features/layout/src/elements/AccessorMutator.js index 8b96d9cca9..656c4abbcf 100644 --- a/platform/features/layout/src/elements/AccessorMutator.js +++ b/platform/features/layout/src/elements/AccessorMutator.js @@ -38,6 +38,7 @@ define( * in certain ranges; specifically, to keep x/y positions * non-negative in a fixed position view. * + * @memberof platform/features/layout * @constructor * @param {Object} object the object to get/set values upon * @param {string} key the property to get/set @@ -56,4 +57,4 @@ define( return AccessorMutator; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/BoxProxy.js b/platform/features/layout/src/elements/BoxProxy.js index 724c9e21cd..46ec351b1f 100644 --- a/platform/features/layout/src/elements/BoxProxy.js +++ b/platform/features/layout/src/elements/BoxProxy.js @@ -34,6 +34,7 @@ define( * Note that arguments here are meant to match those expected * by `Array.prototype.map` * + * @memberof platform/features/layout * @constructor * @param element the fixed position element, as stored in its * configuration @@ -50,6 +51,7 @@ define( * @memberof BoxProxy * @param {string} fill the new fill color * @returns {string} the fill color + * @memberof platform/features/layout.BoxProxy# */ proxy.fill = new AccessorMutator(element, 'fill'); @@ -58,4 +60,4 @@ define( return BoxProxy; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/ElementFactory.js b/platform/features/layout/src/elements/ElementFactory.js index 5bcafd8529..01cc4be729 100644 --- a/platform/features/layout/src/elements/ElementFactory.js +++ b/platform/features/layout/src/elements/ElementFactory.js @@ -85,6 +85,7 @@ define( * The ElementFactory creates new instances of elements for the * fixed position view, prompting for user input where necessary. * @param {DialogService} dialogService service to request user input + * @memberof platform/features/layout * @constructor */ function ElementFactory(dialogService) { @@ -94,6 +95,7 @@ define( * @param {string} type the type of element to create * @returns {Promise|object} the created element, or a promise * for that element + * @memberof platform/features/layout.ElementFactory# */ createElement: function (type) { var initialState = INITIAL_STATES[type] || {}; @@ -112,4 +114,4 @@ define( return ElementFactory; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/ElementProxies.js b/platform/features/layout/src/elements/ElementProxies.js index 02a69f3888..1443363883 100644 --- a/platform/features/layout/src/elements/ElementProxies.js +++ b/platform/features/layout/src/elements/ElementProxies.js @@ -34,4 +34,4 @@ define( "fixed.text": TextProxy }; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/ElementProxy.js b/platform/features/layout/src/elements/ElementProxy.js index 4591480517..1261104a9e 100644 --- a/platform/features/layout/src/elements/ElementProxy.js +++ b/platform/features/layout/src/elements/ElementProxy.js @@ -48,6 +48,7 @@ define( * Note that arguments here are meant to match those expected * by `Array.prototype.map` * + * @memberof platform/features/layout * @constructor * @param element the fixed position element, as stored in its * configuration @@ -60,6 +61,7 @@ define( return { /** * The element as stored in the view configuration. + * @memberof platform/features/layout.ElementProxy# */ element: element, /** @@ -67,6 +69,7 @@ define( * Units are in fixed position grid space. * @param {number} [x] the new x position (if setting) * @returns {number} the x position + * @memberof platform/features/layout.ElementProxy# */ x: new AccessorMutator(element, 'x', clamp), /** @@ -74,12 +77,14 @@ define( * Units are in fixed position grid space. * @param {number} [y] the new y position (if setting) * @returns {number} the y position + * @memberof platform/features/layout.ElementProxy# */ y: new AccessorMutator(element, 'y', clamp), /** * Get and/or set the stroke color of this element. * @param {string} [stroke] the new stroke color (if setting) * @returns {string} the stroke color + * @memberof platform/features/layout.ElementProxy# */ stroke: new AccessorMutator(element, 'stroke'), /** @@ -87,6 +92,7 @@ define( * Units are in fixed position grid space. * @param {number} [w] the new width (if setting) * @returns {number} the width + * @memberof platform/features/layout.ElementProxy# */ width: new AccessorMutator(element, 'width'), /** @@ -94,12 +100,14 @@ define( * Units are in fixed position grid space. * @param {number} [h] the new height (if setting) * @returns {number} the height + * @memberof platform/features/layout.ElementProxy# */ height: new AccessorMutator(element, 'height'), /** * Change the display order of this element. * @param {string} o where to move this element; * one of "top", "up", "down", or "bottom" + * @memberof platform/features/layout.ElementProxy# */ order: function (o) { var delta = ORDERS[o] || 0, @@ -120,6 +128,7 @@ define( }, /** * Remove this element from the fixed position view. + * @memberof platform/features/layout.ElementProxy# */ remove: function () { if (elements[index] === element) { @@ -129,6 +138,7 @@ define( /** * Get handles to control specific features of this element, * e.g. corner size. + * @memberof platform/features/layout.ElementProxy# */ handles: function () { return handles; @@ -138,4 +148,4 @@ define( return ElementProxy; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/ImageProxy.js b/platform/features/layout/src/elements/ImageProxy.js index bafe1b9b00..28d84a3fa4 100644 --- a/platform/features/layout/src/elements/ImageProxy.js +++ b/platform/features/layout/src/elements/ImageProxy.js @@ -32,6 +32,7 @@ define( * Note that arguments here are meant to match those expected * by `Array.prototype.map` * + * @memberof platform/features/layout * @constructor * @param element the fixed position element, as stored in its * configuration @@ -45,6 +46,7 @@ define( * Get and/or set the displayed text of this element. * @param {string} [text] the new text (if setting) * @returns {string} the text + * @memberof platform/features/layout.ImageProxy# */ proxy.url = new AccessorMutator(element, 'url'); @@ -53,4 +55,4 @@ define( return ImageProxy; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/LineHandle.js b/platform/features/layout/src/elements/LineHandle.js index 6fd4ed84aa..f4178f107b 100644 --- a/platform/features/layout/src/elements/LineHandle.js +++ b/platform/features/layout/src/elements/LineHandle.js @@ -30,6 +30,7 @@ define( * This is used to support drag handles for line elements * in a fixed position view. Field names for opposite ends * are provided to avoid zero-length lines. + * @memberof platform/features/layout * @constructor * @param element the line element * @param {string} xProperty field which stores x position @@ -43,6 +44,7 @@ define( * Get/set the x position of the lower-right corner * of the handle-controlled element, changing size * as necessary. + * @memberof platform/features/layout.LineHandle# */ x: function (value) { if (arguments.length > 0) { @@ -60,6 +62,7 @@ define( * Get/set the y position of the lower-right corner * of the handle-controlled element, changing size * as necessary. + * @memberof platform/features/layout.LineHandle# */ y: function (value) { if (arguments.length > 0) { @@ -79,4 +82,4 @@ define( return LineHandle; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/LineProxy.js b/platform/features/layout/src/elements/LineProxy.js index 92ca96bf76..0051b1d3c1 100644 --- a/platform/features/layout/src/elements/LineProxy.js +++ b/platform/features/layout/src/elements/LineProxy.js @@ -29,6 +29,7 @@ define( /** * Selection/diplay proxy for line elements of a fixed position * view. + * @memberof platform/features/layout * @constructor * @param element the fixed position element, as stored in its * configuration @@ -46,6 +47,7 @@ define( * Get the top-left x coordinate, in grid space, of * this line's bounding box. * @returns {number} the x coordinate + * @memberof platform/features/layout.LineProxy# */ proxy.x = function (v) { var x = Math.min(element.x, element.x2), @@ -61,6 +63,7 @@ define( * Get the top-left y coordinate, in grid space, of * this line's bounding box. * @returns {number} the y coordinate + * @memberof platform/features/layout.LineProxy# */ proxy.y = function (v) { var y = Math.min(element.y, element.y2), @@ -76,6 +79,7 @@ define( * Get the width, in grid space, of * this line's bounding box. * @returns {number} the width + * @memberof platform/features/layout.LineProxy# */ proxy.width = function () { return Math.max(Math.abs(element.x - element.x2), 1); @@ -85,6 +89,7 @@ define( * Get the height, in grid space, of * this line's bounding box. * @returns {number} the height + * @memberof platform/features/layout.LineProxy# */ proxy.height = function () { return Math.max(Math.abs(element.y - element.y2), 1); @@ -95,6 +100,7 @@ define( * the top-left corner, of the first point in this line * segment. * @returns {number} the x position of the first point + * @memberof platform/features/layout.LineProxy# */ proxy.x1 = function () { return element.x - proxy.x(); @@ -105,6 +111,7 @@ define( * the top-left corner, of the first point in this line * segment. * @returns {number} the y position of the first point + * @memberof platform/features/layout.LineProxy# */ proxy.y1 = function () { return element.y - proxy.y(); @@ -115,6 +122,7 @@ define( * the top-left corner, of the second point in this line * segment. * @returns {number} the x position of the second point + * @memberof platform/features/layout.LineProxy# */ proxy.x2 = function () { return element.x2 - proxy.x(); @@ -125,6 +133,7 @@ define( * the top-left corner, of the second point in this line * segment. * @returns {number} the y position of the second point + * @memberof platform/features/layout.LineProxy# */ proxy.y2 = function () { return element.y2 - proxy.y(); @@ -134,6 +143,7 @@ define( * Get element handles for changing the position of end * points of this line. * @returns {LineHandle[]} line handles for both end points + * @memberof platform/features/layout.LineProxy# */ proxy.handles = function () { return handles; @@ -144,4 +154,4 @@ define( return LineProxy; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/ResizeHandle.js b/platform/features/layout/src/elements/ResizeHandle.js index e87ef91059..c8fe59682c 100644 --- a/platform/features/layout/src/elements/ResizeHandle.js +++ b/platform/features/layout/src/elements/ResizeHandle.js @@ -29,6 +29,7 @@ define( * Handle for changing width/height properties of an element. * This is used to support drag handles for different * element types in a fixed position view. + * @memberof platform/features/layout * @constructor */ function ResizeHandle(element, minWidth, minHeight) { @@ -41,6 +42,7 @@ define( * Get/set the x position of the lower-right corner * of the handle-controlled element, changing size * as necessary. + * @memberof platform/features/layout.ResizeHandle# */ x: function (value) { if (arguments.length > 0) { @@ -55,6 +57,7 @@ define( * Get/set the y position of the lower-right corner * of the handle-controlled element, changing size * as necessary. + * @memberof platform/features/layout.ResizeHandle# */ y: function (value) { if (arguments.length > 0) { @@ -71,4 +74,4 @@ define( return ResizeHandle; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/TelemetryProxy.js b/platform/features/layout/src/elements/TelemetryProxy.js index 7397c0e81a..058048eca8 100644 --- a/platform/features/layout/src/elements/TelemetryProxy.js +++ b/platform/features/layout/src/elements/TelemetryProxy.js @@ -35,6 +35,7 @@ define( * Note that arguments here are meant to match those expected * by `Array.prototype.map` * + * @memberof platform/features/layout * @constructor * @param element the fixed position element, as stored in its * configuration @@ -70,4 +71,4 @@ define( return TelemetryProxy; } -); \ No newline at end of file +); diff --git a/platform/features/layout/src/elements/TextProxy.js b/platform/features/layout/src/elements/TextProxy.js index 5e7ce4870d..d3ff832833 100644 --- a/platform/features/layout/src/elements/TextProxy.js +++ b/platform/features/layout/src/elements/TextProxy.js @@ -32,6 +32,7 @@ define( * Note that arguments here are meant to match those expected * by `Array.prototype.map` * + * @memberof platform/features/layout * @constructor * @param element the fixed position element, as stored in its * configuration @@ -45,6 +46,7 @@ define( * Get and/or set the text color of this element. * @param {string} [color] the new text color (if setting) * @returns {string} the text color + * @memberof platform/features/layout.TextProxy# */ proxy.color = new AccessorMutator(element, 'color'); @@ -52,6 +54,7 @@ define( * Get and/or set the displayed text of this element. * @param {string} [text] the new text (if setting) * @returns {string} the text + * @memberof platform/features/layout.TextProxy# */ proxy.text = new AccessorMutator(element, 'text'); @@ -60,4 +63,4 @@ define( return TextProxy; } -); \ No newline at end of file +); diff --git a/platform/features/pages/src/EmbeddedPageController.js b/platform/features/pages/src/EmbeddedPageController.js index a0e08e6549..843492866f 100644 --- a/platform/features/pages/src/EmbeddedPageController.js +++ b/platform/features/pages/src/EmbeddedPageController.js @@ -29,11 +29,14 @@ define( /** * Controller for embedded web pages; serves simply as a * wrapper for `$sce` to mark pages as trusted. + * @constructor + * @memberof platform/features/pages */ function EmbeddedPageController($sce) { return { /** * Alias of `$sce.trustAsResourceUrl`. + * @memberof platform/features/pages.EmbeddedPageController# */ trust: function (url) { return $sce.trustAsResourceUrl(url); @@ -44,4 +47,4 @@ define( return EmbeddedPageController; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/Canvas2DChart.js b/platform/features/plot/src/Canvas2DChart.js index 7587159986..9fcee46123 100644 --- a/platform/features/plot/src/Canvas2DChart.js +++ b/platform/features/plot/src/Canvas2DChart.js @@ -29,6 +29,7 @@ define( /** * Create a new chart which uses Canvas's 2D API for rendering. * + * @memberof platform/features/plot * @constructor * @param {CanvasElement} canvas the canvas object to render upon * @throws {Error} an error is thrown if Canvas's 2D API is unavailable. @@ -66,6 +67,7 @@ define( return { /** * Clear the chart. + * @memberof platform/features/plot.Canvas2DChart# */ clear: function () { width = canvas.width; @@ -78,6 +80,7 @@ define( * vertical dimensions of the chart * @param {number[]} origin the horizontal/vertical * origin of the chart + * @memberof platform/features/plot.Canvas2DChart# */ setDimensions: function (newDimensions, newOrigin) { dimensions = newDimensions; @@ -92,6 +95,7 @@ define( * the line, as an RGBA color where each element * is in the range of 0.0-1.0 * @param {number} points the number of points to draw + * @memberof platform/features/plot.Canvas2DChart# */ drawLine: function (buf, color, points) { var i; @@ -123,6 +127,7 @@ define( * @param {number[]} color the color to use when drawing * the rectangle, as an RGBA color where each element * is in the range of 0.0-1.0 + * @memberof platform/features/plot.Canvas2DChart# */ drawSquare: function (min, max, color) { var x1 = x(min[0]), @@ -138,4 +143,4 @@ define( return Canvas2DChart; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/GLChart.js b/platform/features/plot/src/GLChart.js index a5e52b6f4d..a390cf1153 100644 --- a/platform/features/plot/src/GLChart.js +++ b/platform/features/plot/src/GLChart.js @@ -49,6 +49,7 @@ define( /** * Create a new chart which uses WebGL for rendering. * + * @memberof platform/features/plot * @constructor * @param {CanvasElement} canvas the canvas object to render upon * @throws {Error} an error is thrown if WebGL is unavailable. @@ -115,6 +116,7 @@ define( return { /** * Clear the chart. + * @memberof platform/features/plot.GLChart# */ clear: function () { // Set the viewport size; note that we use the width/height @@ -134,6 +136,7 @@ define( * vertical dimensions of the chart * @param {number[]} origin the horizontal/vertical * origin of the chart + * @memberof platform/features/plot.GLChart# */ setDimensions: function (dimensions, origin) { if (dimensions && dimensions.length > 0 && @@ -151,6 +154,7 @@ define( * the line, as an RGBA color where each element * is in the range of 0.0-1.0 * @param {number} points the number of points to draw + * @memberof platform/features/plot.GLChart# */ drawLine: function (buf, color, points) { doDraw(gl.LINE_STRIP, buf, color, points); @@ -163,6 +167,7 @@ define( * @param {number[]} color the color to use when drawing * the rectangle, as an RGBA color where each element * is in the range of 0.0-1.0 + * @memberof platform/features/plot.GLChart# */ drawSquare: function (min, max, color) { doDraw(gl.TRIANGLE_FAN, new Float32Array( @@ -173,4 +178,4 @@ define( } return GLChart; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/MCTChart.js b/platform/features/plot/src/MCTChart.js index 2ca51b2309..951ca3532b 100644 --- a/platform/features/plot/src/MCTChart.js +++ b/platform/features/plot/src/MCTChart.js @@ -61,6 +61,7 @@ define( * * `color`: The color of the box, as a four-element RGBA * array, where each element is in the range of 0.0-1.0 * + * @memberof platform/features/plot * @constructor */ function MCTChart($interval, $log) { @@ -208,3 +209,4 @@ define( return MCTChart; } ); + diff --git a/platform/features/plot/src/PlotController.js b/platform/features/plot/src/PlotController.js index da1a7a88ab..3c944f362b 100644 --- a/platform/features/plot/src/PlotController.js +++ b/platform/features/plot/src/PlotController.js @@ -50,6 +50,7 @@ define( * * Handling user interactions. * * Deciding what needs to be drawn in the chart area. * + * @memberof platform/features/plot * @constructor */ function PlotController( @@ -190,6 +191,7 @@ define( * for plotting the trace at the specified index. * @param {number} index the index of the trace * @returns {string} the color, in #RRGGBB form + * @memberof platform/features/plot.PlotController# */ getColor: function (index) { return PlotPalette.getStringColor(index); @@ -199,6 +201,7 @@ define( * of its default state (to determine whether back/unzoom * controls should be shown) * @returns {boolean} true if not in default state + * @memberof platform/features/plot.PlotController# */ isZoomed: function () { return modeOptions.getModeHandler().isZoomed(); @@ -206,12 +209,14 @@ define( /** * Undo the most recent pan/zoom change and restore * the prior state. + * @memberof platform/features/plot.PlotController# */ stepBackPanZoom: function () { return modeOptions.getModeHandler().stepBackPanZoom(); }, /** * Undo all pan/zoom changes and restore the initial state. + * @memberof platform/features/plot.PlotController# */ unzoom: function () { return modeOptions.getModeHandler().unzoom(); @@ -219,6 +224,7 @@ define( /** * Get the mode options (Stacked/Overlaid) that are applicable * for this plot. + * @memberof platform/features/plot.PlotController# */ getModeOptions: function () { return modeOptions.getModeOptions(); @@ -226,6 +232,7 @@ define( /** * Get the current mode that is applicable to this plot. This * will include key, name, and glyph fields. + * @memberof platform/features/plot.PlotController# */ getMode: function () { return modeOptions.getMode(); @@ -234,6 +241,7 @@ define( * Set the mode which should be active in this plot. * @param mode one of the mode options returned from * getModeOptions() + * @memberof platform/features/plot.PlotController# */ setMode: function (mode) { modeOptions.setMode(mode); @@ -243,6 +251,7 @@ define( * Get all individual plots contained within this Plot view. * (Multiple may be contained when in Stacked mode). * @returns {SubPlot[]} all subplots in this Plot view + * @memberof platform/features/plot.PlotController# */ getSubPlots: function () { return modeOptions.getModeHandler().getSubPlots(); @@ -251,6 +260,7 @@ define( * Get the CSS class to apply to the legend for this domain * object; this will reflect limit state. * @returns {string} the CSS class + * @memberof platform/features/plot.PlotController# */ getLegendClass: function (telemetryObject) { return limitTracker && @@ -258,10 +268,12 @@ define( }, /** * Explicitly update all plots. + * @memberof platform/features/plot.PlotController# */ update: update, /** * Check if a request is pending (to show the wait spinner) + * @memberof platform/features/plot.PlotController# */ isRequestPending: function () { // Placeholder; this should reflect request state @@ -274,3 +286,4 @@ define( return PlotController; } ); + diff --git a/platform/features/plot/src/SubPlot.js b/platform/features/plot/src/SubPlot.js index 7c74751b27..9cd8b829cf 100644 --- a/platform/features/plot/src/SubPlot.js +++ b/platform/features/plot/src/SubPlot.js @@ -36,6 +36,7 @@ define( * A SubPlot is an individual plot within a Plot View (which * may contain multiple plots, specifically when in Stacked * plot mode.) + * @memberof platform/features/plot * @constructor * @param {DomainObject[]} telemetryObjects the domain objects * which will be plotted in this sub-plot @@ -214,6 +215,7 @@ define( * represented in this sub-plot. * @returns {DomainObject[]} the domain objects which * will have data plotted in this sub-plot + * @memberof platform/features/plot.SubPlot# */ getTelemetryObjects: function () { return telemetryObjects; @@ -223,6 +225,7 @@ define( * template for this sub-plot's domain axis, as prepared * by the PlotTickGenerator. * @returns {Array} tick marks for the domain axis + * @memberof platform/features/plot.SubPlot# */ getDomainTicks: function () { return domainTicks; @@ -232,6 +235,7 @@ define( * template for this sub-plot's range axis, as prepared * by the PlotTickGenerator. * @returns {Array} tick marks for the range axis + * @memberof platform/features/plot.SubPlot# */ getRangeTicks: function () { return rangeTicks; @@ -243,6 +247,7 @@ define( * attribute, and should have the same internal format * expected by that directive. * @return {object} the drawing object + * @memberof platform/features/plot.SubPlot# */ getDrawingObject: function () { return draw; @@ -252,6 +257,7 @@ define( * current mouse position. * @returns {string[]} the displayable domain and range * coordinates over which the mouse is hovered + * @memberof platform/features/plot.SubPlot# */ getHoverCoordinates: function () { return hoverCoordinates; @@ -259,6 +265,7 @@ define( /** * Handle mouse movement over the chart area. * @param $event the mouse event + * @memberof platform/features/plot.SubPlot# */ hover: function ($event) { isHovering = true; @@ -277,6 +284,7 @@ define( /** * Continue a previously-start pan or zoom gesture. * @param $event the mouse event + * @memberof platform/features/plot.SubPlot# */ continueDrag: function ($event) { mousePosition = toMousePosition($event); @@ -292,6 +300,7 @@ define( /** * Initiate a marquee zoom action. * @param $event the mouse event + * @memberof platform/features/plot.SubPlot# */ startDrag: function ($event) { subPlotBounds = $event.target.getBoundingClientRect(); @@ -318,6 +327,7 @@ define( /** * Complete a marquee zoom action. * @param $event the mouse event + * @memberof platform/features/plot.SubPlot# */ endDrag: function ($event) { mousePosition = toMousePosition($event); @@ -338,6 +348,7 @@ define( /** * Update the drawing bounds, marquee box, and * tick marks for this subplot. + * @memberof platform/features/plot.SubPlot# */ update: function () { updateDrawingBounds(); @@ -355,6 +366,7 @@ define( * the value of this to position that marquee box * correctly. * @param {number} value the domain offset + * @memberof platform/features/plot.SubPlot# */ setDomainOffset: function (value) { domainOffset = value; @@ -365,6 +377,7 @@ define( * an argument, set that state. * @param {boolean} [state] the new hovering state * @returns {boolean} the hovering state + * @memberof platform/features/plot.SubPlot# */ isHovering: function (state) { if (state !== undefined) { @@ -379,3 +392,4 @@ define( } ); + diff --git a/platform/features/plot/src/SubPlotFactory.js b/platform/features/plot/src/SubPlotFactory.js index c883a488c2..33eb8fff65 100644 --- a/platform/features/plot/src/SubPlotFactory.js +++ b/platform/features/plot/src/SubPlotFactory.js @@ -31,6 +31,7 @@ define( * in a reference to the telemetryFormatter, which will be * used to represent telemetry values (timestamps or data * values) as human-readable strings. + * @memberof platform/features/plot * @constructor */ function SubPlotFactory(telemetryFormatter) { @@ -44,6 +45,7 @@ define( * @returns {SubPlot} the instantiated sub-plot * @method * @memberof SubPlotFactory + * @memberof platform/features/plot.SubPlotFactory# */ createSubPlot: function (telemetryObjects, panZoomStack) { return new SubPlot( @@ -58,4 +60,4 @@ define( return SubPlotFactory; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotAxis.js b/platform/features/plot/src/elements/PlotAxis.js index a523a7e352..2066b9c1bd 100644 --- a/platform/features/plot/src/elements/PlotAxis.js +++ b/platform/features/plot/src/elements/PlotAxis.js @@ -31,6 +31,7 @@ define( * for the domain or range axis, sufficient to populate * selectors. * + * @memberof platform/features/plot * @constructor * @param {string} axisType the field in metadatas to * look at for axis options; usually one of @@ -70,12 +71,14 @@ define( * an array of objects, where each object contains a * "key" field and a "name" field (for machine- and * human-readable names respectively) + * @memberof platform/features/plot.PlotAxis# */ options: options, /** * The currently chosen option for this axis. An * initial value is provided; this will be updated * directly form the plot template. + * @memberof platform/features/plot.PlotAxis# */ active: options[0] || defaultValue }; @@ -84,4 +87,4 @@ define( return PlotAxis; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotLimitTracker.js b/platform/features/plot/src/elements/PlotLimitTracker.js index 518344a08e..9993ff2144 100644 --- a/platform/features/plot/src/elements/PlotLimitTracker.js +++ b/platform/features/plot/src/elements/PlotLimitTracker.js @@ -34,6 +34,7 @@ define( INITIAL_SIZE = 675; // 1/128 of MAX_POINTS /** + * @memberof platform/features/plot * @constructor * @param {TelemetryHandle} handle the handle to telemetry access * @param {string} range the key to use when looking up range values @@ -66,4 +67,4 @@ define( return PlotLimitTracker; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotLine.js b/platform/features/plot/src/elements/PlotLine.js index df20fffa4c..b9d2df3588 100644 --- a/platform/features/plot/src/elements/PlotLine.js +++ b/platform/features/plot/src/elements/PlotLine.js @@ -70,6 +70,8 @@ define( * Add a point to this plot line. * @param {number} domainValue the domain value * @param {number} rangeValue the range value + * @constructor + * @memberof platform/features/plot */ addPoint: function (domainValue, rangeValue) { var index; @@ -112,4 +114,4 @@ define( return PlotLine; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotLineBuffer.js b/platform/features/plot/src/elements/PlotLineBuffer.js index e51e6e8a61..5cf52ad49d 100644 --- a/platform/features/plot/src/elements/PlotLineBuffer.js +++ b/platform/features/plot/src/elements/PlotLineBuffer.js @@ -31,6 +31,7 @@ define( * @param {number} domainOffset number to subtract from domain values * @param {number} initialSize initial buffer size * @param {number} maxSize maximum buffer size + * @memberof platform/features/plot * @constructor */ function PlotLineBuffer(domainOffset, initialSize, maxSize) { @@ -104,6 +105,7 @@ define( /** * Get the WebGL-displayable buffer of points to plot. * @returns {Float32Array} displayable buffer for this line + * @memberof platform/features/plot.PlotLineBuffer# */ getBuffer: function () { return buffer; @@ -111,6 +113,7 @@ define( /** * Get the number of points stored in this buffer. * @returns {number} the number of points stored + * @memberof platform/features/plot.PlotLineBuffer# */ getLength: function () { return length; @@ -120,6 +123,7 @@ define( * buffer. Unlike range extrema, these will change as the * buffer gets trimmed. * @returns {number[]} min, max domain values + * @memberof platform/features/plot.PlotLineBuffer# */ getDomainExtrema: function () { // Since these are ordered in the buffer, assume @@ -134,6 +138,7 @@ define( * buffer. Note that these values may have been trimmed out at * some point. * @returns {number[]} min, max range values + * @memberof platform/features/plot.PlotLineBuffer# */ getRangeExtrema: function () { return rangeExtrema; @@ -146,6 +151,7 @@ define( * @param {number} count number of values to remove * @param {boolean} [fromEnd] true if the most recent * values should be removed + * @memberof platform/features/plot.PlotLineBuffer# */ trim: function (count, fromEnd) { // If we're removing values from the start... @@ -170,6 +176,7 @@ define( * series * @returns {boolean} true if insertion succeeded; otherwise * false + * @memberof platform/features/plot.PlotLineBuffer# */ insert: function (series, index) { var sz = series.getPointCount(), @@ -211,6 +218,7 @@ define( }, /** * Append a single data point. + * @memberof platform/features/plot.PlotLineBuffer# */ insertPoint: function (domainValue, rangeValue, index) { // Don't allow @@ -241,6 +249,7 @@ define( * occurs, this will return -1. * @param {number} timestamp timestamp to insert * @returns {number} the index for insertion (or -1) + * @memberof platform/features/plot.PlotLineBuffer# */ findInsertionIndex: function (timestamp) { var value = timestamp - domainOffset; @@ -259,3 +268,4 @@ define( return PlotLineBuffer; } ); + diff --git a/platform/features/plot/src/elements/PlotPalette.js b/platform/features/plot/src/elements/PlotPalette.js index 8e61fe2f6e..f003317fec 100644 --- a/platform/features/plot/src/elements/PlotPalette.js +++ b/platform/features/plot/src/elements/PlotPalette.js @@ -78,6 +78,7 @@ define( * by index, in various color formats. All PlotPalette methods are * static, so there is no need for a constructor call; using * this will simply return PlotPalette itself. + * @memberof platform/features/plot * @constructor */ function PlotPalette() { @@ -131,4 +132,4 @@ define( return PlotPalette; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotPanZoomStack.js b/platform/features/plot/src/elements/PlotPanZoomStack.js index 32f3efd27a..66e3593488 100644 --- a/platform/features/plot/src/elements/PlotPanZoomStack.js +++ b/platform/features/plot/src/elements/PlotPanZoomStack.js @@ -37,6 +37,7 @@ define( * along the domain axis, and the second element describes the same * along the range axis. * + * @memberof platform/features/plot * @constructor * @param {number[]} origin the plot's origin, initially * @param {number[]} dimensions the plot's dimensions, initially @@ -91,6 +92,7 @@ define( * panning or zooming relative to the base value has * been applied. * @returns {number} the depth of the stack + * @memberof platform/features/plot.PlotPanZoomStack# */ getDepth: getDepth, @@ -99,6 +101,7 @@ define( * become the active pan-zoom state. * @param {number[]} origin the new origin * @param {number[]} dimensions the new dimensions + * @memberof platform/features/plot.PlotPanZoomStack# */ pushPanZoom: pushPanZoom, @@ -109,6 +112,7 @@ define( * stack, this acts as a no-op (that is, the lowest * pan-zoom state on the stack cannot be popped, to ensure * that some pan-zoom state is always available.) + * @memberof platform/features/plot.PlotPanZoomStack# */ popPanZoom: popPanZoom, @@ -119,6 +123,7 @@ define( * interfering with the user's chosen zoom level. * @param {number[]} origin the base origin * @param {number[]} dimensions the base dimensions + * @memberof platform/features/plot.PlotPanZoomStack# */ setBasePanZoom: setBasePanZoom, @@ -126,6 +131,7 @@ define( * Clear the pan-zoom stack down to its bottom element; * in effect, pop all elements but the last, e.g. to remove * any temporary user modifications to pan-zoom state. + * @memberof platform/features/plot.PlotPanZoomStack# */ clearPanZoom: clearPanZoom, @@ -134,6 +140,7 @@ define( * of the stack), expressed as an object with "origin" and * "dimensions" fields. * @returns {object} the current pan-zoom state + * @memberof platform/features/plot.PlotPanZoomStack# */ getPanZoom: getPanZoom, @@ -141,6 +148,7 @@ define( * Get the current origin, as represented on the top of the * stack. * @returns {number[]} the current plot origin + * @memberof platform/features/plot.PlotPanZoomStack# */ getOrigin: getOrigin, @@ -148,6 +156,7 @@ define( * Get the current dimensions, as represented on the top of * the stack. * @returns {number[]} the current plot dimensions + * @memberof platform/features/plot.PlotPanZoomStack# */ getDimensions: getDimensions }; @@ -155,4 +164,4 @@ define( return PlotPanZoomStack; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotPanZoomStackGroup.js b/platform/features/plot/src/elements/PlotPanZoomStackGroup.js index 6280c42def..ccb3ae3579 100644 --- a/platform/features/plot/src/elements/PlotPanZoomStackGroup.js +++ b/platform/features/plot/src/elements/PlotPanZoomStackGroup.js @@ -32,6 +32,7 @@ define( * remain independent upon the range axis. This supports panning * and zooming in stacked-plot mode (and, importantly, * stepping back through those states.) + * @memberof platform/features/plot * @constructor * @param {number} count the number of stacks to include in this * group @@ -112,6 +113,7 @@ define( * stack, this acts as a no-op (that is, the lowest * pan-zoom state on the stack cannot be popped, to ensure * that some pan-zoom state is always available.) + * @memberof platform/features/plot.PlotPanZoomStackGroup# */ popPanZoom: popPanZoom, @@ -123,6 +125,7 @@ define( * interfering with the user's chosen pan/zoom states. * @param {number[]} origin the base origin * @param {number[]} dimensions the base dimensions + * @memberof platform/features/plot.PlotPanZoomStackGroup# */ setBasePanZoom: setBasePanZoom, @@ -131,6 +134,7 @@ define( * their bottom element; in effect, pop all elements * but the last, e.g. to remove any temporary user * modifications to pan-zoom state. + * @memberof platform/features/plot.PlotPanZoomStackGroup# */ clearPanZoom: clearPanZoom, /** @@ -140,6 +144,7 @@ define( * panning or zooming relative to the base value has * been applied. * @returns {number} the depth of the stacks in this group + * @memberof platform/features/plot.PlotPanZoomStackGroup# */ getDepth: function () { // All stacks are kept in sync, so look up depth @@ -160,6 +165,7 @@ define( * @param {number} index the index of the stack to get * @returns {PlotPanZoomStack} the pan-zoom stack in the * group identified by that index + * @memberof platform/features/plot.PlotPanZoomStackGroup# */ getPanZoomStack: function (index) { return decoratedStacks[index]; @@ -170,4 +176,4 @@ define( return PlotPanZoomStackGroup; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotPosition.js b/platform/features/plot/src/elements/PlotPosition.js index 462e0882fd..30220f56f6 100644 --- a/platform/features/plot/src/elements/PlotPosition.js +++ b/platform/features/plot/src/elements/PlotPosition.js @@ -36,6 +36,7 @@ define( * PlotPosition was instantiated. Care should be taken when retaining * PlotPosition objects across changes to the pan-zoom stack. * + * @memberof platform/features/plot * @constructor * @param {number} x the horizontal pixel position in the plot area * @param {number} y the vertical pixel position in the plot area @@ -68,6 +69,7 @@ define( /** * Get the domain value corresponding to this pixel position. * @returns {number} the domain value + * @memberof platform/features/plot.PlotPosition# */ getDomain: function () { return position[0]; @@ -75,6 +77,7 @@ define( /** * Get the range value corresponding to this pixel position. * @returns {number} the range value + * @memberof platform/features/plot.PlotPosition# */ getRange: function () { return position[1]; @@ -84,6 +87,7 @@ define( * pixel position. * @returns {number[]} an array containing the domain and * the range value, in that order + * @memberof platform/features/plot.PlotPosition# */ getPosition: function () { return position; @@ -94,4 +98,4 @@ define( return PlotPosition; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotPreparer.js b/platform/features/plot/src/elements/PlotPreparer.js index e301b693c0..87049c9198 100644 --- a/platform/features/plot/src/elements/PlotPreparer.js +++ b/platform/features/plot/src/elements/PlotPreparer.js @@ -36,6 +36,7 @@ define( * preparing them to be rendered. It creates a WebGL-plottable * Float32Array for each trace, and tracks the boundaries of the * data sets (since this is convenient to do during the same pass). + * @memberof platform/features/plot * @constructor * @param {Telemetry[]} datas telemetry data objects * @param {string} domain the key to use when looking up domain values @@ -92,6 +93,7 @@ define( * data sets. This is given as a two-element array where the * first element is domain, and second is range. * @returns {number[]} the dimensions which bound this data set + * @memberof platform/features/plot.PlotPreparer# */ getDimensions: function () { return [max[0] - min[0], max[1] - min[1]]; @@ -102,6 +104,7 @@ define( * first element is domain, and second is range. * The domain value here is not adjusted by the domain offset. * @returns {number[]} the origin of this data set's boundary + * @memberof platform/features/plot.PlotPreparer# */ getOrigin: function () { return min; @@ -112,6 +115,7 @@ define( * preparer, in order to minimize loss-of-precision due to * conversion to the 32-bit float format needed by WebGL. * @returns {number} the domain offset + * @memberof platform/features/plot.PlotPreparer# */ getDomainOffset: function () { return domainOffset; @@ -132,6 +136,7 @@ define( * cause aliasing artifacts (particularly for timestamps) * * @returns {Float32Array[]} the buffers for these traces + * @memberof platform/features/plot.PlotPreparer# */ getBuffers: function () { return buffers; @@ -142,4 +147,4 @@ define( return PlotPreparer; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotSeriesWindow.js b/platform/features/plot/src/elements/PlotSeriesWindow.js index 7cfb89601a..bff0710b34 100644 --- a/platform/features/plot/src/elements/PlotSeriesWindow.js +++ b/platform/features/plot/src/elements/PlotSeriesWindow.js @@ -28,6 +28,8 @@ define( /** * Provides a window on a telemetry data series, to support * insertion into a plot line. + * @constructor + * @memberof platform/features/plot */ function PlotSeriesWindow(series, domain, range, start, end) { return { @@ -65,4 +67,4 @@ define( return PlotSeriesWindow; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotTickGenerator.js b/platform/features/plot/src/elements/PlotTickGenerator.js index 714588b31f..024338eb4d 100644 --- a/platform/features/plot/src/elements/PlotTickGenerator.js +++ b/platform/features/plot/src/elements/PlotTickGenerator.js @@ -31,6 +31,7 @@ define( * domain and range axes of the plot, to support the plot * template. * + * @memberof platform/features/plot * @constructor * @param {PlotPanZoomStack} panZoomStack the pan-zoom stack for * this plot, used to determine plot boundaries @@ -62,6 +63,7 @@ define( * Generate tick marks for the domain axis. * @param {number} count the number of ticks * @returns {string[]} labels for those ticks + * @memberof platform/features/plot.PlotTickGenerator# */ generateDomainTicks: function (count) { var panZoom = panZoomStack.getPanZoom(); @@ -77,6 +79,7 @@ define( * Generate tick marks for the range axis. * @param {number} count the number of ticks * @returns {string[]} labels for those ticks + * @memberof platform/features/plot.PlotTickGenerator# */ generateRangeTicks: function (count) { var panZoom = panZoomStack.getPanZoom(); @@ -93,4 +96,4 @@ define( return PlotTickGenerator; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/elements/PlotUpdater.js b/platform/features/plot/src/elements/PlotUpdater.js index caf3abf3a2..d37112c243 100644 --- a/platform/features/plot/src/elements/PlotUpdater.js +++ b/platform/features/plot/src/elements/PlotUpdater.js @@ -39,6 +39,7 @@ define( * preparing them to be rendered. It creates a WebGL-plottable * Float32Array for each trace, and tracks the boundaries of the * data sets (since this is convenient to do during the same pass). + * @memberof platform/features/plot * @constructor * @param {TelemetryHandle} handle the handle to telemetry access * @param {string} domain the key to use when looking up domain values @@ -277,6 +278,7 @@ define( * data sets. This is given as a two-element array where the * first element is domain, and second is range. * @returns {number[]} the dimensions which bound this data set + * @memberof platform/features/plot.PlotUpdater# */ getDimensions: function () { return dimensions; @@ -287,6 +289,7 @@ define( * first element is domain, and second is range. * The domain value here is not adjusted by the domain offset. * @returns {number[]} the origin of this data set's boundary + * @memberof platform/features/plot.PlotUpdater# */ getOrigin: function () { // Pad range if necessary @@ -298,6 +301,7 @@ define( * preparer, in order to minimize loss-of-precision due to * conversion to the 32-bit float format needed by WebGL. * @returns {number} the domain offset + * @memberof platform/features/plot.PlotUpdater# */ getDomainOffset: function () { return domainOffset; @@ -318,16 +322,19 @@ define( * cause aliasing artifacts (particularly for timestamps) * * @returns {Float32Array[]} the buffers for these traces + * @memberof platform/features/plot.PlotUpdater# */ getLineBuffers: function () { return bufferArray; }, /** * Update with latest data. + * @memberof platform/features/plot.PlotUpdater# */ update: update, /** * Fill in historical data. + * @memberof platform/features/plot.PlotUpdater# */ addHistorical: setHistorical }; @@ -337,3 +344,4 @@ define( } ); + diff --git a/platform/features/plot/src/modes/PlotModeOptions.js b/platform/features/plot/src/modes/PlotModeOptions.js index 355f553228..efeea30fb5 100644 --- a/platform/features/plot/src/modes/PlotModeOptions.js +++ b/platform/features/plot/src/modes/PlotModeOptions.js @@ -44,6 +44,7 @@ define( * are applicable in a given plot view, maintains current * selection state thereof, and provides handlers for the * different behaviors associated with these modes. + * @memberof platform/features/plot * @constructor * @param {DomainObject[]} the telemetry objects being * represented in this plot view @@ -61,6 +62,7 @@ define( * and view-level interactions with pan-zoom state. * @returns {PlotOverlayMode|PlotStackMode} a handler * for the current mode + * @memberof platform/features/plot.PlotModeOptions# */ getModeHandler: function () { // Lazily initialize @@ -77,6 +79,7 @@ define( * mode contains a `name` and `glyph` field suitable * for display in a template. * @return {Array} the available modes + * @memberof platform/features/plot.PlotModeOptions# */ getModeOptions: function () { return options; @@ -86,6 +89,7 @@ define( * This will be one of the elements returned from * `getModeOptions`. * @return {object} the current mode + * @memberof platform/features/plot.PlotModeOptions# */ getMode: function () { return mode; @@ -96,6 +100,7 @@ define( * returned by `getModeOptions`. * @param {object} option one of the plot mode options * from `getModeOptions` + * @memberof platform/features/plot.PlotModeOptions# */ setMode: function (option) { if (mode !== option) { @@ -110,4 +115,4 @@ define( return PlotModeOptions; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/modes/PlotOverlayMode.js b/platform/features/plot/src/modes/PlotOverlayMode.js index 501d4b0e78..6baad8a546 100644 --- a/platform/features/plot/src/modes/PlotOverlayMode.js +++ b/platform/features/plot/src/modes/PlotOverlayMode.js @@ -29,6 +29,7 @@ define( /** * Handles plotting in Overlaid mode. In overlaid mode, there * is one sub-plot which contains all plotted objects. + * @memberof platform/features/plot * @constructor * @param {DomainObject[]} the domain objects to be plotted */ @@ -68,12 +69,14 @@ define( /** * Plot telemetry to the sub-plot(s) managed by this mode. * @param {PlotPreparer} prepared the prepared data to plot + * @memberof platform/features/plot.PlotOverlayMode# */ plotTelemetry: plotTelemetry, /** * Get all sub-plots to be displayed in this mode; used * to populate the plot template. * @return {SubPlot[]} all sub-plots to display in this mode + * @memberof platform/features/plot.PlotOverlayMode# */ getSubPlots: function () { return subplots; @@ -83,6 +86,7 @@ define( * there are some temporary user modifications to the * current pan-zoom state.) * @returns {boolean} true if not in the base pan-zoom state + * @memberof platform/features/plot.PlotOverlayMode# */ isZoomed: function () { return panZoomStack.getDepth() > 1; @@ -90,6 +94,7 @@ define( /** * Undo the most recent pan/zoom change and restore * the prior state. + * @memberof platform/features/plot.PlotOverlayMode# */ stepBackPanZoom: function () { panZoomStack.popPanZoom(); @@ -104,4 +109,4 @@ define( return PlotOverlayMode; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/modes/PlotStackMode.js b/platform/features/plot/src/modes/PlotStackMode.js index 5d54b461f1..c64f3fe286 100644 --- a/platform/features/plot/src/modes/PlotStackMode.js +++ b/platform/features/plot/src/modes/PlotStackMode.js @@ -29,6 +29,7 @@ define( /** * Handles plotting in Stacked mode. In stacked mode, there * is one sub-plot for each plotted object. + * @memberof platform/features/plot * @constructor * @param {DomainObject[]} the domain objects to be plotted */ @@ -77,12 +78,14 @@ define( /** * Plot telemetry to the sub-plot(s) managed by this mode. * @param {PlotPreparer} prepared the prepared data to plot + * @memberof platform/features/plot.PlotStackMode# */ plotTelemetry: plotTelemetry, /** * Get all sub-plots to be displayed in this mode; used * to populate the plot template. * @return {SubPlot[]} all sub-plots to display in this mode + * @memberof platform/features/plot.PlotStackMode# */ getSubPlots: function () { return subplots; @@ -92,6 +95,7 @@ define( * there are some temporary user modifications to the * current pan-zoom state.) * @returns {boolean} true if not in the base pan-zoom state + * @memberof platform/features/plot.PlotStackMode# */ isZoomed: function () { return panZoomStackGroup.getDepth() > 1; @@ -99,6 +103,7 @@ define( /** * Undo the most recent pan/zoom change and restore * the prior state. + * @memberof platform/features/plot.PlotStackMode# */ stepBackPanZoom: function () { panZoomStackGroup.popPanZoom(); @@ -108,6 +113,7 @@ define( }, /** * Undo all pan/zoom changes and restore the initial state. + * @memberof platform/features/plot.PlotStackMode# */ unzoom: function () { panZoomStackGroup.clearPanZoom(); @@ -120,4 +126,4 @@ define( return PlotStackMode; } -); \ No newline at end of file +); diff --git a/platform/features/plot/src/policies/PlotViewPolicy.js b/platform/features/plot/src/policies/PlotViewPolicy.js index 78df8c3187..26a64c0101 100644 --- a/platform/features/plot/src/policies/PlotViewPolicy.js +++ b/platform/features/plot/src/policies/PlotViewPolicy.js @@ -29,6 +29,8 @@ define( * Policy preventing the Plot view from being made available for * domain objects which have non-numeric telemetry. * @implements {Policy} + * @constructor + * @memberof platform/features/plot */ function PlotViewPolicy() { function hasImageTelemetry(domainObject) { @@ -63,3 +65,4 @@ define( return PlotViewPolicy; } ); + diff --git a/platform/features/rtevents/src/DomainColumn.js b/platform/features/rtevents/src/DomainColumn.js index 43279a42d7..ea2e039634 100644 --- a/platform/features/rtevents/src/DomainColumn.js +++ b/platform/features/rtevents/src/DomainColumn.js @@ -33,6 +33,7 @@ define( * A column which will report telemetry domain values * (typically, timestamps.) Used by the ScrollingListController. * + * @memberof platform/features/rtevents * @constructor * @param domainMetadata an object with the machine- and human- * readable names for this domain (in `key` and `name` @@ -45,6 +46,7 @@ define( /** * Get the title to display in this column's header. * @returns {string} the title to display + * @memberof platform/features/rtevents.DomainColumn# */ getTitle: function () { // At the moment there does not appear to be a way to get the @@ -55,6 +57,7 @@ define( * Get the text to display inside a row under this * column. * @returns {string} the text to display + * @memberof platform/features/rtevents.DomainColumn# */ getValue: function (domainObject, handle) { return { @@ -69,3 +72,4 @@ define( return DomainColumn; } ); + diff --git a/platform/features/rtevents/src/RTEventListController.js b/platform/features/rtevents/src/RTEventListController.js index bed335c6cd..93441f2635 100644 --- a/platform/features/rtevents/src/RTEventListController.js +++ b/platform/features/rtevents/src/RTEventListController.js @@ -35,6 +35,7 @@ define( /** * The RTEventListController is responsible for populating * the contents of the messages view. + * @memberof platform/features/rtevents * @constructor */ function RTEventListController($scope, telemetryHandler, telemetryFormatter) { @@ -136,3 +137,4 @@ define( return RTEventListController; } ); + diff --git a/platform/features/rtevents/src/RangeColumn.js b/platform/features/rtevents/src/RangeColumn.js index 68147062b5..1c398ddd44 100644 --- a/platform/features/rtevents/src/RangeColumn.js +++ b/platform/features/rtevents/src/RangeColumn.js @@ -34,6 +34,7 @@ define( * A column which will report telemetry range values * (typically, measurements.) Used by the RTEventListController. * + * @memberof platform/features/rtevents * @constructor * @param rangeMetadata an object with the machine- and human- * readable names for this range (in `key` and `name` @@ -46,6 +47,7 @@ define( /** * Get the title to display in this column's header. * @returns {string} the title to display + * @memberof platform/features/rtevents.RangeColumn# */ getTitle: function () { return "Message"; @@ -54,6 +56,7 @@ define( * Get the text to display inside a row under this * column. * @returns {string} the text to display + * @memberof platform/features/rtevents.RangeColumn# */ getValue: function (domainObject, handle) { return { @@ -66,3 +69,4 @@ define( return RangeColumn; } ); + diff --git a/platform/features/rtevents/src/directives/MCTRTDataTable.js b/platform/features/rtevents/src/directives/MCTRTDataTable.js index 9047d9e7f1..d7337eab4f 100644 --- a/platform/features/rtevents/src/directives/MCTRTDataTable.js +++ b/platform/features/rtevents/src/directives/MCTRTDataTable.js @@ -71,4 +71,4 @@ define( return MCTRTDataTable; } -); \ No newline at end of file +); diff --git a/platform/features/rtevents/src/policies/RTMessagesViewPolicy.js b/platform/features/rtevents/src/policies/RTMessagesViewPolicy.js index e3948e5a5c..a5a2373fb8 100644 --- a/platform/features/rtevents/src/policies/RTMessagesViewPolicy.js +++ b/platform/features/rtevents/src/policies/RTMessagesViewPolicy.js @@ -31,6 +31,7 @@ define( /** * Policy controlling when the real time Messages view should be avaliable. + * @memberof platform/features/rtevents * @constructor */ function RTMessagesViewPolicy() { @@ -52,6 +53,7 @@ define( * @param {Action} action the action * @param domainObject the domain object which will be viewed * @returns {boolean} true if not disallowed + * @memberof platform/features/rtevents.RTMessagesViewPolicy# */ allow: function (view, domainObject) { // This policy only applies for the RT Messages view @@ -71,4 +73,4 @@ define( return RTMessagesViewPolicy; } -); \ No newline at end of file +); diff --git a/platform/features/rtscrolling/src/DomainColumn.js b/platform/features/rtscrolling/src/DomainColumn.js index c4f8a2a143..95f262515d 100644 --- a/platform/features/rtscrolling/src/DomainColumn.js +++ b/platform/features/rtscrolling/src/DomainColumn.js @@ -33,6 +33,7 @@ define( * A column which will report telemetry domain values * (typically, timestamps.) Used by the ScrollingListController. * + * @memberof platform/features/rtscrolling * @constructor * @param domainMetadata an object with the machine- and human- * readable names for this domain (in `key` and `name` @@ -45,6 +46,7 @@ define( /** * Get the title to display in this column's header. * @returns {string} the title to display + * @memberof platform/features/rtscrolling.DomainColumn# */ getTitle: function () { return "Time"; @@ -53,6 +55,7 @@ define( * Get the text to display inside a row under this * column. * @returns {string} the text to display + * @memberof platform/features/rtscrolling.DomainColumn# */ getValue: function (domainObject, handle) { return { @@ -67,3 +70,4 @@ define( return DomainColumn; } ); + diff --git a/platform/features/rtscrolling/src/NameColumn.js b/platform/features/rtscrolling/src/NameColumn.js index eb08ebc7ed..b30891341b 100644 --- a/platform/features/rtscrolling/src/NameColumn.js +++ b/platform/features/rtscrolling/src/NameColumn.js @@ -33,6 +33,7 @@ define( * A column which will report the name of the domain object * which exposed specific telemetry values. * + * @memberof platform/features/rtscrolling * @constructor */ function NameColumn() { @@ -40,6 +41,7 @@ define( /** * Get the title to display in this column's header. * @returns {string} the title to display + * @memberof platform/features/rtscrolling.NameColumn# */ getTitle: function () { return "Name"; @@ -48,6 +50,7 @@ define( * Get the text to display inside a row under this * column. This returns the domain object's name. * @returns {string} the text to display + * @memberof platform/features/rtscrolling.NameColumn# */ getValue: function (domainObject) { return { @@ -60,3 +63,4 @@ define( return NameColumn; } ); + diff --git a/platform/features/rtscrolling/src/RTScrollingListController.js b/platform/features/rtscrolling/src/RTScrollingListController.js index bc9f8a63ed..282ccd145c 100644 --- a/platform/features/rtscrolling/src/RTScrollingListController.js +++ b/platform/features/rtscrolling/src/RTScrollingListController.js @@ -34,6 +34,7 @@ define( /** * The RTScrollingListController is responsible for populating * the contents of the scrolling list view. + * @memberof platform/features/rtscrolling * @constructor */ function RTScrollingListController($scope, telemetryHandler, telemetryFormatter) { @@ -135,3 +136,4 @@ define( return RTScrollingListController; } ); + diff --git a/platform/features/rtscrolling/src/RangeColumn.js b/platform/features/rtscrolling/src/RangeColumn.js index 867cc0798c..79c6cb8c73 100644 --- a/platform/features/rtscrolling/src/RangeColumn.js +++ b/platform/features/rtscrolling/src/RangeColumn.js @@ -33,6 +33,7 @@ define( * A column which will report telemetry range values * (typically, measurements.) Used by the RTScrollingListController. * + * @memberof platform/features/rtscrolling * @constructor * @param rangeMetadata an object with the machine- and human- * readable names for this range (in `key` and `name` @@ -52,6 +53,7 @@ define( /** * Get the title to display in this column's header. * @returns {string} the title to display + * @memberof platform/features/rtscrolling.RangeColumn# */ getTitle: function () { return "Value"; @@ -60,6 +62,7 @@ define( * Get the text to display inside a row under this * column. * @returns {string} the text to display + * @memberof platform/features/rtscrolling.RangeColumn# */ getValue: function (domainObject, handle) { var range = findRange(domainObject), @@ -81,3 +84,4 @@ define( return RangeColumn; } ); + diff --git a/platform/features/scrolling/src/DomainColumn.js b/platform/features/scrolling/src/DomainColumn.js index 33f3f4e020..96df96f822 100644 --- a/platform/features/scrolling/src/DomainColumn.js +++ b/platform/features/scrolling/src/DomainColumn.js @@ -33,6 +33,7 @@ define( * A column which will report telemetry domain values * (typically, timestamps.) Used by the ScrollingListController. * + * @memberof platform/features/scrolling * @constructor * @param domainMetadata an object with the machine- and human- * readable names for this domain (in `key` and `name` @@ -45,6 +46,7 @@ define( /** * Get the title to display in this column's header. * @returns {string} the title to display + * @memberof platform/features/scrolling.DomainColumn# */ getTitle: function () { return domainMetadata.name; @@ -53,6 +55,7 @@ define( * Get the text to display inside a row under this * column. * @returns {string} the text to display + * @memberof platform/features/scrolling.DomainColumn# */ getValue: function (domainObject, datum) { return { @@ -66,4 +69,4 @@ define( return DomainColumn; } -); \ No newline at end of file +); diff --git a/platform/features/scrolling/src/NameColumn.js b/platform/features/scrolling/src/NameColumn.js index 6420c44439..e177f0ceca 100644 --- a/platform/features/scrolling/src/NameColumn.js +++ b/platform/features/scrolling/src/NameColumn.js @@ -33,6 +33,7 @@ define( * A column which will report the name of the domain object * which exposed specific telemetry values. * + * @memberof platform/features/scrolling * @constructor */ function NameColumn() { @@ -40,6 +41,7 @@ define( /** * Get the title to display in this column's header. * @returns {string} the title to display + * @memberof platform/features/scrolling.NameColumn# */ getTitle: function () { return "Name"; @@ -48,6 +50,7 @@ define( * Get the text to display inside a row under this * column. This returns the domain object's name. * @returns {string} the text to display + * @memberof platform/features/scrolling.NameColumn# */ getValue: function (domainObject) { return { @@ -59,4 +62,4 @@ define( return NameColumn; } -); \ No newline at end of file +); diff --git a/platform/features/scrolling/src/RangeColumn.js b/platform/features/scrolling/src/RangeColumn.js index 1e89dfc376..980ed5da39 100644 --- a/platform/features/scrolling/src/RangeColumn.js +++ b/platform/features/scrolling/src/RangeColumn.js @@ -33,6 +33,7 @@ define( * A column which will report telemetry range values * (typically, measurements.) Used by the ScrollingListController. * + * @memberof platform/features/scrolling * @constructor * @param rangeMetadata an object with the machine- and human- * readable names for this range (in `key` and `name` @@ -45,6 +46,7 @@ define( /** * Get the title to display in this column's header. * @returns {string} the title to display + * @memberof platform/features/scrolling.RangeColumn# */ getTitle: function () { return rangeMetadata.name; @@ -53,6 +55,7 @@ define( * Get the text to display inside a row under this * column. * @returns {string} the text to display + * @memberof platform/features/scrolling.RangeColumn# */ getValue: function (domainObject, datum) { var range = rangeMetadata.key, @@ -70,4 +73,4 @@ define( return RangeColumn; } -); \ No newline at end of file +); diff --git a/platform/features/scrolling/src/ScrollingListController.js b/platform/features/scrolling/src/ScrollingListController.js index f61e178964..522a762474 100644 --- a/platform/features/scrolling/src/ScrollingListController.js +++ b/platform/features/scrolling/src/ScrollingListController.js @@ -34,6 +34,7 @@ define( /** * The ScrollingListController is responsible for populating * the contents of the scrolling list view. + * @memberof platform/features/scrolling * @constructor */ function ScrollingListController($scope, formatter) { @@ -130,3 +131,4 @@ define( return ScrollingListController; } ); + diff --git a/platform/features/scrolling/src/ScrollingListPopulator.js b/platform/features/scrolling/src/ScrollingListPopulator.js index bbdda2359a..058829bab0 100644 --- a/platform/features/scrolling/src/ScrollingListPopulator.js +++ b/platform/features/scrolling/src/ScrollingListPopulator.js @@ -30,6 +30,7 @@ define( * The ScrollingListPopulator is responsible for filling in the * values which should appear within columns of a scrolling list * view, based on received telemetry data. + * @memberof platform/features/scrolling * @constructor * @param {Column[]} columns the columns to be populated */ @@ -50,6 +51,7 @@ define( * data objects; expected to be in the same order * as the domain objects provided at constructor * @param {number} count the number of rows to provide + * @memberof platform/features/scrolling.ScrollingListPopulator# */ function getLatestDataValues(datas, count) { var latest = [], @@ -136,6 +138,7 @@ define( * Get the text which should appear in headers for the * provided columns. * @returns {string[]} column headers + * @memberof platform/features/scrolling.ScrollingListPopulator# */ getHeaders: function () { return columns.map(function (column) { @@ -152,6 +155,7 @@ define( * @returns {string[][]} an array of rows, each of which * is an array of values which should appear * in that row + * @memberof platform/features/scrolling.ScrollingListPopulator# */ getRows: function (datas, objects, count) { var values = getLatestDataValues(datas, count); @@ -181,3 +185,4 @@ define( } ); + diff --git a/platform/forms/src/MCTControl.js b/platform/forms/src/MCTControl.js index 8ec0d5e039..b46ba6e7a1 100644 --- a/platform/forms/src/MCTControl.js +++ b/platform/forms/src/MCTControl.js @@ -33,6 +33,8 @@ define( * `controls`; this allows plug-ins to introduce new form * control types while still making use of the form * generator to ensure an overall consistent form style. + * @constructor + * @memberof platform/forms */ function MCTControl(controls) { var controlMap = {}; @@ -103,4 +105,4 @@ define( return MCTControl; } -); \ No newline at end of file +); diff --git a/platform/forms/src/MCTForm.js b/platform/forms/src/MCTForm.js index a318870198..fb288ed244 100644 --- a/platform/forms/src/MCTForm.js +++ b/platform/forms/src/MCTForm.js @@ -46,6 +46,7 @@ define( * of name, except this will be made available in the * parent scope. * + * @memberof platform/forms * @constructor */ function MCTForm() { @@ -82,4 +83,4 @@ define( return MCTForm; } -); \ No newline at end of file +); diff --git a/platform/forms/src/MCTToolbar.js b/platform/forms/src/MCTToolbar.js index ea0f644cc3..41d2c4c00d 100644 --- a/platform/forms/src/MCTToolbar.js +++ b/platform/forms/src/MCTToolbar.js @@ -46,6 +46,7 @@ define( * of name, except this will be made available in the * parent scope. * + * @memberof platform/forms * @constructor */ function MCTForm() { @@ -82,4 +83,4 @@ define( return MCTForm; } -); \ No newline at end of file +); diff --git a/platform/forms/src/controllers/ColorController.js b/platform/forms/src/controllers/ColorController.js index 420e2ed96d..6c1db4fed1 100644 --- a/platform/forms/src/controllers/ColorController.js +++ b/platform/forms/src/controllers/ColorController.js @@ -99,4 +99,4 @@ define( return ColorController; } -); \ No newline at end of file +); diff --git a/platform/forms/src/controllers/CompositeController.js b/platform/forms/src/controllers/CompositeController.js index e332ed7115..e3a0559d09 100644 --- a/platform/forms/src/controllers/CompositeController.js +++ b/platform/forms/src/controllers/CompositeController.js @@ -35,6 +35,7 @@ define( * filled in) should be disallowed. This is enforced in the template * by an ng-required directive, but that is supported by the * isNonEmpty check that this controller provides. + * @memberof platform/forms * @constructor */ function CompositeController() { @@ -55,6 +56,7 @@ define( * @param {Array} value the array to check * @returns {boolean} true if any non-undefined * element is in the array + * @memberof platform/forms.CompositeController# */ isNonEmpty: function (value) { return Array.isArray(value) && @@ -66,4 +68,4 @@ define( return CompositeController; } -); \ No newline at end of file +); diff --git a/platform/forms/src/controllers/DateTimeController.js b/platform/forms/src/controllers/DateTimeController.js index e37e3a8f71..5ef7735ed1 100644 --- a/platform/forms/src/controllers/DateTimeController.js +++ b/platform/forms/src/controllers/DateTimeController.js @@ -34,6 +34,7 @@ define( * input fields but outputs a single timestamp (in * milliseconds since start of 1970) to the ngModel. * + * @memberof platform/forms * @constructor */ function DateTimeController($scope) { @@ -106,3 +107,4 @@ define( } ); + diff --git a/platform/forms/src/controllers/DialogButtonController.js b/platform/forms/src/controllers/DialogButtonController.js index 1298b1a63c..afb0e54391 100644 --- a/platform/forms/src/controllers/DialogButtonController.js +++ b/platform/forms/src/controllers/DialogButtonController.js @@ -29,6 +29,7 @@ define( * Controller for the `dialog-button` control type. Provides * structure for a button (embedded via the template) which * will show a dialog for editing a single property when clicked. + * @memberof platform/forms * @constructor * @param $scope the control's Angular scope * @param {DialogService} dialogService service to use to prompt @@ -85,6 +86,7 @@ define( * `button`; a dialog will be launched when this button * is clicked. * @returns dialog structure + * @memberof platform/forms.DialogButtonController# */ getButtonStructure: function () { return buttonStructure; @@ -94,4 +96,4 @@ define( return DialogButtonController; } -); \ No newline at end of file +); diff --git a/platform/forms/src/controllers/FormController.js b/platform/forms/src/controllers/FormController.js index 12b5261b76..04b8379304 100644 --- a/platform/forms/src/controllers/FormController.js +++ b/platform/forms/src/controllers/FormController.js @@ -31,6 +31,7 @@ define( /** * Controller for mct-form and mct-toolbar directives. + * @memberof platform/forms * @constructor */ function FormController($scope) { @@ -75,4 +76,4 @@ define( return FormController; } -); \ No newline at end of file +); diff --git a/platform/framework/src/Constants.js b/platform/framework/src/Constants.js index 6bfa6ce7b9..3d9fb949b0 100644 --- a/platform/framework/src/Constants.js +++ b/platform/framework/src/Constants.js @@ -47,4 +47,4 @@ define({ "mandatory": Number.POSITIVE_INFINITY }, DEFAULT_PRIORITY: 0 -}); \ No newline at end of file +}); diff --git a/platform/framework/src/FrameworkInitializer.js b/platform/framework/src/FrameworkInitializer.js index 359fd1274f..a0db162f01 100644 --- a/platform/framework/src/FrameworkInitializer.js +++ b/platform/framework/src/FrameworkInitializer.js @@ -38,6 +38,7 @@ define( * * Registering extensions with Angular * * Bootstrapping the Angular application. * + * @memberof platform/framework * @constructor * @param {BundleLoader} loader * @param {BundleResolver} resolver @@ -59,4 +60,4 @@ define( return FrameworkInitializer; } -); \ No newline at end of file +); diff --git a/platform/framework/src/LogLevel.js b/platform/framework/src/LogLevel.js index 5734a66f45..1c54659ff6 100644 --- a/platform/framework/src/LogLevel.js +++ b/platform/framework/src/LogLevel.js @@ -47,6 +47,7 @@ define( * as a default. Only log messages of levels equal to or greater * than the specified level will be passed to console. * + * @memberof platform/framework * @constructor * @param {string} level the logging level */ @@ -83,6 +84,7 @@ define( * * @param app the Angular app to configure * @param $log Angular's $log (also configured) + * @memberof platform/framework.LogLevel# */ configure: function (app, $log) { decorate($log); @@ -98,4 +100,4 @@ define( return LogLevel; } -); \ No newline at end of file +); diff --git a/platform/framework/src/Main.js b/platform/framework/src/Main.js index 2faf115a85..47391a6bb5 100644 --- a/platform/framework/src/Main.js +++ b/platform/framework/src/Main.js @@ -129,4 +129,4 @@ define( requirejs.config({ "baseUrl": "" }); injector.invoke(['$http', '$log', initializeApplication]); } -); \ No newline at end of file +); diff --git a/platform/framework/src/bootstrap/ApplicationBootstrapper.js b/platform/framework/src/bootstrap/ApplicationBootstrapper.js index 8649175091..82b1714e31 100644 --- a/platform/framework/src/bootstrap/ApplicationBootstrapper.js +++ b/platform/framework/src/bootstrap/ApplicationBootstrapper.js @@ -38,6 +38,7 @@ define( * framework needs to wait until all extensions have been loaded * and registered. * + * @memberof platform/framework * @constructor */ function ApplicationBootstrapper(angular, document, $log) { @@ -49,6 +50,7 @@ define( * @memberof ApplicationBootstrapper# * @param {angular.Module} app the Angular application to * bootstrap + * @memberof platform/framework.ApplicationBootstrapper# */ bootstrap: function (app) { $log.info("Bootstrapping application " + (app || {}).name); @@ -61,4 +63,4 @@ define( return ApplicationBootstrapper; } -); \ No newline at end of file +); diff --git a/platform/framework/src/load/Bundle.js b/platform/framework/src/load/Bundle.js index 1a4265fe2c..147ca01ef1 100644 --- a/platform/framework/src/load/Bundle.js +++ b/platform/framework/src/load/Bundle.js @@ -38,6 +38,8 @@ define( * contains resource files used by this bundle * @property {Object.} [extensions={}] * all extensions exposed by this bundle + * @constructor + * @memberof platform/framework */ @@ -84,6 +86,7 @@ define( * Get the path to this bundle. * @memberof Bundle# * @returns {string} + * @memberof platform/framework.Bundle# */ getPath: function () { return path; @@ -97,6 +100,7 @@ define( * @param {string} [sourceFile] optionally, give a path to * a specific source file in the bundle. * @returns {string} + * @memberof platform/framework.Bundle# */ getSourcePath: function (sourceFile) { var subpath = sourceFile ? @@ -114,6 +118,7 @@ define( * @param {string} [resourceFile] optionally, give a path to * a specific resource file in the bundle. * @returns {string} + * @memberof platform/framework.Bundle# */ getResourcePath: function (resourceFile) { var subpath = resourceFile ? @@ -131,6 +136,7 @@ define( * @param {string} [libraryFile] optionally, give a path to * a specific library file in the bundle. * @returns {string} + * @memberof platform/framework.Bundle# */ getLibraryPath: function (libraryFile) { var subpath = libraryFile ? @@ -145,6 +151,7 @@ define( * it will resemble a require.config object. * @memberof Bundle# * @returns {object} + * @memberof platform/framework.Bundle# */ getConfiguration: function () { return definition.configuration || {}; @@ -155,6 +162,7 @@ define( * bundle) and the name (human-readable name for this * bundle.) * @returns {string} log-friendly name for this bundle + * @memberof platform/framework.Bundle# */ getLogName: function () { return logName; @@ -166,6 +174,7 @@ define( * @param category * @memberof Bundle# * @returns {Array} + * @memberof platform/framework.Bundle# */ getExtensions: function (category) { var extensions = definition.extensions[category] || []; @@ -180,6 +189,7 @@ define( * * @memberof Bundle# * @returns {Array} + * @memberof platform/framework.Bundle# */ getExtensionCategories: function () { return Object.keys(definition.extensions); @@ -190,6 +200,7 @@ define( * * @memberof Bundle# * @returns {BundleDefinition} the raw definition of this bundle + * @memberof platform/framework.Bundle# */ getDefinition: function () { return definition; @@ -201,4 +212,4 @@ define( return Bundle; } -); \ No newline at end of file +); diff --git a/platform/framework/src/load/BundleLoader.js b/platform/framework/src/load/BundleLoader.js index 0329681630..34f70b2502 100644 --- a/platform/framework/src/load/BundleLoader.js +++ b/platform/framework/src/load/BundleLoader.js @@ -39,6 +39,7 @@ define( * useful to the framework. This provides the base information which * will be used by later phases of framework layer initialization. * + * @memberof platform/framework * @constructor * @param {object} $http Angular's HTTP requester * @param {object} $log Angular's logging service @@ -120,6 +121,7 @@ define( * @param {string|string[]} an array of bundle names to load, or * the name of a JSON file containing that array * @returns {Promise.} + * @memberof platform/framework.BundleLoader# */ loadBundles: loadBundles }; @@ -127,4 +129,4 @@ define( return BundleLoader; } -); \ No newline at end of file +); diff --git a/platform/framework/src/load/Extension.js b/platform/framework/src/load/Extension.js index 3063838a14..7a2d46ae7b 100644 --- a/platform/framework/src/load/Extension.js +++ b/platform/framework/src/load/Extension.js @@ -38,6 +38,8 @@ define( * @property {string[]} [depends=[]] the dependencies needed by this * extension; these are strings as shall be passed to * Angular's dependency resolution mechanism. + * @constructor + * @memberof platform/framework */ /** @@ -81,6 +83,7 @@ define( * Get the machine-readable identifier for this extension. * * @returns {string} + * @memberof platform/framework.Extension# */ getKey: function () { return definition.key || "undefined"; @@ -90,6 +93,7 @@ define( * * @memberof Extension# * @returns {Bundle} + * @memberof platform/framework.Extension# */ getBundle: function () { return bundle; @@ -100,6 +104,7 @@ define( * * @memberof Extension# * @returns {string} + * @memberof platform/framework.Extension# */ getCategory: function () { return category; @@ -111,6 +116,7 @@ define( * * @returns {boolean} true if an implementation separate * from this definition should also be loaded + * @memberof platform/framework.Extension# */ hasImplementation: function () { return definition.implementation !== undefined; @@ -122,6 +128,7 @@ define( * * @memberof Extension# * @returns {string} path to implementation, or undefined + * @memberof platform/framework.Extension# */ getImplementationPath: function () { return definition.implementation ? @@ -134,6 +141,7 @@ define( * extension) and the name (human-readable name for this * extension.) * @returns {string} log-friendly name for this extension + * @memberof platform/framework.Extension# */ getLogName: function () { return logName; @@ -149,6 +157,7 @@ define( * @returns {ExtensionDefinition} the plain definition of * this extension, as read from the bundle * declaration. + * @memberof platform/framework.Extension# */ getDefinition: function () { return extensionDefinition; @@ -160,4 +169,4 @@ define( return Extension; } -); \ No newline at end of file +); diff --git a/platform/framework/src/register/CustomRegistrars.js b/platform/framework/src/register/CustomRegistrars.js index 5920e4c630..392a8c98c7 100644 --- a/platform/framework/src/register/CustomRegistrars.js +++ b/platform/framework/src/register/CustomRegistrars.js @@ -33,6 +33,7 @@ define( * Handles registration of a few specific extension types that are * understood natively by Angular. This includes services and * directives. + * @memberof platform/framework * @constructor */ function CustomRegistrars(app, $log) { @@ -164,4 +165,4 @@ define( return CustomRegistrars; } -); \ No newline at end of file +); diff --git a/platform/framework/src/register/ExtensionRegistrar.js b/platform/framework/src/register/ExtensionRegistrar.js index cbc44562d0..bc6f58084e 100644 --- a/platform/framework/src/register/ExtensionRegistrar.js +++ b/platform/framework/src/register/ExtensionRegistrar.js @@ -32,6 +32,7 @@ define( /** * Responsible for registering extensions with Angular. * + * @memberof platform/framework * @constructor * @param {angular.Module} the Angular application with which * extensions should be registered @@ -215,6 +216,7 @@ define( * extensions * @returns {angular.Module} the application module with * which extensions were registered + * @memberof platform/framework.ExtensionRegistrar# */ registerExtensions: registerExtensionGroup }; @@ -222,4 +224,4 @@ define( return ExtensionRegistrar; } -); \ No newline at end of file +); diff --git a/platform/framework/src/register/ExtensionSorter.js b/platform/framework/src/register/ExtensionSorter.js index fb401de351..f10d7b62ce 100644 --- a/platform/framework/src/register/ExtensionSorter.js +++ b/platform/framework/src/register/ExtensionSorter.js @@ -34,6 +34,7 @@ define( * specify symbolic properties as strings (instead of numbers), * which will be looked up from the table `Constants.PRIORITY_LEVELS`. * @param $log Angular's logging service + * @memberof platform/framework * @constructor */ function ExtensionSorter($log) { @@ -103,6 +104,7 @@ define( * * @param {object[]} extensions array of resolved extensions * @returns {object[]} the same extensions, in priority order + * @memberof platform/framework.ExtensionSorter# */ sort: function (extensions) { return (extensions || []) @@ -115,4 +117,4 @@ define( return ExtensionSorter; } -); \ No newline at end of file +); diff --git a/platform/framework/src/register/PartialConstructor.js b/platform/framework/src/register/PartialConstructor.js index 3778a2519a..46598f6402 100644 --- a/platform/framework/src/register/PartialConstructor.js +++ b/platform/framework/src/register/PartialConstructor.js @@ -43,6 +43,7 @@ define( * instantiate instances of these extensions by passing only * those per-instance arguments. * + * @memberof platform/framework * @constructor */ function PartialConstructor(Constructor) { @@ -76,4 +77,4 @@ define( return PartialConstructor; } -); \ No newline at end of file +); diff --git a/platform/framework/src/register/ServiceCompositor.js b/platform/framework/src/register/ServiceCompositor.js index d44e8cb24b..c76beeba49 100644 --- a/platform/framework/src/register/ServiceCompositor.js +++ b/platform/framework/src/register/ServiceCompositor.js @@ -33,6 +33,7 @@ define( * Handles service compositing; that is, building up services * from provider, aggregator, and decorator components. * + * @memberof platform/framework * @constructor */ function ServiceCompositor(app, $log) { @@ -221,6 +222,7 @@ define( * method may not behave as expected. * * @param {Array} components extensions of category component + * @memberof platform/framework.ServiceCompositor# */ registerCompositeServices: registerCompositeServices }; @@ -228,4 +230,4 @@ define( return ServiceCompositor; } -); \ No newline at end of file +); diff --git a/platform/framework/src/resolve/BundleResolver.js b/platform/framework/src/resolve/BundleResolver.js index 5c8216da94..02bb76110d 100644 --- a/platform/framework/src/resolve/BundleResolver.js +++ b/platform/framework/src/resolve/BundleResolver.js @@ -34,6 +34,7 @@ define( * initialization. During this phase, any scripts implementing * extensions provided by bundles are loaded. * + * @memberof platform/framework * @constructor */ function BundleResolver(extensionResolver, requireConfigurator, $log) { @@ -47,6 +48,7 @@ define( * * @param {Object.|Array} resolvedBundles * @returns {Object.} + * @memberof platform/framework.BundleResolver# */ function mergeResolvedBundles(resolvedBundles) { var result = {}; @@ -107,6 +109,7 @@ define( * key-value pairs, where keys are extension * categories and values are arrays of resolved * extensions belonging to those categories + * @memberof platform/framework.BundleResolver# */ resolveBundles: function (bundles) { // First, make sure Require is suitably configured @@ -121,4 +124,4 @@ define( return BundleResolver; } -); \ No newline at end of file +); diff --git a/platform/framework/src/resolve/ExtensionResolver.js b/platform/framework/src/resolve/ExtensionResolver.js index 0257664f1f..86eb657f35 100644 --- a/platform/framework/src/resolve/ExtensionResolver.js +++ b/platform/framework/src/resolve/ExtensionResolver.js @@ -35,6 +35,7 @@ define( * * @param {ImplementationLoader} loader used to load implementations * @param {*} $log Angular's logging service + * @memberof platform/framework * @constructor */ function ExtensionResolver(loader, $log) { @@ -111,6 +112,7 @@ define( * will additionally be attached to any loaded implementation. * * @param {Extension} extension + * @memberof platform/framework.ExtensionResolver# */ resolve: function (extension) { // Log that loading has begun @@ -128,4 +130,4 @@ define( return ExtensionResolver; } -); \ No newline at end of file +); diff --git a/platform/framework/src/resolve/ImplementationLoader.js b/platform/framework/src/resolve/ImplementationLoader.js index ce0abe104c..b76c5035e8 100644 --- a/platform/framework/src/resolve/ImplementationLoader.js +++ b/platform/framework/src/resolve/ImplementationLoader.js @@ -33,6 +33,7 @@ define( * Responsible for loading extension implementations * (AMD modules.) Acts as a wrapper around RequireJS to * provide a promise-like API. + * @memberof platform/framework * @constructor * @param {*} require RequireJS, or an object with similar API * @param {*} $log Angular's logging service @@ -57,6 +58,7 @@ define( * @memberof ImplementationLoader# * @param {string} path the path to the module to load * @returns {Promise} a promise for the specified module. + * @memberof platform/framework.ImplementationLoader# */ load: loadModule }; @@ -64,4 +66,4 @@ define( return ImplementationLoader; } -); \ No newline at end of file +); diff --git a/platform/framework/src/resolve/RequireConfigurator.js b/platform/framework/src/resolve/RequireConfigurator.js index 7900efeed9..231a4c316f 100644 --- a/platform/framework/src/resolve/RequireConfigurator.js +++ b/platform/framework/src/resolve/RequireConfigurator.js @@ -30,6 +30,7 @@ define( * Handles configuration of RequireJS to expose libraries * from bundles with module names that can be used from other * bundles. + * @memberof platform/framework * @constructor * @param requirejs an instance of RequireJS */ @@ -99,6 +100,7 @@ define( * * @param {Bundle[]} the bundles to include in this * configuration + * @memberof platform/framework.RequireConfigurator# */ configure: function (bundles) { return requirejs.config(buildConfiguration(bundles)); @@ -109,4 +111,4 @@ define( return RequireConfigurator; } -); \ No newline at end of file +); diff --git a/platform/persistence/cache/src/CachingPersistenceDecorator.js b/platform/persistence/cache/src/CachingPersistenceDecorator.js index 5647f3c9e1..a4ff16c09e 100644 --- a/platform/persistence/cache/src/CachingPersistenceDecorator.js +++ b/platform/persistence/cache/src/CachingPersistenceDecorator.js @@ -31,6 +31,7 @@ define( * that have been loaded, and keeps them in sync after writes. This allows * retrievals to occur more quickly after the first load. * + * @memberof platform/persistence/cache * @constructor * @param {string[]} CACHE_SPACES persistence space names which * should be cached @@ -113,6 +114,7 @@ define( * decorated service. * @memberof CachingPersistenceDecorator# * @returns {Promise.} spaces supported + * @memberof platform/persistence/cache.CachingPersistenceDecorator# */ listSpaces: function () { return persistenceService.listSpaces(); @@ -122,6 +124,7 @@ define( * @memberof CachingPersistenceDecorator# * @param {string} space the space in which to list objects * @returns {Promise.} keys for objects in this space + * @memberof platform/persistence/cache.CachingPersistenceDecorator# */ listObjects: function (space) { return persistenceService.listObjects(space); @@ -136,6 +139,7 @@ define( * @param {object} value a JSONifiable object to store * @returns {Promise.} an indicator of the success or * failure of this request + * @memberof platform/persistence/cache.CachingPersistenceDecorator# */ createObject: function (space, key, value) { addToCache(space, key, value); @@ -150,6 +154,7 @@ define( * @returns {Promise.} a promise for the object; may * resolve to undefined (if the object does not exist * in this space) + * @memberof platform/persistence/cache.CachingPersistenceDecorator# */ readObject: function (space, key) { return (cache[space] && cache[space][key]) ? @@ -167,6 +172,7 @@ define( * @param {object} value a JSONifiable object to store * @returns {Promise.} an indicator of the success or * failure of this request + * @memberof platform/persistence/cache.CachingPersistenceDecorator# */ updateObject: function (space, key, value) { return persistenceService.updateObject(space, key, value) @@ -185,6 +191,7 @@ define( * @param {object} value a JSONifiable object to delete * @returns {Promise.} an indicator of the success or * failure of this request + * @memberof platform/persistence/cache.CachingPersistenceDecorator# */ deleteObject: function (space, key, value) { if (cache[space]) { @@ -198,4 +205,4 @@ define( return CachingPersistenceDecorator; } -); \ No newline at end of file +); diff --git a/platform/persistence/couch/src/CouchDocument.js b/platform/persistence/couch/src/CouchDocument.js index d115f56839..d61641f041 100644 --- a/platform/persistence/couch/src/CouchDocument.js +++ b/platform/persistence/couch/src/CouchDocument.js @@ -33,6 +33,7 @@ define( * metadata field which contains a subset of information found * in the model itself (to support search optimization with * CouchDB views.) + * @memberof platform/persistence/couch * @constructor * @param {string} id the id under which to store this mode * @param {object} model the model to store @@ -59,4 +60,4 @@ define( return CouchDocument; } -); \ No newline at end of file +); diff --git a/platform/persistence/couch/src/CouchIndicator.js b/platform/persistence/couch/src/CouchIndicator.js index f49f6ce2e5..a57a129c21 100644 --- a/platform/persistence/couch/src/CouchIndicator.js +++ b/platform/persistence/couch/src/CouchIndicator.js @@ -55,6 +55,8 @@ define( * Indicator for the current CouchDB connection. Polls CouchDB * at a regular interval (defined by bundle constants) to ensure * that the database is available. + * @constructor + * @memberof platform/persistence/couch */ function CouchIndicator($http, $interval, PATH, INTERVAL) { // Track the current connection state @@ -87,6 +89,7 @@ define( * to display in this indicator. This will return "D", * which should appear as a database icon. * @returns {string} the character of the database icon + * @memberof platform/persistence/couch.CouchIndicator# */ getGlyph: function () { return "D"; @@ -96,6 +99,7 @@ define( * This is used to color the glyph to match its * state (one of ok, caution or err) * @returns {string} the CSS class to apply to this glyph + * @memberof platform/persistence/couch.CouchIndicator# */ getGlyphClass: function () { return state.glyphClass; @@ -103,6 +107,7 @@ define( /** * Get the text that should appear in the indicator. * @returns {string} brief summary of connection status + * @memberof platform/persistence/couch.CouchIndicator# */ getText: function () { return state.text; @@ -111,6 +116,7 @@ define( * Get a longer-form description of the current connection * space, suitable for display in a tooltip * @returns {string} longer summary of connection status + * @memberof platform/persistence/couch.CouchIndicator# */ getDescription: function () { return state.description; @@ -121,4 +127,4 @@ define( return CouchIndicator; } -); \ No newline at end of file +); diff --git a/platform/persistence/couch/src/CouchPersistenceProvider.js b/platform/persistence/couch/src/CouchPersistenceProvider.js index e9dd13e39b..77c8ac7bd8 100644 --- a/platform/persistence/couch/src/CouchPersistenceProvider.js +++ b/platform/persistence/couch/src/CouchPersistenceProvider.js @@ -35,6 +35,7 @@ define( * The CouchPersistenceProvider reads and writes JSON documents * (more specifically, domain object models) to/from a CouchDB * instance. + * @memberof platform/persistence/couch * @constructor */ function CouchPersistenceProvider($http, $q, SPACE, PATH) { @@ -104,6 +105,7 @@ define( * * @returns {Promise.} a promise for a list of * spaces supported by this provider + * @memberof platform/persistence/couch.CouchPersistenceProvider# */ listSpaces: function () { return $q.when(spaces); @@ -114,6 +116,7 @@ define( * @param {string} space the space to check * @returns {Promise.} a promise for the list of * identifiers + * @memberof platform/persistence/couch.CouchPersistenceProvider# */ listObjects: function (space) { return get("_all_docs").then(getIdsFromAllDocs); @@ -127,6 +130,7 @@ define( * @returns {Promise.} a promise for an indication * of the success (true) or failure (false) of this * operation + * @memberof platform/persistence/couch.CouchPersistenceProvider# */ createObject: function (space, key, value) { return put(key, new CouchDocument(key, value)) @@ -141,6 +145,7 @@ define( * @returns {Promise.} a promise for the stored * object; this will resolve to undefined if no such * object is found. + * @memberof platform/persistence/couch.CouchPersistenceProvider# */ readObject: function (space, key) { return get(key).then(getModel); @@ -154,6 +159,7 @@ define( * @returns {Promise.} a promise for an indication * of the success (true) or failure (false) of this * operation + * @memberof platform/persistence/couch.CouchPersistenceProvider# */ updateObject: function (space, key, value) { return put(key, new CouchDocument(key, value, revs[key])) @@ -169,6 +175,7 @@ define( * @returns {Promise.} a promise for an indication * of the success (true) or failure (false) of this * operation + * @memberof platform/persistence/couch.CouchPersistenceProvider# */ deleteObject: function (space, key, value) { return put(key, new CouchDocument(key, value, revs[key], true)) @@ -180,4 +187,4 @@ define( return CouchPersistenceProvider; } -); \ No newline at end of file +); diff --git a/platform/persistence/elastic/src/ElasticIndicator.js b/platform/persistence/elastic/src/ElasticIndicator.js index 82714080a0..17eb4e28db 100644 --- a/platform/persistence/elastic/src/ElasticIndicator.js +++ b/platform/persistence/elastic/src/ElasticIndicator.js @@ -49,6 +49,8 @@ define( * Indicator for the current CouchDB connection. Polls CouchDB * at a regular interval (defined by bundle constants) to ensure * that the database is available. + * @constructor + * @memberof platform/persistence/elastic */ function ElasticIndicator($http, $interval, PATH, INTERVAL) { // Track the current connection state @@ -79,6 +81,7 @@ define( * to display in this indicator. This will return "D", * which should appear as a database icon. * @returns {string} the character of the database icon + * @memberof platform/persistence/elastic.ElasticIndicator# */ getGlyph: function () { return "D"; @@ -88,6 +91,7 @@ define( * This is used to color the glyph to match its * state (one of ok, caution or err) * @returns {string} the CSS class to apply to this glyph + * @memberof platform/persistence/elastic.ElasticIndicator# */ getGlyphClass: function () { return state.glyphClass; @@ -95,6 +99,7 @@ define( /** * Get the text that should appear in the indicator. * @returns {string} brief summary of connection status + * @memberof platform/persistence/elastic.ElasticIndicator# */ getText: function () { return state.text; @@ -103,6 +108,7 @@ define( * Get a longer-form description of the current connection * space, suitable for display in a tooltip * @returns {string} longer summary of connection status + * @memberof platform/persistence/elastic.ElasticIndicator# */ getDescription: function () { return state.description; @@ -113,4 +119,4 @@ define( return ElasticIndicator; } -); \ No newline at end of file +); diff --git a/platform/persistence/elastic/src/ElasticPersistenceProvider.js b/platform/persistence/elastic/src/ElasticPersistenceProvider.js index a9c35af210..dffd13044e 100644 --- a/platform/persistence/elastic/src/ElasticPersistenceProvider.js +++ b/platform/persistence/elastic/src/ElasticPersistenceProvider.js @@ -37,6 +37,7 @@ define( * The ElasticPersistenceProvider reads and writes JSON documents * (more specifically, domain object models) to/from an ElasticSearch * instance. + * @memberof platform/persistence/elastic * @constructor */ function ElasticPersistenceProvider($http, $q, SPACE, ROOT, PATH) { @@ -120,6 +121,7 @@ define( * * @returns {Promise.} a promise for a list of * spaces supported by this provider + * @memberof platform/persistence/elastic.ElasticPersistenceProvider# */ listSpaces: function () { return $q.when(spaces); @@ -130,6 +132,7 @@ define( * @param {string} space the space to check * @returns {Promise.} a promise for the list of * identifiers + * @memberof platform/persistence/elastic.ElasticPersistenceProvider# */ listObjects: function (space) { return $q.when([]); @@ -143,6 +146,7 @@ define( * @returns {Promise.} a promise for an indication * of the success (true) or failure (false) of this * operation + * @memberof platform/persistence/elastic.ElasticPersistenceProvider# */ createObject: function (space, key, value) { return put(key, value).then(checkResponse); @@ -156,6 +160,7 @@ define( * @returns {Promise.} a promise for the stored * object; this will resolve to undefined if no such * object is found. + * @memberof platform/persistence/elastic.ElasticPersistenceProvider# */ readObject: function (space, key) { return get(key).then(getModel); @@ -169,6 +174,7 @@ define( * @returns {Promise.} a promise for an indication * of the success (true) or failure (false) of this * operation + * @memberof platform/persistence/elastic.ElasticPersistenceProvider# */ updateObject: function (space, key, value) { function checkUpdate(response) { @@ -187,6 +193,7 @@ define( * @returns {Promise.} a promise for an indication * of the success (true) or failure (false) of this * operation + * @memberof platform/persistence/elastic.ElasticPersistenceProvider# */ deleteObject: function (space, key, value) { return del(key).then(checkResponse); @@ -197,4 +204,4 @@ define( return ElasticPersistenceProvider; } -); \ No newline at end of file +); diff --git a/platform/persistence/queue/src/PersistenceFailureConstants.js b/platform/persistence/queue/src/PersistenceFailureConstants.js index ca8aa2db25..8eab3d9f4c 100644 --- a/platform/persistence/queue/src/PersistenceFailureConstants.js +++ b/platform/persistence/queue/src/PersistenceFailureConstants.js @@ -26,4 +26,4 @@ define({ OVERWRITE_KEY: "overwrite", TIMESTAMP_FORMAT: "YYYY-MM-DD HH:mm:ss\\Z", UNKNOWN_USER: "unknown user" -}); \ No newline at end of file +}); diff --git a/platform/persistence/queue/src/PersistenceFailureController.js b/platform/persistence/queue/src/PersistenceFailureController.js index 5d503a0f56..54c957b618 100644 --- a/platform/persistence/queue/src/PersistenceFailureController.js +++ b/platform/persistence/queue/src/PersistenceFailureController.js @@ -29,11 +29,14 @@ define( /** * Controller to support the template to be shown in the * dialog shown for persistence failures. + * @constructor + * @memberof platform/persistence/queue */ function PersistenceFailureController() { return { /** * Format a timestamp for display in the dialog. + * @memberof platform/persistence/queue.PersistenceFailureController# */ formatTimestamp: function (timestamp) { return moment.utc(timestamp) @@ -41,6 +44,7 @@ define( }, /** * Format a user name for display in the dialog. + * @memberof platform/persistence/queue.PersistenceFailureController# */ formatUsername: function (username) { return username || Constants.UNKNOWN_USER; @@ -50,4 +54,4 @@ define( return PersistenceFailureController; } -); \ No newline at end of file +); diff --git a/platform/persistence/queue/src/PersistenceFailureDialog.js b/platform/persistence/queue/src/PersistenceFailureDialog.js index 9f976e479c..7b048e7519 100644 --- a/platform/persistence/queue/src/PersistenceFailureDialog.js +++ b/platform/persistence/queue/src/PersistenceFailureDialog.js @@ -41,6 +41,8 @@ define( /** * Populates a `dialogModel` to pass to `dialogService.getUserChoise` * in order to choose between Overwrite and Cancel. + * @constructor + * @memberof platform/persistence/queue */ function PersistenceFailureDialog(failures) { var revisionErrors = [], @@ -72,4 +74,4 @@ define( return PersistenceFailureDialog; } -); \ No newline at end of file +); diff --git a/platform/persistence/queue/src/PersistenceFailureHandler.js b/platform/persistence/queue/src/PersistenceFailureHandler.js index 32e12efa66..cb2b039e23 100644 --- a/platform/persistence/queue/src/PersistenceFailureHandler.js +++ b/platform/persistence/queue/src/PersistenceFailureHandler.js @@ -121,6 +121,8 @@ define( * to overwrite/cancel as appropriate. * @param {Array} failures persistence failures, as prepared * by PersistenceQueueHandler + * @constructor + * @memberof platform/persistence/queue */ handle: handleFailures }; @@ -128,4 +130,4 @@ define( return PersistenceFailureHandler; } -); \ No newline at end of file +); diff --git a/platform/persistence/queue/src/PersistenceQueue.js b/platform/persistence/queue/src/PersistenceQueue.js index a54765f6c7..e704dafe71 100644 --- a/platform/persistence/queue/src/PersistenceQueue.js +++ b/platform/persistence/queue/src/PersistenceQueue.js @@ -50,6 +50,8 @@ define( * persistence when the queue is flushed * @param {number} [DELAY] optional; delay in milliseconds between * attempts to flush the queue + * @constructor + * @memberof platform/persistence/queue */ function PersistenceQueue( $q, @@ -74,4 +76,4 @@ define( return PersistenceQueue; } -); \ No newline at end of file +); diff --git a/platform/persistence/queue/src/PersistenceQueueHandler.js b/platform/persistence/queue/src/PersistenceQueueHandler.js index c57133beb8..2965edfc80 100644 --- a/platform/persistence/queue/src/PersistenceQueueHandler.js +++ b/platform/persistence/queue/src/PersistenceQueueHandler.js @@ -34,6 +34,8 @@ define( * @param $q Angular's $q, for promises * @param {PersistenceFailureHandler} handler to invoke in the event * that a persistence attempt fails. + * @constructor + * @memberof platform/persistence/queue */ function PersistenceQueueHandler($q, failureHandler) { @@ -98,6 +100,7 @@ define( * associated domain objects, in id->object pairs. * @param {PersistenceQueue} queue the persistence queue, * to requeue as necessary + * @memberof platform/persistence/queue.PersistenceQueueHandler# */ persist: function (persistences, domainObjects, queue) { var ids = Object.keys(persistences); @@ -108,4 +111,4 @@ define( return PersistenceQueueHandler; } -); \ No newline at end of file +); diff --git a/platform/persistence/queue/src/PersistenceQueueImpl.js b/platform/persistence/queue/src/PersistenceQueueImpl.js index b0e28becd5..d0c77ee057 100644 --- a/platform/persistence/queue/src/PersistenceQueueImpl.js +++ b/platform/persistence/queue/src/PersistenceQueueImpl.js @@ -41,6 +41,8 @@ define( * persistence when the queue is flushed * @param {number} [DELAY] optional; delay in milliseconds between * attempts to flush the queue + * @constructor + * @memberof platform/persistence/queue */ function PersistenceQueueImpl($q, $timeout, handler, DELAY) { var self, @@ -118,6 +120,7 @@ define( * @param {DomainObject} domainObject the domain object * @param {PersistenceCapability} persistence the object's * undecorated persistence capability + * @memberof platform/persistence/queue.PersistenceQueueImpl# */ put: function (domainObject, persistence) { var id = domainObject.getId(); @@ -132,4 +135,4 @@ define( return PersistenceQueueImpl; } -); \ No newline at end of file +); diff --git a/platform/persistence/queue/src/QueuingPersistenceCapability.js b/platform/persistence/queue/src/QueuingPersistenceCapability.js index 7eb98ba3a9..8fe006504a 100644 --- a/platform/persistence/queue/src/QueuingPersistenceCapability.js +++ b/platform/persistence/queue/src/QueuingPersistenceCapability.js @@ -34,6 +34,8 @@ define( * capability * @param {DomainObject} domainObject the domain object which exposes * the capability + * @constructor + * @memberof platform/persistence/queue */ function QueuingPersistenceCapability(queue, persistence, domainObject) { var queuingPersistence = Object.create(persistence); @@ -48,4 +50,4 @@ define( return QueuingPersistenceCapability; } -); \ No newline at end of file +); diff --git a/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js b/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js index 78643f2908..b60d316407 100644 --- a/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js +++ b/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js @@ -35,6 +35,7 @@ define( * will be handled in batches (allowing failure notification to * also be presented in batches.) * + * @memberof platform/persistence/queue * @constructor */ function QueuingPersistenceCapabilityDecorator( @@ -87,6 +88,7 @@ define( * @returns {Object.} all * capabilities known to be valid for this model, as * key-value pairs + * @memberof platform/persistence/queue.QueuingPersistenceCapabilityDecorator# */ getCapabilities: getCapabilities }; @@ -94,4 +96,4 @@ define( return QueuingPersistenceCapabilityDecorator; } -); \ No newline at end of file +); diff --git a/platform/policy/src/PolicyActionDecorator.js b/platform/policy/src/PolicyActionDecorator.js index da15828da9..9b86a2692f 100644 --- a/platform/policy/src/PolicyActionDecorator.js +++ b/platform/policy/src/PolicyActionDecorator.js @@ -31,6 +31,8 @@ define( * @param {PolicyService} policyService the service which provides * policy decisions * @param {ActionService} actionService the service to decorate + * @constructor + * @memberof platform/policy */ function PolicyActionDecorator(policyService, actionService) { return { @@ -40,6 +42,7 @@ define( * are deemed inapplicable by policy. * @param context the context in which the action will occur * @returns {Action[]} applicable actions + * @memberof platform/policy.PolicyActionDecorator# */ getActions: function (context) { // Check if an action is allowed by policy. @@ -55,4 +58,4 @@ define( return PolicyActionDecorator; } -); \ No newline at end of file +); diff --git a/platform/policy/src/PolicyProvider.js b/platform/policy/src/PolicyProvider.js index 50397b7f1f..228b4c47ef 100644 --- a/platform/policy/src/PolicyProvider.js +++ b/platform/policy/src/PolicyProvider.js @@ -30,6 +30,7 @@ define( * Provides an implementation of `policyService` which consults * various policy extensions to determine whether or not a specific * decision should be allowed. + * @memberof platform/policy * @constructor */ function PolicyProvider(policies) { @@ -74,6 +75,7 @@ define( * was disallowed (if its disallowed) * @returns {boolean} true if the decision is allowed, * otherwise false. + * @memberof platform/policy.PolicyProvider# */ allow: function (category, candidate, context, callback) { var policyList = policyMap[category] || [], @@ -103,4 +105,4 @@ define( return PolicyProvider; } -); \ No newline at end of file +); diff --git a/platform/policy/src/PolicyViewDecorator.js b/platform/policy/src/PolicyViewDecorator.js index 1fd6503649..d1570ffa4e 100644 --- a/platform/policy/src/PolicyViewDecorator.js +++ b/platform/policy/src/PolicyViewDecorator.js @@ -31,6 +31,8 @@ define( * @param {PolicyService} policyService the service which provides * policy decisions * @param {ViewService} viewService the service to decorate + * @constructor + * @memberof platform/policy */ function PolicyActionDecorator(policyService, viewService) { return { @@ -40,6 +42,7 @@ define( * are deemed inapplicable by policy. * @param {DomainObject} the domain object to view * @returns {View[]} applicable views + * @memberof platform/policy.PolicyViewDecorator# */ getViews: function (domainObject) { // Check if an action is allowed by policy. @@ -55,4 +58,4 @@ define( return PolicyActionDecorator; } -); \ No newline at end of file +); diff --git a/platform/representation/src/MCTInclude.js b/platform/representation/src/MCTInclude.js index 41a319e259..dc00c8b89d 100644 --- a/platform/representation/src/MCTInclude.js +++ b/platform/representation/src/MCTInclude.js @@ -49,6 +49,7 @@ define( * an output) and `parameters` is meant to be useful for * display parameterization (more like an input.) * + * @memberof platform/representation * @constructor * @param {TemplateDefinition[]} templates an array of * template extensions @@ -92,3 +93,4 @@ define( return MCTInclude; } ); + diff --git a/platform/representation/src/MCTRepresentation.js b/platform/representation/src/MCTRepresentation.js index 97194f12c3..1fba543d22 100644 --- a/platform/representation/src/MCTRepresentation.js +++ b/platform/representation/src/MCTRepresentation.js @@ -47,6 +47,7 @@ define( * * `parameters`, used to communicate display parameters to * the included template (e.g. title.) * + * @memberof platform/representation * @constructor * @param {RepresentationDefinition[]} representations an array of * representation extensions @@ -238,3 +239,4 @@ define( return MCTRepresentation; } ); + diff --git a/platform/representation/src/actions/ContextMenuAction.js b/platform/representation/src/actions/ContextMenuAction.js index 390531053e..9544f26ca9 100644 --- a/platform/representation/src/actions/ContextMenuAction.js +++ b/platform/representation/src/actions/ContextMenuAction.js @@ -39,6 +39,7 @@ define( /** * Launches a custom context menu for the domain object it contains. * + * @memberof platform/representation * @constructor * @param $compile Angular's $compile service * @param $document the current document @@ -113,4 +114,4 @@ define( return ContextMenuAction; } -); \ No newline at end of file +); diff --git a/platform/representation/src/gestures/ContextMenuGesture.js b/platform/representation/src/gestures/ContextMenuGesture.js index cfab655442..a0de0cce85 100644 --- a/platform/representation/src/gestures/ContextMenuGesture.js +++ b/platform/representation/src/gestures/ContextMenuGesture.js @@ -33,6 +33,7 @@ define( * Add listeners to a representation such that it calls the * context menu action for the domain object it contains. * + * @memberof platform/representation * @constructor * @param element the jqLite-wrapped element which should exhibit * the context mennu @@ -54,6 +55,7 @@ define( * Detach any event handlers associated with this gesture. * @method * @memberof ContextMenuGesture + * @memberof platform/representation.ContextMenuGesture# */ destroy: function () { element.off('contextmenu', stop); @@ -63,4 +65,4 @@ define( return ContextMenuGesture; } -); \ No newline at end of file +); diff --git a/platform/representation/src/gestures/DragGesture.js b/platform/representation/src/gestures/DragGesture.js index bb67732d0a..6a4dfb0d63 100644 --- a/platform/representation/src/gestures/DragGesture.js +++ b/platform/representation/src/gestures/DragGesture.js @@ -33,6 +33,7 @@ define( * Add event handlers to a representation such that it may be * dragged as the source for drag-drop composition. * + * @memberof platform/representation * @constructor * @param $log Angular's logging service * @param element the jqLite-wrapped element which should become @@ -108,6 +109,7 @@ define( * Detach any event handlers associated with this gesture. * @memberof DragGesture * @method + * @memberof platform/representation.DragGesture# */ destroy: function () { // Detach listener @@ -120,4 +122,4 @@ define( return DragGesture; } -); \ No newline at end of file +); diff --git a/platform/representation/src/gestures/DropGesture.js b/platform/representation/src/gestures/DropGesture.js index 25bee716cf..7afffc3c03 100644 --- a/platform/representation/src/gestures/DropGesture.js +++ b/platform/representation/src/gestures/DropGesture.js @@ -33,6 +33,7 @@ define( * A DropGesture adds and maintains event handlers upon an element * such that it may act as a drop target for drag-drop composition. + * @memberof platform/representation * @constructor * @param $q Angular's $q, for promise handling * @param element the jqLite-wrapped representation element @@ -124,6 +125,7 @@ define( return { /** * Detach any event handlers associated with this gesture. + * @memberof platform/representation.DropGesture# */ destroy: function () { element.off('dragover', dragOver); @@ -136,4 +138,4 @@ define( return DropGesture; } -); \ No newline at end of file +); diff --git a/platform/representation/src/gestures/GestureConstants.js b/platform/representation/src/gestures/GestureConstants.js index 2cdba87d0b..811e942c84 100644 --- a/platform/representation/src/gestures/GestureConstants.js +++ b/platform/representation/src/gestures/GestureConstants.js @@ -29,6 +29,8 @@ define({ * The string identifier for the data type used for drag-and-drop * composition of domain objects. (e.g. in event.dataTransfer.setData * calls.) + * @constructor + * @memberof platform/representation */ MCT_DRAG_TYPE: 'mct-domain-object-id', /** @@ -46,4 +48,4 @@ define({ * Identifier for drop events. */ MCT_DROP_EVENT: 'mctDrop' -}); \ No newline at end of file +}); diff --git a/platform/representation/src/gestures/GestureProvider.js b/platform/representation/src/gestures/GestureProvider.js index 797a00aa10..255c33a28f 100644 --- a/platform/representation/src/gestures/GestureProvider.js +++ b/platform/representation/src/gestures/GestureProvider.js @@ -40,6 +40,7 @@ define( * intermediary between these and the `mct-representation` directive * where they are used. * + * @memberof platform/representation * @constructor * @param {Gesture[]} gestures an array of all gestures which are * available as extensions @@ -100,6 +101,7 @@ define( * @return {{ destroy: function }} an object with a `destroy` * method which can (and should) be used when a * gesture should no longer be applied to an element. + * @memberof platform/representation.GestureProvider# */ attachGestures: attachGestures }; @@ -107,4 +109,4 @@ define( return GestureProvider; } -); \ No newline at end of file +); diff --git a/platform/representation/src/gestures/GestureRepresenter.js b/platform/representation/src/gestures/GestureRepresenter.js index 57084c102f..db74d923eb 100644 --- a/platform/representation/src/gestures/GestureRepresenter.js +++ b/platform/representation/src/gestures/GestureRepresenter.js @@ -37,6 +37,8 @@ define( * gestures * @param {Scope} scope the Angular scope for this representation * @param element the JQLite-wrapped mct-representation element + * @constructor + * @memberof platform/representation */ function GestureRepresenter(gestureService, scope, element) { var gestureHandle; @@ -69,10 +71,12 @@ define( * definition of the representation in use * @param {DomainObject} domainObject the domain object * being represented + * @memberof platform/representation.GestureRepresenter# */ represent: represent, /** * Release any resources associated with this representer. + * @memberof platform/representation.GestureRepresenter# */ destroy: destroy }; @@ -80,4 +84,4 @@ define( return GestureRepresenter; } -); \ No newline at end of file +); diff --git a/platform/representation/src/services/DndService.js b/platform/representation/src/services/DndService.js index 0497c2bbfd..b8c4ae7bfe 100644 --- a/platform/representation/src/services/DndService.js +++ b/platform/representation/src/services/DndService.js @@ -32,6 +32,7 @@ define( * * Storing arbitrary JavaScript objects (not just strings.) * * Allowing inspection of dragged objects during `dragover` events, * etc. (which cannot be done in Chrome for security reasons) + * @memberof platform/representation * @constructor * @param $log Angular's $log service */ @@ -43,6 +44,7 @@ define( * Set drag data associated with a given type. * @param {string} key the type's identiifer * @param {*} value the data being dragged + * @memberof platform/representation.DndService# */ setData: function (key, value) { $log.debug("Setting drag data for " + key); @@ -51,6 +53,7 @@ define( /** * Get drag data associated with a given type. * @returns {*} the data being dragged + * @memberof platform/representation.DndService# */ getData: function (key) { return data[key]; @@ -58,6 +61,7 @@ define( /** * Remove data associated with active drags. * @param {string} key the type to remove + * @memberof platform/representation.DndService# */ removeData: function (key) { $log.debug("Clearing drag data for " + key); @@ -68,4 +72,4 @@ define( return DndService; } -); \ No newline at end of file +); diff --git a/platform/telemetry/src/TelemetryAggregator.js b/platform/telemetry/src/TelemetryAggregator.js index 11c2802e52..8a30e4bc2f 100644 --- a/platform/telemetry/src/TelemetryAggregator.js +++ b/platform/telemetry/src/TelemetryAggregator.js @@ -33,6 +33,7 @@ define( * A telemetry aggregator makes many telemetry providers * appear as one. * + * @memberof platform/telemetry * @constructor */ function TelemetryAggregator($q, telemetryProviders) { @@ -84,6 +85,7 @@ define( * @returns {Promise} a promise for telemetry data * which may (or may not, depending on * availability) satisfy the requests + * @memberof platform/telemetry.TelemetryAggregator# */ requestTelemetry: requestTelemetry, /** @@ -100,6 +102,7 @@ define( * requests to be subscribed upon * @returns {Function} a function which can be called * to unsubscribe + * @memberof platform/telemetry.TelemetryAggregator# */ subscribe: subscribe }; @@ -107,4 +110,4 @@ define( return TelemetryAggregator; } -); \ No newline at end of file +); diff --git a/platform/telemetry/src/TelemetryCapability.js b/platform/telemetry/src/TelemetryCapability.js index 473aafcdb9..041379e497 100644 --- a/platform/telemetry/src/TelemetryCapability.js +++ b/platform/telemetry/src/TelemetryCapability.js @@ -41,6 +41,7 @@ define( * for a specific object, and for unwrapping the response (to get * at the specific data which is appropriate to the domain object.) * + * @memberof platform/telemetry * @constructor */ function TelemetryCapability($injector, $q, $log, domainObject) { @@ -151,12 +152,14 @@ define( * specific request * @returns {Promise} a promise for the resulting telemetry * object + * @memberof platform/telemetry.TelemetryCapability# */ requestData: requestTelemetry, /** * Get metadata about this domain object's associated * telemetry. + * @memberof platform/telemetry.TelemetryCapability# */ getMetadata: function () { // metadata just looks like a request, @@ -174,6 +177,7 @@ define( * containing the data will be given as an argument. * @param {TelemetryRequest} [request] parameters for the * subscription request + * @memberof platform/telemetry.TelemetryCapability# */ subscribe: subscribe }; @@ -191,3 +195,4 @@ define( return TelemetryCapability; } ); + diff --git a/platform/telemetry/src/TelemetryController.js b/platform/telemetry/src/TelemetryController.js index 504ec2ec4a..3334baf48d 100644 --- a/platform/telemetry/src/TelemetryController.js +++ b/platform/telemetry/src/TelemetryController.js @@ -34,6 +34,7 @@ define( * which need to issue requests for telemetry data and use the * results * + * @memberof platform/telemetry * @constructor */ function TelemetryController($scope, $q, $timeout, $log) { @@ -314,6 +315,7 @@ define( * given index will correspond to the telemetry-providing * domain object at the same index. * @returns {Array} an array of metadata objects + * @memberof platform/telemetry.TelemetryController# */ getMetadata: function () { return self.metadatas; @@ -328,6 +330,7 @@ define( * given index will correspond to the telemetry-providing * domain object at the same index. * @returns {DomainObject[]} an array of metadata objects + * @memberof platform/telemetry.TelemetryController# */ getTelemetryObjects: function () { return self.telemetryObjects; @@ -345,6 +348,7 @@ define( * response at a given index will correspond to the * telemetry-providing domain object at the same index. * @returns {Array} an array of responses + * @memberof platform/telemetry.TelemetryController# */ getResponse: function getResponse(arg) { var id = arg && (typeof arg === 'string' ? @@ -364,6 +368,7 @@ define( * show user feedback, such as a wait spinner. * * @returns {boolean} true if the request is still outstanding + * @memberof platform/telemetry.TelemetryController# */ isRequestPending: function () { return self.pending > 0; @@ -372,6 +377,7 @@ define( * Issue a new data request. This will change the * request parameters that are passed along to all * telemetry capabilities managed by this controller. + * @memberof platform/telemetry.TelemetryController# */ requestData: function (request) { self.request = request || {}; @@ -382,6 +388,7 @@ define( * perform its polling activity. * @param {number} durationMillis the interval at * which to poll, in milliseconds + * @memberof platform/telemetry.TelemetryController# */ setRefreshInterval: function (durationMillis) { self.interval = durationMillis; @@ -392,4 +399,4 @@ define( return TelemetryController; } -); \ No newline at end of file +); diff --git a/platform/telemetry/src/TelemetryDelegator.js b/platform/telemetry/src/TelemetryDelegator.js index 50fee40ad1..865503154d 100644 --- a/platform/telemetry/src/TelemetryDelegator.js +++ b/platform/telemetry/src/TelemetryDelegator.js @@ -29,6 +29,8 @@ define( /** * Used to handle telemetry delegation associated with a * given domain object. + * @constructor + * @memberof platform/telemetry */ function TelemetryDelegator($q) { return { @@ -38,6 +40,7 @@ define( * or the objects it delegates) * @returns {Promise.} domain objects with * a telemetry capability + * @memberof platform/telemetry.TelemetryDelegator# */ promiseTelemetryObjects: function (domainObject) { // If object has been cleared, there are no relevant @@ -63,4 +66,4 @@ define( return TelemetryDelegator; } -); \ No newline at end of file +); diff --git a/platform/telemetry/src/TelemetryFormatter.js b/platform/telemetry/src/TelemetryFormatter.js index 853db642d7..277ad0ca24 100644 --- a/platform/telemetry/src/TelemetryFormatter.js +++ b/platform/telemetry/src/TelemetryFormatter.js @@ -35,6 +35,7 @@ define( * The TelemetryFormatter is responsible for formatting (as text * for display) values along either the domain (usually time) or * the range (usually value) of a data series. + * @memberof platform/telemetry * @constructor */ function TelemetryFormatter() { @@ -56,6 +57,7 @@ define( * be treated as a standard timestamp. * @returns {string} a textual representation of the * data and time, suitable for display. + * @memberof platform/telemetry.TelemetryFormatter# */ formatDomainValue: formatDomainValue, /** @@ -66,6 +68,7 @@ define( * be treated as a numeric value. * @returns {string} a textual representation of the * value, suitable for display. + * @memberof platform/telemetry.TelemetryFormatter# */ formatRangeValue: formatRangeValue }; @@ -73,4 +76,4 @@ define( return TelemetryFormatter; } -); \ No newline at end of file +); diff --git a/platform/telemetry/src/TelemetryHandle.js b/platform/telemetry/src/TelemetryHandle.js index e93b606aeb..145edfc5d7 100644 --- a/platform/telemetry/src/TelemetryHandle.js +++ b/platform/telemetry/src/TelemetryHandle.js @@ -34,6 +34,8 @@ define( * @param $q Angular's $q, for promises * @param {TelemetrySubscription} subscription a subscription * to supplied telemetry + * @constructor + * @memberof platform/telemetry */ function TelemetryHandle($q, subscription) { var seriesMap = {}, @@ -67,6 +69,7 @@ define( * data associated with it * @return {TelemetrySeries} the most recent telemetry series * (or undefined if there is not one) + * @memberof platform/telemetry.TelemetryHandle# */ self.getSeries = function (domainObject) { var id = domainObject.getId(); @@ -81,6 +84,7 @@ define( * @param {Function} [callback] a callback that will be * invoked as new data becomes available, with the * domain object for which new data is available. + * @memberof platform/telemetry.TelemetryHandle# */ self.request = function (request, callback) { // Issue (and handle) the new request from this object @@ -109,4 +113,4 @@ define( return TelemetryHandle; } -); \ No newline at end of file +); diff --git a/platform/telemetry/src/TelemetryHandler.js b/platform/telemetry/src/TelemetryHandler.js index 9b56bbc41e..f600f52cb7 100644 --- a/platform/telemetry/src/TelemetryHandler.js +++ b/platform/telemetry/src/TelemetryHandler.js @@ -31,6 +31,7 @@ define( * A TelemetryRequester provides an easy interface to request * telemetry associated with a set of domain objects. * + * @memberof platform/telemetry * @constructor * @param $q Angular's $q */ @@ -51,4 +52,4 @@ define( return TelemetryHandler; } -); \ No newline at end of file +); diff --git a/platform/telemetry/src/TelemetryQueue.js b/platform/telemetry/src/TelemetryQueue.js index cf82d08ff8..b5da77d717 100644 --- a/platform/telemetry/src/TelemetryQueue.js +++ b/platform/telemetry/src/TelemetryQueue.js @@ -32,6 +32,7 @@ define( * a queued series of large objects, ensuring that no value is * overwritten (but consolidated non-overlapping keys into single * objects.) + * @memberof platform/telemetry * @constructor */ function TelemetryQueue() { @@ -102,6 +103,7 @@ define( /** * Check if any value groups remain in this pool. * @return {boolean} true if value groups remain + * @memberof platform/telemetry.TelemetryQueue# */ isEmpty: function () { return queue.length < 1; @@ -112,6 +114,7 @@ define( * where keys and values correspond to the arguments * given to previous put functions. * @return {object} key-value pairs + * @memberof platform/telemetry.TelemetryQueue# */ poll: function () { // Decrement counts for the object that will be popped @@ -122,6 +125,7 @@ define( * Put a key-value pair into the pool. * @param {string} key the key to store the value under * @param {*} value the value to store + * @memberof platform/telemetry.TelemetryQueue# */ put: function (key, value) { getFreeObject(key)[key] = value; @@ -131,4 +135,4 @@ define( return TelemetryQueue; } -); \ No newline at end of file +); diff --git a/platform/telemetry/src/TelemetrySubscriber.js b/platform/telemetry/src/TelemetrySubscriber.js index e106968828..7f8a6fd58e 100644 --- a/platform/telemetry/src/TelemetrySubscriber.js +++ b/platform/telemetry/src/TelemetrySubscriber.js @@ -38,6 +38,7 @@ define( * (e.g. for telemetry panels) as well as latest-value * extraction. * + * @memberof platform/telemetry * @constructor * @param $q Angular's $q * @param $timeout Angular's $timeout @@ -62,6 +63,7 @@ define( * * @method * @memberof TelemetrySubscriber + * @memberof platform/telemetry.TelemetrySubscriber# */ subscribe: function (domainObject, callback, lossless) { return new TelemetrySubscription( @@ -77,4 +79,4 @@ define( return TelemetrySubscriber; } -); \ No newline at end of file +); diff --git a/platform/telemetry/src/TelemetrySubscription.js b/platform/telemetry/src/TelemetrySubscription.js index 4f7b8379d1..b4ecdd4770 100644 --- a/platform/telemetry/src/TelemetrySubscription.js +++ b/platform/telemetry/src/TelemetrySubscription.js @@ -38,6 +38,7 @@ define( * (e.g. for telemetry panels) as well as latest-value * extraction. * + * @memberof platform/telemetry * @constructor * @param $q Angular's $q * @param $timeout Angular's $timeout @@ -227,6 +228,7 @@ define( * with this object. * @method * @memberof TelemetrySubscription + * @memberof platform/telemetry.TelemetrySubscription# */ unsubscribe: function () { if (unlistenToMutation) { @@ -247,6 +249,7 @@ define( * @returns the most recent domain value observed * @method * @memberof TelemetrySubscription + * @memberof platform/telemetry.TelemetrySubscription# */ getDomainValue: function (domainObject) { var id = domainObject.getId(); @@ -265,6 +268,7 @@ define( * @returns the most recent range value observed * @method * @memberof TelemetrySubscription + * @memberof platform/telemetry.TelemetrySubscription# */ getRangeValue: function (domainObject) { var id = domainObject.getId(); @@ -275,6 +279,7 @@ define( * * @param {DomainObject} domainObject the object of interest * @returns {TelemetryDatum} the most recent datum + * @memberof platform/telemetry.TelemetrySubscription# */ getDatum: function (domainObject) { var id = domainObject.getId(); @@ -294,6 +299,7 @@ define( * @returns {DomainObject[]} all subscribed-to domain objects * @method * @memberof TelemetrySubscription + * @memberof platform/telemetry.TelemetrySubscription# */ getTelemetryObjects: function () { return telemetryObjects; @@ -309,6 +315,7 @@ define( * given index will correspond to the telemetry-providing * domain object at the same index. * @returns {Array} an array of metadata objects + * @memberof platform/telemetry.TelemetrySubscription# */ getMetadata: function () { return metadatas; @@ -318,6 +325,7 @@ define( * associated with this subscription. * @returns {Promise.} a promise for * telemetry-providing objects + * @memberof platform/telemetry.TelemetrySubscription# */ promiseTelemetryObjects: function () { // Unsubscribe promise is available after objects @@ -331,3 +339,4 @@ define( } ); + diff --git a/platform/telemetry/src/TelemetryTable.js b/platform/telemetry/src/TelemetryTable.js index d70febed2f..c992a3ec18 100644 --- a/platform/telemetry/src/TelemetryTable.js +++ b/platform/telemetry/src/TelemetryTable.js @@ -32,6 +32,7 @@ define( * one large object, overwriting new values as necessary. Stands * in contrast to the TelemetryQueue, which will avoid overwriting * values. + * @memberof platform/telemetry * @constructor */ function TelemetryTable() { @@ -41,6 +42,7 @@ define( /** * Check if any value groups remain in this pool. * @return {boolean} true if value groups remain + * @memberof platform/telemetry.TelemetryTable# */ isEmpty: function () { return !table; @@ -51,6 +53,7 @@ define( * where keys and values correspond to the arguments * given to previous put functions. * @return {object} key-value pairs + * @memberof platform/telemetry.TelemetryTable# */ poll: function () { var t = table; @@ -61,6 +64,7 @@ define( * Put a key-value pair into the pool. * @param {string} key the key to store the value under * @param {*} value the value to store + * @memberof platform/telemetry.TelemetryTable# */ put: function (key, value) { table = table || {}; @@ -71,4 +75,4 @@ define( return TelemetryTable; } -); \ No newline at end of file +); From eaaa1a19caaa32b45ce95dbaa051b55714eebb49 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 7 Aug 2015 11:55:38 -0700 Subject: [PATCH 29/84] [JSDoc] Remove obsolete module references WTD-1482 --- platform/commonUI/browse/src/creation/CreateWizard.js | 7 ------- platform/commonUI/edit/src/actions/PropertiesDialog.js | 7 ------- .../edit/src/objects/EditableDomainObjectCache.js | 5 +---- platform/core/src/types/TypeImpl.js | 9 --------- platform/core/src/types/TypeProperty.js | 7 ------- platform/core/src/types/TypePropertyConversion.js | 6 ------ platform/features/events/src/EventListPopulator.js | 5 ++++- platform/features/plot/src/elements/PlotLine.js | 9 +++++++-- platform/representation/src/gestures/GestureConstants.js | 8 ++++++-- 9 files changed, 18 insertions(+), 45 deletions(-) diff --git a/platform/commonUI/browse/src/creation/CreateWizard.js b/platform/commonUI/browse/src/creation/CreateWizard.js index a0e21b102d..bd013f5acc 100644 --- a/platform/commonUI/browse/src/creation/CreateWizard.js +++ b/platform/commonUI/browse/src/creation/CreateWizard.js @@ -21,12 +21,6 @@ *****************************************************************************/ /*global define*/ -/** - * Defines the CreateWizard, used by the CreateAction to - * populate the form shown in dialog based on the created type. - * - * @module core/action/create-wizard - */ define( function () { 'use strict'; @@ -39,7 +33,6 @@ define( * the initial parent for the created object, in the dialog * @memberof platform/commonUI/browse * @constructor - * @memberof module:core/action/create-wizard */ function CreateWizard(type, parent, policyService) { var model = type.getInitialModel(), diff --git a/platform/commonUI/edit/src/actions/PropertiesDialog.js b/platform/commonUI/edit/src/actions/PropertiesDialog.js index 9d7c6ddcb4..a4e3ba1f9f 100644 --- a/platform/commonUI/edit/src/actions/PropertiesDialog.js +++ b/platform/commonUI/edit/src/actions/PropertiesDialog.js @@ -21,12 +21,6 @@ *****************************************************************************/ /*global define*/ -/** - * Defines the PropertiesDialog, used by the PropertiesAction to - * populate the form shown in dialog based on the created type. - * - * @module common/actions/properties-dialog - */ define( function () { 'use strict'; @@ -39,7 +33,6 @@ define( * @param {DomainObject} the object for which properties will be set * @memberof platform/commonUI/edit * @constructor - * @memberof module:common/actions/properties-dialog */ function PropertiesDialog(type, model) { var properties = type.getProperties(); diff --git a/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js b/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js index 9d69a9e364..9fc47ef790 100644 --- a/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js +++ b/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js @@ -22,7 +22,7 @@ /*global define*/ -/** +/* * An editable domain object cache stores domain objects that have been * made editable, in a group that can be saved all-at-once. This supports * Edit mode, which is launched for a specific object but may contain @@ -32,8 +32,6 @@ * to ensure that changes made while in edit mode do not propagate up * to the objects used in browse mode (or to persistence) until the user * initiates a Save. - * - * @module editor/object/editable-domain-object-cache */ define( ["./EditableModelCache"], @@ -53,7 +51,6 @@ define( * @param $q Angular's $q, for promise handling * @memberof platform/commonUI/edit * @constructor - * @memberof module:editor/object/editable-domain-object-cache */ function EditableDomainObjectCache(EditableDomainObject, $q) { var cache = new EditableModelCache(), diff --git a/platform/core/src/types/TypeImpl.js b/platform/core/src/types/TypeImpl.js index 9e5a52d37f..526675e611 100644 --- a/platform/core/src/types/TypeImpl.js +++ b/platform/core/src/types/TypeImpl.js @@ -21,14 +21,6 @@ *****************************************************************************/ /*global define*/ -/** - * Type implementation. Defines a type object which wraps a - * type definition and exposes useful methods for inspecting - * that type and understanding its relationship to other - * types. - * - * @module core/type/type-impl - */ define( ['./TypeProperty'], function (TypeProperty) { @@ -41,7 +33,6 @@ define( * @param {TypeDefinition} typeDef an object containing * key-value pairs describing a type and its * relationship to other types. - * @memberof module:core/type/type-impl * @constructor * @memberof platform/core */ diff --git a/platform/core/src/types/TypeProperty.js b/platform/core/src/types/TypeProperty.js index fb58199c06..2b1cfea0ac 100644 --- a/platform/core/src/types/TypeProperty.js +++ b/platform/core/src/types/TypeProperty.js @@ -21,12 +21,6 @@ *****************************************************************************/ /*global define*/ -/** - * Type property. Defines a mutable or displayable property - * associated with objects of a given type. - * - * @module core/type/type-property - */ define( ['./TypePropertyConversion'], function (TypePropertyConversion) { @@ -38,7 +32,6 @@ define( * * @memberof platform/core * @constructor - * @memberof module:core/type/type-property */ function TypeProperty(propertyDefinition) { // Load an appropriate conversion diff --git a/platform/core/src/types/TypePropertyConversion.js b/platform/core/src/types/TypePropertyConversion.js index d390e74108..56ce1cc5e5 100644 --- a/platform/core/src/types/TypePropertyConversion.js +++ b/platform/core/src/types/TypePropertyConversion.js @@ -21,12 +21,6 @@ *****************************************************************************/ /*global define*/ -/** - * Defines type property conversions, used to convert values from - * a domain object model to values displayable in a form, and - * vice versa. - * @module core/type/type-property-conversion - */ define( function () { 'use strict'; diff --git a/platform/features/events/src/EventListPopulator.js b/platform/features/events/src/EventListPopulator.js index d4e7429d28..f9581e0890 100644 --- a/platform/features/events/src/EventListPopulator.js +++ b/platform/features/events/src/EventListPopulator.js @@ -31,10 +31,11 @@ define( * values which should appear within columns of a event list * view, based on received telemetry data. * @constructor + * @memberof platform/features/events * @param {Column[]} columns the columns to be populated */ function EventListPopulator(columns) { - /** + /* * Look up the most recent values from a set of data objects. * Returns an array of objects in the order in which data * should be displayed; each element is an object with @@ -116,6 +117,7 @@ define( /** * Get the text which should appear in headers for the * provided columns. + * @memberof platform/features/events.EventListPopulator * @returns {string[]} column headers */ getHeaders: function () { @@ -130,6 +132,7 @@ define( * provided the data sets; these should match * index-to-index with the `datas` argument * @param {number} count the number of rows to populate + * @memberof platform/features/events.EventListPopulator * @returns {string[][]} an array of rows, each of which * is an array of values which should appear * in that row diff --git a/platform/features/plot/src/elements/PlotLine.js b/platform/features/plot/src/elements/PlotLine.js index b9d2df3588..ae9b3b56b3 100644 --- a/platform/features/plot/src/elements/PlotLine.js +++ b/platform/features/plot/src/elements/PlotLine.js @@ -27,6 +27,11 @@ define( "use strict"; + /** + * Represents a single line or trace of a plot. + * @param {{PlotLineBuffer}} buffer the plot buffer + * @constructor + */ function PlotLine(buffer) { // Insert a time-windowed data series into the buffer @@ -70,8 +75,7 @@ define( * Add a point to this plot line. * @param {number} domainValue the domain value * @param {number} rangeValue the range value - * @constructor - * @memberof platform/features/plot + * @memberof platform/features/plot.PlotLine */ addPoint: function (domainValue, rangeValue) { var index; @@ -100,6 +104,7 @@ define( * to use when looking up data from this series * @param {string} [range] the key indicating which range * to use when looking up data from this series + * @memberof platform/features/plot.PlotLine */ addSeries: function (series, domain, range) { // Should try to add via insertion if a diff --git a/platform/representation/src/gestures/GestureConstants.js b/platform/representation/src/gestures/GestureConstants.js index 811e942c84..d41fd1b89b 100644 --- a/platform/representation/src/gestures/GestureConstants.js +++ b/platform/representation/src/gestures/GestureConstants.js @@ -22,7 +22,8 @@ /*global define,Promise*/ /** - * Module defining GestureConstants. Created by vwoeltje on 11/17/14. + * Constants used by domain object gestures. + * @class platform/representation.GestureConstants */ define({ /** @@ -30,22 +31,25 @@ define({ * composition of domain objects. (e.g. in event.dataTransfer.setData * calls.) * @constructor - * @memberof platform/representation + * @memberof platform/representation.GestureConstants */ MCT_DRAG_TYPE: 'mct-domain-object-id', /** * The string identifier for the data type used for drag-and-drop * composition of domain objects, by object instance (passed through * the dndService) + * @memberof platform/representation.GestureConstants */ MCT_EXTENDED_DRAG_TYPE: 'mct-domain-object', /** * An estimate for the dimensions of a context menu, used for * positioning. + * @memberof platform/representation.GestureConstants */ MCT_MENU_DIMENSIONS: [ 170, 200 ], /** * Identifier for drop events. + * @memberof platform/representation.GestureConstants */ MCT_DROP_EVENT: 'mctDrop' }); From 31eb366e7fbaeae15172d999f4721308204ada2e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 7 Aug 2015 12:13:15 -0700 Subject: [PATCH 30/84] [JSDoc] Add namespace docs WTD-1482. --- platform/commonUI/about/src/AboutController.js | 5 +++++ platform/commonUI/browse/src/BrowseController.js | 3 ++- platform/commonUI/dialog/src/DialogService.js | 4 +++- platform/commonUI/edit/src/controllers/EditController.js | 3 ++- platform/commonUI/general/src/StyleSheetLoader.js | 5 +++++ platform/commonUI/inspect/src/InfoConstants.js | 7 +++++++ platform/containment/src/CompositionPolicy.js | 5 +++++ platform/core/src/objects/DomainObjectProvider.js | 4 +++- platform/entanglement/src/services/LocationService.js | 5 +++++ platform/execution/src/WorkerService.js | 6 ++++++ platform/features/events/src/EventListController.js | 7 ++++++- .../features/imagery/src/controllers/ImageryController.js | 4 ++++ platform/features/layout/src/LayoutController.js | 5 +++++ platform/features/pages/src/EmbeddedPageController.js | 5 +++++ platform/features/plot/src/PlotController.js | 3 ++- platform/features/scrolling/src/ScrollingListController.js | 3 ++- platform/forms/src/MCTForm.js | 4 +++- platform/framework/src/Main.js | 5 +++++ .../persistence/cache/src/CachingPersistenceDecorator.js | 5 +++++ platform/persistence/couch/src/CouchPersistenceProvider.js | 5 +++++ .../persistence/elastic/src/ElasticPersistenceProvider.js | 5 +++++ .../queue/src/QueuingPersistenceCapabilityDecorator.js | 5 ++++- platform/policy/src/PolicyProvider.js | 4 ++++ platform/representation/src/MCTRepresentation.js | 4 +++- platform/representation/src/gestures/GestureConstants.js | 1 - platform/telemetry/src/TelemetryAggregator.js | 4 +++- 26 files changed, 104 insertions(+), 12 deletions(-) diff --git a/platform/commonUI/about/src/AboutController.js b/platform/commonUI/about/src/AboutController.js index b2fce0bdfd..c40df7e824 100644 --- a/platform/commonUI/about/src/AboutController.js +++ b/platform/commonUI/about/src/AboutController.js @@ -21,6 +21,11 @@ *****************************************************************************/ /*global define*/ + +/** + * Implements Open MCT Web's About dialog. + * @namespace platform/commonUI/about + */ define( [], function () { diff --git a/platform/commonUI/browse/src/BrowseController.js b/platform/commonUI/browse/src/BrowseController.js index 7d65db507d..b10e0a598a 100644 --- a/platform/commonUI/browse/src/BrowseController.js +++ b/platform/commonUI/browse/src/BrowseController.js @@ -22,7 +22,8 @@ /*global define,Promise*/ /** - * Module defining BrowseController. Created by vwoeltje on 11/7/14. + * This bundle implements Browse mode. + * @namespace platform/commonUI/browse */ define( [], diff --git a/platform/commonUI/dialog/src/DialogService.js b/platform/commonUI/dialog/src/DialogService.js index a435d287e5..e23d0d7c8e 100644 --- a/platform/commonUI/dialog/src/DialogService.js +++ b/platform/commonUI/dialog/src/DialogService.js @@ -22,7 +22,9 @@ /*global define*/ /** - * Module defining DialogService. Created by vwoeltje on 11/10/14. + * This bundle implements the dialog service, which can be used to + * launch dialogs for user input & notifications. + * @namespace platform/commonUI/dialog */ define( [], diff --git a/platform/commonUI/edit/src/controllers/EditController.js b/platform/commonUI/edit/src/controllers/EditController.js index f0f2822207..9b0c228ac3 100644 --- a/platform/commonUI/edit/src/controllers/EditController.js +++ b/platform/commonUI/edit/src/controllers/EditController.js @@ -22,7 +22,8 @@ /*global define,Promise*/ /** - * Module defining EditController. Created by vwoeltje on 11/14/14. + * This bundle implements Edit mode. + * @namespace platform/commonUI/edit */ define( ["../objects/EditableDomainObject"], diff --git a/platform/commonUI/general/src/StyleSheetLoader.js b/platform/commonUI/general/src/StyleSheetLoader.js index fe535df888..19c0ffc291 100644 --- a/platform/commonUI/general/src/StyleSheetLoader.js +++ b/platform/commonUI/general/src/StyleSheetLoader.js @@ -21,6 +21,11 @@ *****************************************************************************/ /*global define*/ +/** + * This bundle provides various general-purpose UI elements, including + * platform styling. + * @namespace platform/commonUI/general + */ define( [], function () { diff --git a/platform/commonUI/inspect/src/InfoConstants.js b/platform/commonUI/inspect/src/InfoConstants.js index c5886cba92..4927de870f 100644 --- a/platform/commonUI/inspect/src/InfoConstants.js +++ b/platform/commonUI/inspect/src/InfoConstants.js @@ -20,6 +20,13 @@ * at runtime from the About dialog for additional information. *****************************************************************************/ /*global define*/ + +/** + * This bundle provides support for object inspection (specifically, metadata + * show in bubbles on hover.) + * @namespace platform/commonUI/inspect + */ + define({ BUBBLE_TEMPLATE: " Date: Fri, 7 Aug 2015 12:14:40 -0700 Subject: [PATCH 31/84] [JSDoc] Remove obsolete module references WTD-1482. --- platform/commonUI/edit/src/actions/RemoveAction.js | 1 - platform/core/src/types/TypeProvider.js | 1 - 2 files changed, 2 deletions(-) diff --git a/platform/commonUI/edit/src/actions/RemoveAction.js b/platform/commonUI/edit/src/actions/RemoveAction.js index b19dff31a2..9c64da9b7a 100644 --- a/platform/commonUI/edit/src/actions/RemoveAction.js +++ b/platform/commonUI/edit/src/actions/RemoveAction.js @@ -39,7 +39,6 @@ define( * @param {ActionContext} context the context in which this action is performed * @memberof platform/commonUI/edit * @constructor - * @memberof module:editor/actions/remove-action */ function RemoveAction($q, context) { var object = (context || {}).domainObject; diff --git a/platform/core/src/types/TypeProvider.js b/platform/core/src/types/TypeProvider.js index f321cdc0ef..a55c834da8 100644 --- a/platform/core/src/types/TypeProvider.js +++ b/platform/core/src/types/TypeProvider.js @@ -57,7 +57,6 @@ define( * definitions for this type. * @memberof platform/core * @constructor - * @memberof module:core/type/type-provider */ function TypeProvider(types) { var rawTypeDefinitions = types, From 23f18c799d2a7598ac4e0853c65de89f8a6acd1b Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 7 Aug 2015 12:19:32 -0700 Subject: [PATCH 32/84] [JSDoc] Enable markdown processing WTD-1482. --- jsdoc.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/jsdoc.json b/jsdoc.json index 4164aa3577..4f4ee0afd4 100644 --- a/jsdoc.json +++ b/jsdoc.json @@ -5,5 +5,8 @@ ], "includePattern": "platform/.+\\.js$", "excludePattern": ".+\\Spec\\.js$|lib/.+" - } + }, + "plugins": [ + "plugins/markdown" + ] } \ No newline at end of file From 0b9b9363686d2fd1bc9e5a9732312a0a0857f99e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 7 Aug 2015 13:35:07 -0700 Subject: [PATCH 33/84] [JSDoc] Add missing class doc WTD-1482. --- .../persistence/queue/src/PersistenceFailureHandler.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/platform/persistence/queue/src/PersistenceFailureHandler.js b/platform/persistence/queue/src/PersistenceFailureHandler.js index cb2b039e23..45f4360662 100644 --- a/platform/persistence/queue/src/PersistenceFailureHandler.js +++ b/platform/persistence/queue/src/PersistenceFailureHandler.js @@ -26,6 +26,13 @@ define( function (PersistenceFailureDialog, PersistenceFailureConstants) { "use strict"; + /** + * Handle failures to persist domain object models. + * @param $q Angular's `$q` + * @param {DialogService} dialogService the dialog service + * @constructor + * @memberof platform/persistence/queue + */ function PersistenceFailureHandler($q, dialogService) { // Refresh revision information for the domain object associated // with this persistence failure @@ -121,8 +128,7 @@ define( * to overwrite/cancel as appropriate. * @param {Array} failures persistence failures, as prepared * by PersistenceQueueHandler - * @constructor - * @memberof platform/persistence/queue + * @memberof platform/persistence/queue.PersistenceFailureHandler# */ handle: handleFailures }; From 78146d97f8b81a41b4a99d28f353bde24ae25010 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 10 Aug 2015 10:19:02 -0700 Subject: [PATCH 34/84] [Code Style] Use prototypes in About bundle WTD-1482. --- .../commonUI/about/src/AboutController.js | 44 +++++++++---------- .../commonUI/about/src/LicenseController.js | 20 ++++----- platform/commonUI/about/src/LogoController.js | 20 ++++----- 3 files changed, 41 insertions(+), 43 deletions(-) diff --git a/platform/commonUI/about/src/AboutController.js b/platform/commonUI/about/src/AboutController.js index c40df7e824..dffd9b9471 100644 --- a/platform/commonUI/about/src/AboutController.js +++ b/platform/commonUI/about/src/AboutController.js @@ -41,31 +41,29 @@ define( * @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 - * @memberof platform/commonUI/about.AboutController# - */ - versions: function () { - return versions; - }, - /** - * Open a new window (or tab, depending on browser - * configuration) containing open source licenses. - * @memberof AboutController# - * @memberof platform/commonUI/about.AboutController# - */ - openLicenses: function () { - // Open a new browser window at the licenses route - $window.open("#/licenses"); - } - }; + this.versionDefinitions = versions; + this.$window = $window; } + /** + * 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. + * @returns {object[]} version information + */ + AboutController.prototype.versions = function () { + return this.versionDefinitions; + }; + + /** + * Open a new window (or tab, depending on browser + * configuration) containing open source licenses. + */ + AboutController.prototype.openLicenses = function () { + // Open a new browser window at the licenses route + this.$window.open("#/licenses"); + }; + return AboutController; } ); diff --git a/platform/commonUI/about/src/LicenseController.js b/platform/commonUI/about/src/LicenseController.js index a2e7463b37..740124641f 100644 --- a/platform/commonUI/about/src/LicenseController.js +++ b/platform/commonUI/about/src/LicenseController.js @@ -33,18 +33,18 @@ define( * @constructor */ function LicenseController(licenses) { - return { - /** - * Get license information. - * @returns {Array} license extensions - * @memberof platform/commonUI/about.LicenseController# - */ - licenses: function () { - return licenses; - } - }; + this.licenseDefinitions = licenses; } + /** + * Get license information. + * @returns {Array} license extensions + * @memberof platform/commonUI/about.LicenseController# + */ + LicenseController.prototype.licenses = function () { + return this.licenseDefinitions; + }; + return LicenseController; } ); diff --git a/platform/commonUI/about/src/LogoController.js b/platform/commonUI/about/src/LogoController.js index f151900df5..85909a0552 100644 --- a/platform/commonUI/about/src/LogoController.js +++ b/platform/commonUI/about/src/LogoController.js @@ -34,18 +34,18 @@ define( * @param {OverlayService} overlayService the overlay service */ function LogoController(overlayService) { - return { - /** - * Display the About dialog. - * @memberof LogoController# - * @memberof platform/commonUI/about.LogoController# - */ - showAboutDialog: function () { - overlayService.createOverlay("overlay-about"); - } - }; + this.overlayService = overlayService; } + /** + * Display the About dialog. + * @memberof LogoController# + * @memberof platform/commonUI/about.LogoController# + */ + LogoController.prototype.showAboutDialog = function () { + this.overlayService.createOverlay("overlay-about"); + }; + return LogoController; } ); From a77920bd1849b762a3ba1b58df466bce6531fc95 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 10 Aug 2015 11:52:23 -0700 Subject: [PATCH 35/84] [Code Style] Use prototypes in Browse bundle WTD-1482. --- .../browse/src/MenuArrowController.js | 25 ++- .../browse/src/creation/CreateAction.js | 126 ++++++------ .../src/creation/CreateActionProvider.js | 72 ++++--- .../browse/src/creation/CreateWizard.js | 193 +++++++++--------- .../browse/src/creation/CreationService.js | 81 ++++---- .../browse/src/navigation/NavigateAction.js | 30 +-- .../src/navigation/NavigationService.js | 97 ++++----- .../browse/src/windowing/FullscreenAction.js | 47 ++--- .../browse/src/windowing/NewTabAction.js | 39 ++-- platform/core/src/actions/ActionAggregator.js | 73 ++++++- 10 files changed, 418 insertions(+), 365 deletions(-) diff --git a/platform/commonUI/browse/src/MenuArrowController.js b/platform/commonUI/browse/src/MenuArrowController.js index f3894df03c..5c4916e099 100644 --- a/platform/commonUI/browse/src/MenuArrowController.js +++ b/platform/commonUI/browse/src/MenuArrowController.js @@ -37,16 +37,25 @@ define( * @constructor */ function MenuArrowController($scope) { - function showMenu(event) { - var actionContext = {key: 'menu', domainObject: $scope.domainObject, event: event}; - $scope.domainObject.getCapability('action').perform(actionContext); - } - - return { - showMenu: showMenu - }; + this.$scope = $scope; } + /** + * Show a context menu for the domain object in this scope. + * + * @param event the browser event which caused this (used to + * position the menu) + */ + MenuArrowController.prototype.showMenu = function (event) { + var actionContext = { + key: 'menu', + domainObject: this.$scope.domainObject, + event: event + }; + + this.$scope.domainObject.getCapability('action').perform(actionContext); + }; + return MenuArrowController; } ); diff --git a/platform/commonUI/browse/src/creation/CreateAction.js b/platform/commonUI/browse/src/creation/CreateAction.js index e30ff06d05..984b26cfe5 100644 --- a/platform/commonUI/browse/src/creation/CreateAction.js +++ b/platform/commonUI/browse/src/creation/CreateAction.js @@ -35,7 +35,9 @@ define( * is performed when a user uses the Create menu. * * @memberof platform/commonUI/browse + * @implements {Action} * @constructor + * * @param {Type} type the type of domain object to create * @param {DomainObject} parent the domain object that should * act as a container for the newly-created object @@ -50,79 +52,83 @@ define( * of the newly-created domain object */ function CreateAction(type, parent, context, dialogService, creationService, policyService) { + this.metadata = { + key: 'create', + glyph: type.getGlyph(), + name: type.getName(), + type: type.getKey(), + description: type.getDescription(), + context: context + }; + + this.type = type; + this.parent = parent; + this.policyService = policyService; + this.dialogService = dialogService; + this.creationService = creationService; + } + + /** + * Create a new object of the given type. + * This will prompt for user input first. + */ + CreateAction.prototype.perform = function () { /* Overview of steps in object creation: 1. Show dialog - a. Prepare dialog contents - b. Invoke dialogService + a. Prepare dialog contents + b. Invoke dialogService 2. Create new object in persistence service - a. Generate UUID - b. Store model + a. Generate UUID + b. Store model 3. Mutate destination container - a. Get mutation capability - b. Add new id to composition + a. Get mutation capability + b. Add new id to composition 4. Persist destination container - a. ...use persistence capability. + a. ...use persistence capability. */ - function perform() { - // The wizard will handle creating the form model based - // on the type... - var wizard = new CreateWizard(type, parent, policyService); + // The wizard will handle creating the form model based + // on the type... + var wizard = + new CreateWizard(this.type, this.parent, this.policyService), + self = this; - // Create and persist the new object, based on user - // input. - function persistResult(formValue) { - var parent = wizard.getLocation(formValue), - newModel = wizard.createModel(formValue); - return creationService.createObject(newModel, parent); - } - - function doNothing() { - // Create cancelled, do nothing - return false; - } - - return dialogService.getUserInput( - wizard.getFormStructure(), - wizard.getInitialFormValue() - ).then(persistResult, doNothing); + // Create and persist the new object, based on user + // input. + function persistResult(formValue) { + var parent = wizard.getLocation(formValue), + newModel = wizard.createModel(formValue); + return self.creationService.createObject(newModel, parent); } - return { - /** - * Create a new object of the given type. - * This will prompt for user input first. - * @method - * @memberof CreateAction - * @memberof platform/commonUI/browse.CreateAction# - */ - perform: perform, + function doNothing() { + // Create cancelled, do nothing + return false; + } - /** - * Get metadata about this action. This includes fields: - * * `name`: Human-readable name - * * `key`: Machine-readable identifier ("create") - * * `glyph`: Glyph to use as an icon for this action - * * `description`: Human-readable description - * * `context`: The context in which this action will be performed. - * - * @return {object} metadata about the create action - * @memberof platform/commonUI/browse.CreateAction# - */ - getMetadata: function () { - return { - key: 'create', - glyph: type.getGlyph(), - name: type.getName(), - type: type.getKey(), - description: type.getDescription(), - context: context - }; - } - }; - } + return this.dialogService.getUserInput( + wizard.getFormStructure(), + wizard.getInitialFormValue() + ).then(persistResult, doNothing); + }; + + + /** + * Metadata associated with a Create action. + * @typedef {ActionMetadata} CreateActionMetadata + * @property {string} type the key for the type of domain object + * to be created + */ + + /** + * Get metadata about this action. + * @returns {CreateActionMetadata} metadata about this action + */ + CreateAction.prototype.getMetadata = function () { + return this.metadata; + }; return CreateAction; } diff --git a/platform/commonUI/browse/src/creation/CreateActionProvider.js b/platform/commonUI/browse/src/creation/CreateActionProvider.js index 1078089d3f..4ca2bce59f 100644 --- a/platform/commonUI/browse/src/creation/CreateActionProvider.js +++ b/platform/commonUI/browse/src/creation/CreateActionProvider.js @@ -35,6 +35,8 @@ define( * * @memberof platform/commonUI/browse * @constructor + * @implements {ActionService} + * * @param {TypeService} typeService the type service, used to discover * available types * @param {DialogService} dialogService the dialog service, used by @@ -45,45 +47,41 @@ define( * object creation. */ function CreateActionProvider(typeService, dialogService, creationService, policyService) { - return { - /** - * Get all Create actions which are applicable in the provided - * context. - * @memberof CreateActionProvider - * @method - * @returns {CreateAction[]} - * @memberof platform/commonUI/browse.CreateActionProvider# - */ - getActions: function (actionContext) { - var context = actionContext || {}, - key = context.key, - destination = context.domainObject; - - // We only provide Create actions, and we need a - // domain object to serve as the container for the - // newly-created object (although the user may later - // make a different selection) - if (key !== 'create' || !destination) { - return []; - } - - // Introduce one create action per type - return typeService.listTypes().filter(function (type) { - return type.hasFeature("creation"); - }).map(function (type) { - return new CreateAction( - type, - destination, - context, - dialogService, - creationService, - policyService - ); - }); - } - }; + this.typeService = typeService; + this.dialogService = dialogService; + this.creationService = creationService; + this.policyService = policyService; } + CreateActionProvider.prototype.getActions = function (actionContext) { + var context = actionContext || {}, + key = context.key, + destination = context.domainObject, + self = this; + + // We only provide Create actions, and we need a + // domain object to serve as the container for the + // newly-created object (although the user may later + // make a different selection) + if (key !== 'create' || !destination) { + return []; + } + + // Introduce one create action per type + return this.typeService.listTypes().filter(function (type) { + return type.hasFeature("creation"); + }).map(function (type) { + return new CreateAction( + type, + destination, + context, + self.dialogService, + self.creationService, + self.policyService + ); + }); + }; + return CreateActionProvider; } ); diff --git a/platform/commonUI/browse/src/creation/CreateWizard.js b/platform/commonUI/browse/src/creation/CreateWizard.js index bd013f5acc..4073ed7e90 100644 --- a/platform/commonUI/browse/src/creation/CreateWizard.js +++ b/platform/commonUI/browse/src/creation/CreateWizard.js @@ -35,112 +35,113 @@ define( * @constructor */ function CreateWizard(type, parent, policyService) { - var model = type.getInitialModel(), - properties = type.getProperties(); + this.type = type; + this.model = type.getInitialModel(); + this.properties = type.getProperties(); + this.parent = parent; + this.policyService = policyService; + } + + /** + * Get the form model for this wizard; this is a description + * that will be rendered to an HTML form. See the + * platform/forms bundle + * + * @return {FormModel} formModel the form model to + * show in the create dialog + */ + CreateWizard.prototype.getFormStructure = function () { + var sections = [], + type = this.type, + policyService = this.policyService; function validateLocation(locatingObject) { var locatingType = locatingObject && - locatingObject.getCapability('type'); + locatingObject.getCapability('type'); return locatingType && policyService.allow( - "composition", - locatingType, - type - ); + "composition", + locatingType, + type + ); } + sections.push({ + name: "Properties", + rows: this.properties.map(function (property, index) { + // Property definition is same as form row definition + var row = Object.create(property.getDefinition()); + + // Use index as the key into the formValue; + // this correlates to the indexing provided by + // getInitialFormValue + row.key = index; + + return row; + }) + }); + + // Ensure there is always a "save in" section + sections.push({ name: 'Location', rows: [{ + name: "Save In", + control: "locator", + validate: validateLocation, + key: "createParent" + }]}); + return { - /** - * Get the form model for this wizard; this is a description - * that will be rendered to an HTML form. See the - * platform/forms bundle - * - * @return {FormModel} formModel the form model to - * show in the create dialog - * @memberof platform/commonUI/browse.CreateWizard# - */ - getFormStructure: function () { - var sections = []; - - sections.push({ - name: "Properties", - rows: properties.map(function (property, index) { - // Property definition is same as form row definition - var row = Object.create(property.getDefinition()); - - // Use index as the key into the formValue; - // this correlates to the indexing provided by - // getInitialFormValue - row.key = index; - - return row; - }) - }); - - // Ensure there is always a "save in" section - sections.push({ name: 'Location', rows: [{ - name: "Save In", - control: "locator", - validate: validateLocation, - key: "createParent" - }]}); - - return { - sections: sections, - name: "Create a New " + type.getName() - }; - }, - /** - * Get the initial value for the form being described. - * This will include the values for all properties described - * in the structure. - * - * @returns {object} the initial value of the form - * @memberof platform/commonUI/browse.CreateWizard# - */ - getInitialFormValue: function () { - // Start with initial values for properties - var formValue = properties.map(function (property) { - return property.getValue(model); - }); - - // Include the createParent - formValue.createParent = parent; - - return formValue; - }, - /** - * Based on a populated form, get the domain object which - * should be used as a parent for the newly-created object. - * @return {DomainObject} - * @memberof platform/commonUI/browse.CreateWizard# - */ - getLocation: function (formValue) { - return formValue.createParent || parent; - }, - /** - * Create the domain object model for a newly-created object, - * based on user input read from a formModel. - * @return {object} the domain object' model - * @memberof platform/commonUI/browse.CreateWizard# - */ - createModel: function (formValue) { - // Clone - var newModel = JSON.parse(JSON.stringify(model)); - - // Always use the type from the type definition - newModel.type = type.getKey(); - - // Update all properties - properties.forEach(function (property, index) { - property.setValue(newModel, formValue[index]); - }); - - return newModel; - } + sections: sections, + name: "Create a New " + this.type.getName() }; + }; + /** + * Get the initial value for the form being described. + * This will include the values for all properties described + * in the structure. + * + * @returns {object} the initial value of the form + */ + CreateWizard.prototype.getInitialFormValue = function () { + // Start with initial values for properties + var model = this.model, + formValue = this.properties.map(function (property) { + return property.getValue(model); + }); - } + // Include the createParent + formValue.createParent = this.parent; + + return formValue; + }; + + /** + * Based on a populated form, get the domain object which + * should be used as a parent for the newly-created object. + * @return {DomainObject} + */ + CreateWizard.prototype.getLocation = function (formValue) { + return formValue.createParent || this.parent; + }; + + /** + * Create the domain object model for a newly-created object, + * based on user input read from a formModel. + * @return {object} the domain object model + */ + CreateWizard.prototype.createModel = function (formValue) { + // Clone + var newModel = JSON.parse(JSON.stringify(this.model)); + + // Always use the type from the type definition + newModel.type = this.type.getKey(); + + // Update all properties + this.properties.forEach(function (property, index) { + property.setValue(newModel, formValue[index]); + }); + + return newModel; + }; return CreateWizard; } diff --git a/platform/commonUI/browse/src/creation/CreationService.js b/platform/commonUI/browse/src/creation/CreationService.js index a4dffdd8e4..44f47fe20f 100644 --- a/platform/commonUI/browse/src/creation/CreationService.js +++ b/platform/commonUI/browse/src/creation/CreationService.js @@ -43,12 +43,35 @@ define( * @constructor */ function CreationService(persistenceService, $q, $log) { + this.persistenceService = persistenceService; + this.$q = $q; + this.$log = $log; + } + + /** + * 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 + * @return {Promise} a promise that will resolve when the domain + * object has been created + */ + CreationService.prototype.createObject = function (model, parent) { + var persistence = parent.getCapability("persistence"), + self = this; // 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( + return self.persistenceService.createObject( space, id, model @@ -67,14 +90,14 @@ define( } } else { // This is abnormal; composition should be an array - $log.warn(NO_COMPOSITION_WARNING + parent.getId()); + self.$log.warn(NO_COMPOSITION_WARNING + parent.getId()); return false; // Cancel mutation } }); - return $q.when(mutatationResult).then(function (result) { + return self.$q.when(mutatationResult).then(function (result) { if (!result) { - $log.error("Could not mutate " + parent.getId()); + self.$log.error("Could not mutate " + parent.getId()); return undefined; } @@ -94,49 +117,25 @@ define( }); } - // 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"); + // We need the parent's persistence capability to determine + // what space to create the new object's model in. + if (!persistence) { + self.$log.warn(NON_PERSISTENT_WARNING); + return self.$q.reject(new Error(NON_PERSISTENT_WARNING)); + } - // 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); - return $q.reject(new Error(NON_PERSISTENT_WARNING)); - } - - // 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) { + // 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 self.$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 - * @memberof platform/commonUI/browse.CreationService# - */ - createObject: createObject - }; - } return CreationService; } diff --git a/platform/commonUI/browse/src/navigation/NavigateAction.js b/platform/commonUI/browse/src/navigation/NavigateAction.js index 04ada63690..47a8fa3e16 100644 --- a/platform/commonUI/browse/src/navigation/NavigateAction.js +++ b/platform/commonUI/browse/src/navigation/NavigateAction.js @@ -33,24 +33,24 @@ define( * The navigate action navigates to a specific domain object. * @memberof platform/commonUI/browse * @constructor + * @implements {Action} */ function NavigateAction(navigationService, $q, context) { - var domainObject = context.domainObject; + this.domainObject = context.domainObject; + this.$q = $q; + this.navigationService = navigationService; + } - function perform() { - // 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 - * @memberof platform/commonUI/browse.NavigateAction# - */ - perform: perform - }; + /** + * Navigate to the object described in the context. + * @returns {Promise} a promise that is resolved once the + * navigation has been updated + */ + NavigateAction.prototype.perform = function () { + // Set navigation, and wrap like a promise + return this.$q.when( + this.navigationService.setNavigation(this.domainObject) + ); } /** diff --git a/platform/commonUI/browse/src/navigation/NavigationService.js b/platform/commonUI/browse/src/navigation/NavigationService.js index cd2ab1b206..0779ce3026 100644 --- a/platform/commonUI/browse/src/navigation/NavigationService.js +++ b/platform/commonUI/browse/src/navigation/NavigationService.js @@ -36,67 +36,52 @@ define( * @constructor */ function NavigationService() { - var navigated, - callbacks = []; + this.navigated = undefined; + this.callbacks = []; + } - // Getter for current navigation - function getNavigation() { - return navigated; - } + /** + * Get the current navigation state. + * @returns {DomainObject} the object that is navigated-to + */ + NavigationService.prototype.getNavigation = function () { + return this.navigated; + }; - // Setter for navigation; invokes callbacks - function setNavigation(value) { - if (navigated !== value) { - navigated = value; - callbacks.forEach(function (callback) { - callback(value); - }); - } - } - - // Adds a callback - function addListener(callback) { - callbacks.push(callback); - } - - // Filters out a callback - function removeListener(callback) { - callbacks = callbacks.filter(function (cb) { - return cb !== callback; + /** + * Set the current navigation state. This will invoke listeners. + * @param {DomainObject} domainObject the domain object to navigate to + */ + NavigationService.prototype.setNavigation = function (value) { + if (this.navigated !== value) { + this.navigated = value; + this.callbacks.forEach(function (callback) { + callback(value); }); } + }; - return { - /** - * Get the current navigation state. - * @memberof platform/commonUI/browse.NavigationService# - */ - getNavigation: getNavigation, - /** - * Set the current navigation state. Thiswill invoke listeners. - * @param {DomainObject} value the domain object to navigate - * to - * @memberof platform/commonUI/browse.NavigationService# - */ - 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 - * @memberof platform/commonUI/browse.NavigationService# - */ - addListener: addListener, - /** - * Stop listening for changes in navigation state. - * @param {function} callback the callback which should - * no longer be invoked when navigation state - * changes - * @memberof platform/commonUI/browse.NavigationService# - */ - removeListener: removeListener - }; + /** + * 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 + */ + NavigationService.prototype.addListener = function (callback) { + this.callbacks.push(callback); + } + + /** + * Stop listening for changes in navigation state. + * @param {function} callback the callback which should + * no longer be invoked when navigation state + * changes + */ + NavigationService.prototype.removeListener = function (callback) { + this.callbacks = this.callbacks.filter(function (cb) { + return cb !== callback; + }); } return NavigationService; diff --git a/platform/commonUI/browse/src/windowing/FullscreenAction.js b/platform/commonUI/browse/src/windowing/FullscreenAction.js index cea492f892..82d92fbd40 100644 --- a/platform/commonUI/browse/src/windowing/FullscreenAction.js +++ b/platform/commonUI/browse/src/windowing/FullscreenAction.js @@ -37,37 +37,30 @@ define( * and regular in-window display. * @memberof platform/commonUI/browse * @constructor + * @implements {Action} */ function FullscreenAction(context) { - return { - /** - * Toggle full screen state - * @memberof platform/commonUI/browse.FullscreenAction# - */ - perform: function () { - screenfull.toggle(); - }, - /** - * Get metadata about this action, including the - * applicable glyph to display. - * @memberof platform/commonUI/browse.FullscreenAction# - */ - getMetadata: function () { - // We override getMetadata, because the glyph and - // description need to be determined at run-time - // based on whether or not we are currently - // full screen. - var metadata = Object.create(FullscreenAction); - metadata.glyph = screenfull.isFullscreen ? "_" : "z"; - metadata.description = screenfull.isFullscreen ? - EXIT_FULLSCREEN : ENTER_FULLSCREEN; - metadata.group = "windowing"; - metadata.context = context; - return metadata; - } - }; + this.context = context; } + FullscreenAction.prototype.perform = function () { + screenfull.toggle(); + }; + + FullscreenAction.prototype.getMetadata = function () { + // We override getMetadata, because the glyph and + // description need to be determined at run-time + // based on whether or not we are currently + // full screen. + var metadata = Object.create(FullscreenAction); + metadata.glyph = screenfull.isFullscreen ? "_" : "z"; + metadata.description = screenfull.isFullscreen ? + EXIT_FULLSCREEN : ENTER_FULLSCREEN; + metadata.group = "windowing"; + metadata.context = this.context; + return metadata; + }; + return FullscreenAction; } ); diff --git a/platform/commonUI/browse/src/windowing/NewTabAction.js b/platform/commonUI/browse/src/windowing/NewTabAction.js index 8d38f994e2..72ef1ebcb2 100644 --- a/platform/commonUI/browse/src/windowing/NewTabAction.js +++ b/platform/commonUI/browse/src/windowing/NewTabAction.js @@ -35,34 +35,25 @@ define( * into a new browser tab. * @memberof platform/commonUI/browse * @constructor + * @implements {Action} */ function NewTabAction(urlService, $window, context) { - // Returns the selected domain object - // when using the context menu or the top right button - // based on the context and the existance of the object - // It is set to object an returned - function getSelectedObject() { - var object; - if (context.selectedObject) { - object = context.selectedObject; - } else { - object = context.domainObject; - } - return object; - } - - return { - // Performs the open in new tab function - // By calling the url service, the mode needed - // (browse) and the domainObject is passed in and - // the path is returned and opened in a new tab - perform: function () { - $window.open(urlService.urlForNewTab("browse", getSelectedObject()), - "_blank"); - } - }; + context = context || {}; + + this.urlService = urlService; + this.$window = $window; + + // Choose the object to be opened into a new tab + this.domainObject = context.selectedObject || context.domainObject; } + NewTabAction.prototype.perform = function () { + this.$window.open( + this.urlService.urlForNewTab("browse", this.domainObject), + "_blank" + ); + }; + return NewTabAction; } ); diff --git a/platform/core/src/actions/ActionAggregator.js b/platform/core/src/actions/ActionAggregator.js index c12f3cf07d..d0094a8a90 100644 --- a/platform/core/src/actions/ActionAggregator.js +++ b/platform/core/src/actions/ActionAggregator.js @@ -25,6 +25,76 @@ define( function () { "use strict"; + /** + * Actions are reusable processes/behaviors performed by users within + * the system, typically upon domain objects. Actions are commonly + * exposed to users as menu items or buttons. + * + * Actions are usually registered via the `actions` extension + * category, or (in advanced cases) via an `actionService` + * implementation. + * + * @interface Action + */ + + /** + * Perform the behavior associated with this action. The return type + * may vary depending on which action has been performed; in general, + * no return value should be expected. + * + * @method Action#perform + */ + + /** + * Get metadata associated with this action. + * + * @method Action#getMetadata + * @returns {ActionMetadata} + */ + + /** + * Metadata associated with an Action. Actions of specific types may + * extend this with additional properties. + * + * @typedef {Object} ActionMetadata + * @property {string} key machine-readable identifier for this action + * @property {string} name human-readable name for this action + * @property {string} description human-readable description + * @property {string} glyph character to display as icon + * @property {ActionContext} context the context in which the action + * will be performed. + */ + + /** + * Provides actions that can be performed within specific contexts. + * + * @interface ActionService + */ + + /** + * Get actions which can be performed within a certain context. + * + * @method ActionService#getActions + * @param {ActionContext} context the context in which the action will + * be performed + * @return {Action[]} relevant actions + */ + + /** + * A description of the context in which an action may occur. + * + * @typedef ActionContext + * @property {DomainObject} [domainObject] the domain object being + * acted upon. + * @property {DomainObject} [selectedObject] the selection at the + * time of action (e.g. the dragged object in a + * drag-and-drop operation.) + * @property {string} [key] the machine-readable identifier of + * the relevant action + * @property {string} [category] a string identifying the category + * of action being performed + */ + /** * The ActionAggregator makes several actionService * instances act as those they were one. When requesting @@ -33,7 +103,8 @@ define( * * @memberof platform/core * @constructor - * @param {ActionProvider[]} actionProviders an array + * @implements {ActionService} + * @param {ActionService[]} actionProviders an array * of action services */ function ActionAggregator(actionProviders) { From 3a0ba4f5a67a712adc9cdf1266bd043a62120d86 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 10 Aug 2015 12:31:44 -0700 Subject: [PATCH 36/84] [Framework] Allow prototype-style constructors WTD-1482. --- platform/framework/src/register/CustomRegistrars.js | 1 - platform/framework/src/resolve/ExtensionResolver.js | 13 ++++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/platform/framework/src/register/CustomRegistrars.js b/platform/framework/src/register/CustomRegistrars.js index 392a8c98c7..c9d40dd0ab 100644 --- a/platform/framework/src/register/CustomRegistrars.js +++ b/platform/framework/src/register/CustomRegistrars.js @@ -46,7 +46,6 @@ define( var key = extension.key, dependencies = extension.depends || []; - if (!key) { $log.warn([ "Cannot register ", diff --git a/platform/framework/src/resolve/ExtensionResolver.js b/platform/framework/src/resolve/ExtensionResolver.js index 86eb657f35..126b9ab3f9 100644 --- a/platform/framework/src/resolve/ExtensionResolver.js +++ b/platform/framework/src/resolve/ExtensionResolver.js @@ -44,13 +44,20 @@ define( implPromise = loader.load(implPath), definition = extension.getDefinition(); + // Wrap a constructor function (to avoid modifying the original) + function constructorFor(impl) { + function Constructor() { + return impl.apply(this, arguments); + } + Constructor.prototype = impl.prototype; + return Constructor; + } + // Attach values from the object definition to the // loaded implementation. function attachDefinition(impl) { var result = (typeof impl === 'function') ? - function () { - return impl.apply({}, arguments); - } : + constructorFor(impl) : Object.create(impl); // Copy over static properties From f8a0ddb484699415300f8ec3d05f1c9ae8cadf8f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 10 Aug 2015 12:39:56 -0700 Subject: [PATCH 37/84] [Code Style] Avoid retaining reference to window Avoid https://docs.angularjs.org/error/ng/cpws by changing way reference to is retained. WTD-1482. --- platform/commonUI/browse/src/windowing/NewTabAction.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/commonUI/browse/src/windowing/NewTabAction.js b/platform/commonUI/browse/src/windowing/NewTabAction.js index 72ef1ebcb2..8e253ad52e 100644 --- a/platform/commonUI/browse/src/windowing/NewTabAction.js +++ b/platform/commonUI/browse/src/windowing/NewTabAction.js @@ -41,14 +41,16 @@ define( context = context || {}; this.urlService = urlService; - this.$window = $window; + this.open = function () { + $window.open.apply($window, arguments) + }; // Choose the object to be opened into a new tab this.domainObject = context.selectedObject || context.domainObject; } NewTabAction.prototype.perform = function () { - this.$window.open( + this.open( this.urlService.urlForNewTab("browse", this.domainObject), "_blank" ); From efc42aa8f28139e89e5417f18d182fa79e5482bc Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 10 Aug 2015 12:53:55 -0700 Subject: [PATCH 38/84] [Code Style] Use prototypes in Dialog bundle WTD-1482. --- platform/commonUI/dialog/src/DialogService.js | 237 +++++++++--------- .../commonUI/dialog/src/OverlayService.js | 81 +++--- 2 files changed, 157 insertions(+), 161 deletions(-) diff --git a/platform/commonUI/dialog/src/DialogService.js b/platform/commonUI/dialog/src/DialogService.js index e23d0d7c8e..25e8943c06 100644 --- a/platform/commonUI/dialog/src/DialogService.js +++ b/platform/commonUI/dialog/src/DialogService.js @@ -38,127 +38,126 @@ define( * @constructor */ function DialogService(overlayService, $q, $log) { - var overlay, - dialogVisible = false; - - // Stop showing whatever overlay is currently active - // (e.g. because the user hit cancel) - function dismiss() { - if (overlay) { - overlay.dismiss(); - } - dialogVisible = false; - } - - function getDialogResponse(key, model, resultGetter) { - // We will return this result as a promise, because user - // input is asynchronous. - var deferred = $q.defer(), - overlayModel; - - // Confirm function; this will be passed in to the - // overlay-dialog template and associated with a - // OK button click - function confirm(value) { - // Pass along the result - deferred.resolve(resultGetter ? resultGetter() : value); - - // Stop showing the dialog - dismiss(); - } - - // Cancel function; this will be passed in to the - // overlay-dialog template and associated with a - // Cancel or X button click - function cancel() { - deferred.reject(); - dismiss(); - } - - // Add confirm/cancel callbacks - model.confirm = confirm; - model.cancel = cancel; - - if (dialogVisible) { - // Only one dialog should be shown at a time. - // The application design should be such that - // we never even try to do this. - $log.warn([ - "Dialog already showing; ", - "unable to show ", - model.name - ].join("")); - deferred.reject(); - } else { - // Add the overlay using the OverlayService, which - // will handle actual insertion into the DOM - overlay = overlayService.createOverlay( - key, - model - ); - - // Track that a dialog is already visible, to - // avoid spawning multiple dialogs at once. - dialogVisible = true; - } - - return deferred.promise; - } - - function getUserInput(formModel, value) { - var overlayModel = { - title: formModel.name, - message: formModel.message, - structure: formModel, - value: value - }; - - // Provide result from the model - function resultGetter() { - return overlayModel.value; - } - - // Show the overlay-dialog - return getDialogResponse( - "overlay-dialog", - overlayModel, - resultGetter - ); - } - - function getUserChoice(dialogModel) { - // Show the overlay-options dialog - return getDialogResponse( - "overlay-options", - { dialog: dialogModel } - ); - } - - return { - /** - * Request user input via a window-modal dialog. - * - * @param {FormModel} formModel a description of the form - * to be shown (see platform/forms) - * @param {object} value the initial state of the form - * @returns {Promise} a promsie for the form value that the - * user has supplied; this may be rejected if - * user input cannot be obtained (for instance, - * because the user cancelled the dialog) - * @memberof platform/commonUI/dialog.DialogService# - */ - getUserInput: getUserInput, - /** - * Request that the user chooses from a set of options, - * which will be shown as buttons. - * - * @param dialogModel a description of the dialog to show - * @memberof platform/commonUI/dialog.DialogService# - */ - getUserChoice: getUserChoice - }; + this.overlayService = overlayService; + this.$q = $q; + this.$log = $log; + this.overlay = undefined; + this.dialogVisible = false; } + // 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(); + } + this.dialogVisible = false; + }; + + DialogService.prototype.getDialogResponse = function (key, model, resultGetter) { + // We will return this result as a promise, because user + // input is asynchronous. + var deferred = this.$q.defer(), + self = this; + + // Confirm function; this will be passed in to the + // overlay-dialog template and associated with a + // OK button click + function confirm(value) { + // Pass along the result + deferred.resolve(resultGetter ? resultGetter() : value); + + // Stop showing the dialog + self.dismiss(); + } + + // Cancel function; this will be passed in to the + // overlay-dialog template and associated with a + // Cancel or X button click + function cancel() { + deferred.reject(); + self.dismiss(); + } + + // Add confirm/cancel callbacks + model.confirm = confirm; + model.cancel = cancel; + + if (this.dialogVisible) { + // Only one dialog should be shown at a time. + // The application design should be such that + // we never even try to do this. + this.$log.warn([ + "Dialog already showing; ", + "unable to show ", + model.name + ].join("")); + deferred.reject(); + } else { + // Add the overlay using the OverlayService, which + // will handle actual insertion into the DOM + this.overlay = this.overlayService.createOverlay( + key, + model + ); + + // Track that a dialog is already visible, to + // avoid spawning multiple dialogs at once. + this.dialogVisible = true; + } + + return deferred.promise; + }; + + /** + * Request user input via a window-modal dialog. + * + * @param {FormModel} formModel a description of the form + * to be shown (see platform/forms) + * @param {object} value the initial state of the form + * @returns {Promise} a promise for the form value that the + * user has supplied; this may be rejected if + * user input cannot be obtained (for instance, + * because the user cancelled the dialog) + */ + DialogService.prototype.getUserInput = function (formModel, value) { + var overlayModel = { + title: formModel.name, + message: formModel.message, + structure: formModel, + value: value + }; + + // Provide result from the model + function resultGetter() { + return overlayModel.value; + } + + // Show the overlay-dialog + return this.getDialogResponse( + "overlay-dialog", + overlayModel, + resultGetter + ); + }; + + /** + * Request that the user chooses from a set of options, + * which will be shown as buttons. + * + * @param dialogModel a description of the dialog to show + * @return {Promise} a promise for the user's choice + */ + DialogService.prototype.getUserChoice = function (dialogModel) { + // Show the overlay-options dialog + return this.getDialogResponse( + "overlay-options", + { dialog: dialogModel } + ); + }; + + return DialogService; } ); diff --git a/platform/commonUI/dialog/src/OverlayService.js b/platform/commonUI/dialog/src/OverlayService.js index 4611a96148..043f638700 100644 --- a/platform/commonUI/dialog/src/OverlayService.js +++ b/platform/commonUI/dialog/src/OverlayService.js @@ -47,54 +47,51 @@ define( * @constructor */ function OverlayService($document, $compile, $rootScope) { - function createOverlay(key, overlayModel) { - // Create a new scope for this overlay - var scope = $rootScope.$new(), - element; + this.$document = $document; + this.$compile = $compile; + this.$rootScope = $rootScope; + } - // Stop showing the overlay; additionally, release the scope - // that it uses. - function dismiss() { - scope.$destroy(); - element.remove(); - } + /** + * Add a new overlay to the document. This will be + * prepended to the document body; the overlay's + * 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) + */ + OverlayService.prototype.createOverlay = function (key, overlayModel) { + // Create a new scope for this overlay + var scope = this.$rootScope.$new(), + element; - // 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; - - // Create the overlay element and add it to the document's body - element = $compile(TEMPLATE)(scope); - $document.find('body').prepend(element); - - - - return { - dismiss: dismiss - }; + // 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; + + // Create the overlay element and add it to the document's body + element = this.$compile(TEMPLATE)(scope); + this.$document.find('body').prepend(element); + return { - /** - * Add a new overlay to the document. This will be - * prepended to the document body; the overlay's - * 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) - * @memberof platform/commonUI/dialog.OverlayService# - */ - createOverlay: createOverlay + dismiss: dismiss }; - } + }; return OverlayService; } From be5cad212a102f191f414a83c5c30f3955db70c1 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 10 Aug 2015 16:38:13 -0700 Subject: [PATCH 39/84] [Code Style] Use prototypes in Edit bundle WTD-1482. --- .../commonUI/edit/src/actions/CancelAction.js | 36 +- .../commonUI/edit/src/actions/EditAction.js | 22 +- .../commonUI/edit/src/actions/LinkAction.js | 32 +- .../edit/src/actions/PropertiesAction.js | 46 ++- .../edit/src/actions/PropertiesDialog.js | 97 +++--- .../commonUI/edit/src/actions/RemoveAction.js | 56 ++-- .../commonUI/edit/src/actions/SaveAction.js | 33 +- .../EditableCompositionCapability.js | 1 + .../capabilities/EditableContextCapability.js | 1 + .../EditablePersistenceCapability.js | 1 + .../EditableRelationshipCapability.js | 1 + .../edit/src/capabilities/EditorCapability.js | 109 +++--- .../edit/src/controllers/EditController.js | 56 ++-- .../src/controllers/EditPanesController.js | 29 +- .../edit/src/objects/EditableDomainObject.js | 7 +- .../src/objects/EditableDomainObjectCache.js | 198 +++++------ .../edit/src/objects/EditableModelCache.js | 43 ++- .../edit/src/policies/EditActionPolicy.js | 72 ++-- .../edit/src/policies/EditableViewPolicy.js | 32 +- .../edit/src/representers/EditRepresenter.js | 62 ++-- .../edit/src/representers/EditToolbar.js | 309 +++++++++--------- .../representers/EditToolbarRepresenter.js | 117 ++++--- .../src/representers/EditToolbarSelection.js | 165 ++++------ .../objects/EditableDomainObjectCacheSpec.js | 8 +- platform/policy/src/PolicyProvider.js | 23 ++ 25 files changed, 766 insertions(+), 790 deletions(-) diff --git a/platform/commonUI/edit/src/actions/CancelAction.js b/platform/commonUI/edit/src/actions/CancelAction.js index 7b2f28538d..a9e6effe9f 100644 --- a/platform/commonUI/edit/src/actions/CancelAction.js +++ b/platform/commonUI/edit/src/actions/CancelAction.js @@ -31,9 +31,24 @@ define( * capabilities to persist the changes that have been made. * @constructor * @memberof platform/commonUI/edit + * @implements {Action} */ function CancelAction($location, urlService, context) { - var domainObject = context.domainObject; + this.domainObject = context.domainObject; + this.$location = $location; + this.urlService = urlService; + } + + /** + * Cancel editing. + * + * @returns {Promise} a promise that will be fulfilled when + * cancellation has completed + */ + CancelAction.prototype.perform = function () { + var domainObject = this.domainObject, + $location = this.$location, + urlService = this.urlService; // Look up the object's "editor.completion" capability; // this is introduced by EditableDomainObject which is @@ -58,26 +73,15 @@ define( ))); } - return { - /** - * Cancel editing. - * - * @returns {Promise} a promise that will be fulfilled when - * cancellation has completed - * @memberof platform/commonUI/edit.CancelAction# - */ - perform: function () { - return doCancel(getEditorCapability()) - .then(returnToBrowse); - } - }; - } + return doCancel(getEditorCapability()) + .then(returnToBrowse); + }; /** * Check if this action is applicable in a given context. * This will ensure that a domain object is present in the context, * and that this domain object is in Edit mode. - * @returns true if applicable + * @returns {boolean} true if applicable */ CancelAction.appliesTo = function (context) { var domainObject = (context || {}).domainObject; diff --git a/platform/commonUI/edit/src/actions/EditAction.js b/platform/commonUI/edit/src/actions/EditAction.js index 2559d0488d..86a8a75540 100644 --- a/platform/commonUI/edit/src/actions/EditAction.js +++ b/platform/commonUI/edit/src/actions/EditAction.js @@ -44,6 +44,7 @@ define( * route) * @memberof platform/commonUI/edit * @constructor + * @implements {Action} */ function EditAction($location, navigationService, $log, context) { var domainObject = (context || {}).domainObject; @@ -61,18 +62,19 @@ define( return NULL_ACTION; } - return { - /** - * Enter edit mode. - * @memberof platform/commonUI/edit.EditAction# - */ - perform: function () { - navigationService.setNavigation(domainObject); - $location.path("/edit"); - } - }; + this.domainObject = domainObject; + this.$location = $location; + this.navigationService = navigationService; } + /** + * Enter edit mode. + */ + EditAction.prototype.perform = function () { + this.navigationService.setNavigation(this.domainObject); + this.$location.path("/edit"); + }; + /** * Check for applicability; verify that a domain object is present * for this action to be performed upon. diff --git a/platform/commonUI/edit/src/actions/LinkAction.js b/platform/commonUI/edit/src/actions/LinkAction.js index b0c2e35e31..74abd2a93c 100644 --- a/platform/commonUI/edit/src/actions/LinkAction.js +++ b/platform/commonUI/edit/src/actions/LinkAction.js @@ -31,42 +31,40 @@ define( * Add one domain object to another's composition. * @constructor * @memberof platform/commonUI/edit + * @implements {Action} */ function LinkAction(context) { - var domainObject = (context || {}).domainObject, - selectedObject = (context || {}).selectedObject, - selectedId = selectedObject && selectedObject.getId(); + this.domainObject = (context || {}).domainObject; + this.selectedObject = (context || {}).selectedObject; + this.selectedId = this.selectedObject && this.selectedObject.getId(); + } + + LinkAction.prototype.perform = function () { + var self = this; // Add this domain object's identifier function addId(model) { if (Array.isArray(model.composition) && - model.composition.indexOf(selectedId) < 0) { - model.composition.push(selectedId); + model.composition.indexOf(self.selectedId) < 0) { + model.composition.push(self.selectedId); } } // Persist changes to the domain object function doPersist() { - var persistence = domainObject.getCapability('persistence'); + var persistence = + self.domainObject.getCapability('persistence'); return persistence.persist(); } // Link these objects function doLink() { - return domainObject.useCapability("mutation", addId) + return self.domainObject.useCapability("mutation", addId) .then(doPersist); } - return { - /** - * Perform this action. - * @memberof platform/commonUI/edit.LinkAction# - */ - perform: function () { - return selectedId && doLink(); - } - }; - } + return this.selectedId && doLink(); + }; return LinkAction; } diff --git a/platform/commonUI/edit/src/actions/PropertiesAction.js b/platform/commonUI/edit/src/actions/PropertiesAction.js index 0cab34a879..1134c23190 100644 --- a/platform/commonUI/edit/src/actions/PropertiesAction.js +++ b/platform/commonUI/edit/src/actions/PropertiesAction.js @@ -32,60 +32,58 @@ define( 'use strict'; /** - * Construct an action which will allow an object's metadata to be - * edited. + * Implements the "Edit Properties" action, which prompts the user + * to modify a domain object's properties. * * @param {DialogService} dialogService a service which will show the dialog * @param {DomainObject} object the object to be edited * @param {ActionContext} context the context in which this action is performed * @memberof platform/commonUI/edit + * @implements {Action} * @constructor */ function PropertiesAction(dialogService, context) { - var object = context.domainObject; + this.domainObject = (context || {}).domainObject; + this.dialogService = dialogService; + } + + PropertiesAction.prototype.perform = function () { + var type = this.domainObject.getCapability('type'), + domainObject = this.domainObject, + dialogService = this.dialogService; // Persist modifications to this domain object function doPersist() { - var persistence = object.getCapability('persistence'); + var persistence = domainObject.getCapability('persistence'); return persistence && persistence.persist(); } // Update the domain object model based on user input function updateModel(userInput, dialog) { - return object.useCapability('mutation', function (model) { + return domainObject.useCapability('mutation', function (model) { dialog.updateModel(model, userInput); }); } function showDialog(type) { // Create a dialog object to generate the form structure, etc. - var dialog = new PropertiesDialog(type, object.getModel()); + var dialog = + new PropertiesDialog(type, domainObject.getModel()); // Show the dialog return dialogService.getUserInput( dialog.getFormStructure(), dialog.getInitialFormValue() ).then(function (userInput) { - // Update the model, if user input was provided - return userInput && updateModel(userInput, dialog); - }).then(function (result) { - return result && doPersist(); - }); + // Update the model, if user input was provided + return userInput && updateModel(userInput, dialog); + }).then(function (result) { + return result && doPersist(); + }); } - return { - /** - * Perform this action. - * @return {Promise} a promise which will be - * fulfilled when the action has completed. - * @memberof platform/commonUI/edit.PropertiesAction# - */ - perform: function () { - var type = object.getCapability('type'); - return type && showDialog(type); - } - }; - } + return type && showDialog(type); + }; /** * Filter this action for applicability against a given context. diff --git a/platform/commonUI/edit/src/actions/PropertiesDialog.js b/platform/commonUI/edit/src/actions/PropertiesDialog.js index a4e3ba1f9f..97ee1f5c0a 100644 --- a/platform/commonUI/edit/src/actions/PropertiesDialog.js +++ b/platform/commonUI/edit/src/actions/PropertiesDialog.js @@ -35,57 +35,56 @@ define( * @constructor */ function PropertiesDialog(type, model) { - var properties = type.getProperties(); - - return { - /** - * Get sections provided by this dialog. - * @return {FormStructure} the structure of this form - * @memberof platform/commonUI/edit.PropertiesDialog# - */ - getFormStructure: function () { - return { - name: "Edit " + model.name, - sections: [{ - name: "Properties", - rows: properties.map(function (property, index) { - // Property definition is same as form row definition - var row = Object.create(property.getDefinition()); - row.key = index; - return row; - }) - }] - }; - }, - /** - * Get the initial state of the form shown by this dialog - * (based on the object model) - * @returns {object} initial state of the form - * @memberof platform/commonUI/edit.PropertiesDialog# - */ - getInitialFormValue: function () { - // Start with initial values for properties - // Note that index needs to correlate to row.key - // from getFormStructure - return properties.map(function (property) { - return property.getValue(model); - }); - }, - /** - * Update a domain object model based on the value of a form. - * @memberof platform/commonUI/edit.PropertiesDialog# - */ - updateModel: function (model, formValue) { - // Update all properties - properties.forEach(function (property, index) { - property.setValue(model, formValue[index]); - }); - } - }; - - + this.type = type; + this.model = model; + this.properties = type.getProperties(); } + /** + * Get sections provided by this dialog. + * @return {FormStructure} the structure of this form + */ + PropertiesDialog.prototype.getFormStructure = function () { + return { + name: "Edit " + this.model.name, + sections: [{ + name: "Properties", + rows: this.properties.map(function (property, index) { + // Property definition is same as form row definition + var row = Object.create(property.getDefinition()); + row.key = index; + return row; + }) + }] + }; + }; + + /** + * Get the initial state of the form shown by this dialog + * (based on the object model) + * @returns {object} initial state of the form + */ + PropertiesDialog.prototype.getInitialFormValue = function () { + var model = this.model; + + // Start with initial values for properties + // Note that index needs to correlate to row.key + // from getFormStructure + return this.properties.map(function (property) { + return property.getValue(model); + }); + }; + + /** + * Update a domain object model based on the value of a form. + */ + PropertiesDialog.prototype.updateModel = function (model, formValue) { + // Update all properties + this.properties.forEach(function (property, index) { + property.setValue(model, formValue[index]); + }); + }; + return PropertiesDialog; } ); diff --git a/platform/commonUI/edit/src/actions/RemoveAction.js b/platform/commonUI/edit/src/actions/RemoveAction.js index 9c64da9b7a..da1c81b486 100644 --- a/platform/commonUI/edit/src/actions/RemoveAction.js +++ b/platform/commonUI/edit/src/actions/RemoveAction.js @@ -39,68 +39,64 @@ define( * @param {ActionContext} context the context in which this action is performed * @memberof platform/commonUI/edit * @constructor + * @implements {Action} */ function RemoveAction($q, context) { - var object = (context || {}).domainObject; + this.domainObject = (context || {}).domainObject; + this.$q = $q; + } - /** + /** + * Perform this action. + * @return {Promise} a promise which will be + * fulfilled when the action has completed. + */ + RemoveAction.prototype.perform = function () { + var $q = this.$q, + domainObject = this.domainObject; + + /* * Check whether an object ID matches the ID of the object being * removed (used to filter a parent's composition to handle the * removal.) - * @memberof platform/commonUI/edit.RemoveAction# */ function isNotObject(otherObjectId) { - return otherObjectId !== object.getId(); + return otherObjectId !== domainObject.getId(); } - /** + /* * Mutate a parent object such that it no longer contains the object * which is being removed. - * @memberof platform/commonUI/edit.RemoveAction# */ function doMutate(model) { model.composition = model.composition.filter(isNotObject); } - /** + /* * Invoke persistence on a domain object. This will be called upon * the removed object's parent (as its composition will have changed.) - * @memberof platform/commonUI/edit.RemoveAction# */ function doPersist(domainObject) { var persistence = domainObject.getCapability('persistence'); return persistence && persistence.persist(); } - /** + /* * Remove the object from its parent, as identified by its context * capability. - * @param {ContextCapability} contextCapability the "context" capability - * of the domain object being removed. - * @memberof platform/commonUI/edit.RemoveAction# */ function removeFromContext(contextCapability) { var parent = contextCapability.getParent(); - $q.when( - parent.useCapability('mutation', doMutate) - ).then(function () { - return doPersist(parent); - }); + return $q.when( + parent.useCapability('mutation', doMutate) + ).then(function () { + return doPersist(parent); + }); } - return { - /** - * Perform this action. - * @return {module:core/promises.Promise} a promise which will be - * fulfilled when the action has completed. - * @memberof platform/commonUI/edit.RemoveAction# - */ - perform: function () { - return $q.when(object.getCapability('context')) - .then(removeFromContext); - } - }; - } + return $q.when(this.domainObject.getCapability('context')) + .then(removeFromContext); + }; // Object needs to have a parent for Remove to be applicable RemoveAction.appliesTo = function (context) { diff --git a/platform/commonUI/edit/src/actions/SaveAction.js b/platform/commonUI/edit/src/actions/SaveAction.js index 428f825837..fa276bba4b 100644 --- a/platform/commonUI/edit/src/actions/SaveAction.js +++ b/platform/commonUI/edit/src/actions/SaveAction.js @@ -31,10 +31,26 @@ define( * Edit Mode. Exits the editing user interface and invokes object * capabilities to persist the changes that have been made. * @constructor + * @implements {Action} * @memberof platform/commonUI/edit */ function SaveAction($location, urlService, context) { - var domainObject = context.domainObject; + this.domainObject = (context || {}).domainObject; + this.$location = $location; + this.urlService = urlService; + } + + /** + * Save changes and conclude editing. + * + * @returns {Promise} a promise that will be fulfilled when + * cancellation has completed + * @memberof platform/commonUI/edit.SaveAction# + */ + SaveAction.prototype.perform = function () { + var domainObject = this.domainObject, + $location = this.$location, + urlService = this.urlService; // Invoke any save behavior introduced by the editor capability; // this is introduced by EditableDomainObject which is @@ -53,19 +69,8 @@ define( )); } - return { - /** - * Save changes and conclude editing. - * - * @returns {Promise} a promise that will be fulfilled when - * cancellation has completed - * @memberof platform/commonUI/edit.SaveAction# - */ - perform: function () { - return doSave().then(returnToBrowse); - } - }; - } + return doSave().then(returnToBrowse); + }; /** * Check if this action is applicable in a given context. diff --git a/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js b/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js index 462a95ec18..17dff58c0d 100644 --- a/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditableCompositionCapability.js @@ -37,6 +37,7 @@ define( * to a pattern used there and may contain unused arguments. * @constructor * @memberof platform/commonUI/edit + * @implements {CompositionCapability} */ return function EditableCompositionCapability( contextCapability, diff --git a/platform/commonUI/edit/src/capabilities/EditableContextCapability.js b/platform/commonUI/edit/src/capabilities/EditableContextCapability.js index 3d61bdd8a3..d0df90afc4 100644 --- a/platform/commonUI/edit/src/capabilities/EditableContextCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditableContextCapability.js @@ -37,6 +37,7 @@ define( * to a pattern used there and may contain unused arguments. * @constructor * @memberof platform/commonUI/edit + * @implements {ContextCapability} */ return function EditableContextCapability( contextCapability, diff --git a/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js b/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js index 5f702d71b8..42b08c72b1 100644 --- a/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditablePersistenceCapability.js @@ -37,6 +37,7 @@ define( * to a pattern used there and may contain unused arguments. * @constructor * @memberof platform/commonUI/edit + * @implements {PersistenceCapability} */ function EditablePersistenceCapability( persistenceCapability, diff --git a/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js b/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js index 7567143436..3034301502 100644 --- a/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditableRelationshipCapability.js @@ -37,6 +37,7 @@ define( * to a pattern used there and may contain unused arguments. * @constructor * @memberof platform/commonUI/edit + * @implements {RelationshipCapability} */ return function EditableRelationshipCapability( relationshipCapability, diff --git a/platform/commonUI/edit/src/capabilities/EditorCapability.js b/platform/commonUI/edit/src/capabilities/EditorCapability.js index 70dfa44dde..34b3044c17 100644 --- a/platform/commonUI/edit/src/capabilities/EditorCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditorCapability.js @@ -42,26 +42,45 @@ define( * @constructor * @memberof platform/commonUI/edit */ - return function EditorCapability( + function EditorCapability( persistenceCapability, editableObject, domainObject, cache ) { + this.editableObject = editableObject; + this.domainObject = domainObject; + this.cache = cache; + } - // Simulate Promise.resolve (or $q.when); the former - // causes a delayed reaction from Angular (since it - // does not trigger a digest) and the latter is not - // readily accessible, since we're a few classes - // removed from the layer which gets dependency - // injection. - function resolvePromise(value) { - return (value && value.then) ? value : { - then: function (callback) { - return resolvePromise(callback(value)); - } - }; - } + // Simulate Promise.resolve (or $q.when); the former + // causes a delayed reaction from Angular (since it + // does not trigger a digest) and the latter is not + // readily accessible, since we're a few classes + // removed from the layer which gets dependency + // injection. + function resolvePromise(value) { + return (value && value.then) ? value : { + then: function (callback) { + return resolvePromise(callback(value)); + } + }; + } + + /** + * Save any changes that have been made to this domain object + * (as well as to others that might have been retrieved and + * modified during the editing session) + * @param {boolean} nonrecursive if true, save only this + * object (and not other objects with associated changes) + * @returns {Promise} a promise that will be fulfilled after + * persistence has completed. + * @memberof platform/commonUI/edit.EditorCapability# + */ + EditorCapability.prototype.save = function (nonrecursive) { + var domainObject = this.domainObject, + editableObject = this.editableObject, + cache = this.cache; // Update the underlying, "real" domain object's model // with changes made to the copy used for editing. @@ -76,42 +95,32 @@ define( return domainObject.getCapability('persistence').persist(); } - return { - /** - * Save any changes that have been made to this domain object - * (as well as to others that might have been retrieved and - * modified during the editing session) - * @param {boolean} nonrecursive if true, save only this - * object (and not other objects with associated changes) - * @returns {Promise} a promise that will be fulfilled after - * persistence has completed. - * @memberof platform/commonUI/edit.EditorCapability# - */ - save: function (nonrecursive) { - return nonrecursive ? - resolvePromise(doMutate()).then(doPersist) : - resolvePromise(cache.saveAll()); - }, - /** - * Cancel editing; Discard any changes that have been made to - * this domain object (as well as to others that might have - * been retrieved and modified during the editing session) - * @returns {Promise} a promise that will be fulfilled after - * cancellation has completed. - * @memberof platform/commonUI/edit.EditorCapability# - */ - cancel: function () { - return resolvePromise(undefined); - }, - /** - * Check if there are any unsaved changes. - * @returns {boolean} true if there are unsaved changes - * @memberof platform/commonUI/edit.EditorCapability# - */ - dirty: function () { - return cache.dirty(); - } - }; + return nonrecursive ? + resolvePromise(doMutate()).then(doPersist) : + resolvePromise(cache.saveAll()); }; + + /** + * Cancel editing; Discard any changes that have been made to + * this domain object (as well as to others that might have + * been retrieved and modified during the editing session) + * @returns {Promise} a promise that will be fulfilled after + * cancellation has completed. + * @memberof platform/commonUI/edit.EditorCapability# + */ + EditorCapability.prototype.cancel = function () { + return resolvePromise(undefined); + }; + + /** + * Check if there are any unsaved changes. + * @returns {boolean} true if there are unsaved changes + * @memberof platform/commonUI/edit.EditorCapability# + */ + EditorCapability.prototype.dirty = function () { + return cache.dirty(); + }; + + return EditorCapability; } ); diff --git a/platform/commonUI/edit/src/controllers/EditController.js b/platform/commonUI/edit/src/controllers/EditController.js index 9b0c228ac3..eaffe02186 100644 --- a/platform/commonUI/edit/src/controllers/EditController.js +++ b/platform/commonUI/edit/src/controllers/EditController.js @@ -38,12 +38,12 @@ define( * @constructor */ function EditController($scope, $q, navigationService) { - var navigatedObject; + var self = this; function setNavigation(domainObject) { // Wrap the domain object such that all mutation is // confined to edit mode (until Save) - navigatedObject = + self.navigatedDomainObject = domainObject && new EditableDomainObject(domainObject, $q); } @@ -52,35 +52,33 @@ define( $scope.$on("$destroy", function () { navigationService.removeListener(setNavigation); }); - - return { - /** - * Get the domain object which is navigated-to. - * @returns {DomainObject} the domain object that is navigated-to - * @memberof platform/commonUI/edit.EditController# - */ - navigatedObject: function () { - return navigatedObject; - }, - /** - * 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 - * @memberof platform/commonUI/edit.EditController# - */ - getUnloadWarning: function () { - var editorCapability = navigatedObject && - navigatedObject.getCapability("editor"), - hasChanges = editorCapability && editorCapability.dirty(); - - return hasChanges ? - "Unsaved changes will be lost if you leave this page." : - undefined; - } - }; } + /** + * Get the domain object which is navigated-to. + * @returns {DomainObject} the domain object that is navigated-to + */ + EditController.prototype.navigatedObject = function () { + return this.navigatedDomainObject; + }; + + /** + * 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 + */ + EditController.prototype.getUnloadWarning = function () { + var navigatedObject = this.navigatedDomainObject, + editorCapability = navigatedObject && + navigatedObject.getCapability("editor"), + hasChanges = editorCapability && editorCapability.dirty(); + + return hasChanges ? + "Unsaved changes will be lost if you leave this page." : + undefined; + }; + return EditController; } ); diff --git a/platform/commonUI/edit/src/controllers/EditPanesController.js b/platform/commonUI/edit/src/controllers/EditPanesController.js index 258286216f..7dedc251ec 100644 --- a/platform/commonUI/edit/src/controllers/EditPanesController.js +++ b/platform/commonUI/edit/src/controllers/EditPanesController.js @@ -32,12 +32,13 @@ define( * @constructor */ function EditPanesController($scope) { - var root; + var self = this; // Update root object based on represented object function updateRoot(domainObject) { - var context = domainObject && - domainObject.getCapability('context'), + var root = self.rootDomainObject, + context = domainObject && + domainObject.getCapability('context'), newRoot = context && context.getTrueRoot(), oldId = root && root.getId(), newId = newRoot && newRoot.getId(); @@ -45,25 +46,21 @@ define( // Only update if this has actually changed, // to avoid excessive refreshing. if (oldId !== newId) { - root = newRoot; + self.rootDomainObject = newRoot; } } // Update root when represented object changes $scope.$watch('domainObject', updateRoot); - - return { - /** - * Get the root-level domain object, as reported by the - * represented domain object. - * @returns {DomainObject} the root object - * @memberof platform/commonUI/edit.EditPanesController# - */ - getRoot: function () { - return root; - } - }; } + /** + * Get the root-level domain object, as reported by the + * represented domain object. + * @returns {DomainObject} the root object + */ + EditPanesController.prototype.getRoot = function () { + return this.rootDomainObject; + }; return EditPanesController; } diff --git a/platform/commonUI/edit/src/objects/EditableDomainObject.js b/platform/commonUI/edit/src/objects/EditableDomainObject.js index 47e10488ea..bbbc0ae512 100644 --- a/platform/commonUI/edit/src/objects/EditableDomainObject.js +++ b/platform/commonUI/edit/src/objects/EditableDomainObject.js @@ -70,6 +70,7 @@ define( * model to allow changes to be easily cancelled. * @constructor * @memberof platform/commonUI/edit + * @implements {DomainObject} */ function EditableDomainObject(domainObject, $q) { // The cache will hold all domain objects reached from @@ -94,10 +95,10 @@ define( this, delegateArguments ), - factory = capabilityFactories[name]; + Factory = capabilityFactories[name]; - return (factory && capability) ? - factory(capability, editableObject, domainObject, cache) : + return (Factory && capability) ? + new Factory(capability, editableObject, domainObject, cache) : capability; }; diff --git a/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js b/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js index 9fc47ef790..88a154d79b 100644 --- a/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js +++ b/platform/commonUI/edit/src/objects/EditableDomainObjectCache.js @@ -44,7 +44,7 @@ define( * of objects retrieved via composition or context capabilities as * editable domain objects. * - * @param {Constructor} EditableDomainObject a + * @param {Constructor} EditableDomainObject a * constructor function which takes a regular domain object as * an argument, and returns an editable domain object as its * result. @@ -53,104 +53,108 @@ define( * @constructor */ function EditableDomainObjectCache(EditableDomainObject, $q) { - var cache = new EditableModelCache(), - dirty = {}, - root; - - return { - /** - * Wrap this domain object in an editable form, or pull such - * an object from the cache if one already exists. - * - * @param {DomainObject} domainObject the regular domain object - * @returns {DomainObject} the domain object in an editable form - * @memberof platform/commonUI/edit.EditableDomainObjectCache# - */ - getEditableObject: function (domainObject) { - var type = domainObject.getCapability('type'); - - // Track the top-level domain object; this will have - // some special behavior for its context capability. - root = root || domainObject; - - // Avoid double-wrapping (WTD-1017) - if (domainObject.hasCapability('editor')) { - return domainObject; - } - - // Don't bother wrapping non-editable objects - if (!type || !type.hasFeature('creation')) { - return domainObject; - } - - // Provide an editable form of the object - return new EditableDomainObject( - domainObject, - cache.getCachedModel(domainObject) - ); - }, - /** - * Check if a domain object is (effectively) the top-level - * object in this editable subgraph. - * @returns {boolean} true if it is the root - * @memberof platform/commonUI/edit.EditableDomainObjectCache# - */ - isRoot: function (domainObject) { - return domainObject === root; - }, - /** - * Mark an editable domain object (presumably already cached) - * as having received modifications during editing; it should be - * included in the bulk save invoked when editing completes. - * - * @param {DomainObject} domainObject the domain object - * @memberof platform/commonUI/edit.EditableDomainObjectCache# - */ - markDirty: function (domainObject) { - dirty[domainObject.getId()] = domainObject; - }, - /** - * Mark an object (presumably already cached) as having had its - * changes saved (and thus no longer needing to be subject to a - * save operation.) - * - * @param {DomainObject} domainObject the domain object - * @memberof platform/commonUI/edit.EditableDomainObjectCache# - */ - markClean: function (domainObject) { - delete dirty[domainObject.getId()]; - }, - /** - * Initiate a save on all objects that have been cached. - * @memberof platform/commonUI/edit.EditableDomainObjectCache# - */ - saveAll: function () { - // Get a list of all dirty objects - var objects = Object.keys(dirty).map(function (k) { - return dirty[k]; - }); - - // Clear dirty set, since we're about to save. - dirty = {}; - - // Most save logic is handled by the "editor.completion" - // capability, so that is delegated here. - return $q.all(objects.map(function (object) { - // Save; pass a nonrecursive flag to avoid looping - return object.getCapability('editor').save(true); - })); - }, - /** - * Check if any objects have been marked dirty in this cache. - * @returns {boolean} true if objects are dirty - * @memberof platform/commonUI/edit.EditableDomainObjectCache# - */ - dirty: function () { - return Object.keys(dirty).length > 0; - } - }; + this.cache = new EditableModelCache(); + this.dirtyObjects = {}; + this.root = undefined; + this.$q = $q; + this.EditableDomainObject = EditableDomainObject; } + /** + * Wrap this domain object in an editable form, or pull such + * an object from the cache if one already exists. + * + * @param {DomainObject} domainObject the regular domain object + * @returns {DomainObject} the domain object in an editable form + */ + EditableDomainObjectCache.prototype.getEditableObject = function (domainObject) { + var type = domainObject.getCapability('type'), + EditableDomainObject = this.EditableDomainObject; + + // Track the top-level domain object; this will have + // some special behavior for its context capability. + this.root = this.root || domainObject; + + // Avoid double-wrapping (WTD-1017) + if (domainObject.hasCapability('editor')) { + return domainObject; + } + + // Don't bother wrapping non-editable objects + if (!type || !type.hasFeature('creation')) { + return domainObject; + } + + // Provide an editable form of the object + return new EditableDomainObject( + domainObject, + this.cache.getCachedModel(domainObject) + ); + }; + + /** + * Check if a domain object is (effectively) the top-level + * object in this editable subgraph. + * @returns {boolean} true if it is the root + */ + EditableDomainObjectCache.prototype.isRoot = function (domainObject) { + return domainObject === this.root; + }; + + /** + * Mark an editable domain object (presumably already cached) + * as having received modifications during editing; it should be + * included in the bulk save invoked when editing completes. + * + * @param {DomainObject} domainObject the domain object + * @memberof platform/commonUI/edit.EditableDomainObjectCache# + */ + EditableDomainObjectCache.prototype.markDirty = function (domainObject) { + this.dirtyObjects[domainObject.getId()] = domainObject; + }; + + /** + * Mark an object (presumably already cached) as having had its + * changes saved (and thus no longer needing to be subject to a + * save operation.) + * + * @param {DomainObject} domainObject the domain object + */ + EditableDomainObjectCache.prototype.markClean = function (domainObject) { + delete this.dirtyObjects[domainObject.getId()]; + }; + + /** + * Initiate a save on all objects that have been cached. + * @return {Promise} A promise which will resolve when all objects are + * persisted. + */ + EditableDomainObjectCache.prototype.saveAll = function () { + // Get a list of all dirty objects + var dirty = this.dirtyObjects, + objects = Object.keys(dirty).map(function (k) { + return dirty[k]; + }); + + // Clear dirty set, since we're about to save. + this.dirtyObjects = {}; + + // Most save logic is handled by the "editor.completion" + // capability, so that is delegated here. + return this.$q.all(objects.map(function (object) { + // Save; pass a nonrecursive flag to avoid looping + return object.getCapability('editor').save(true); + })); + }; + + /** + * Check if any objects have been marked dirty in this cache. + * @returns {boolean} true if objects are dirty + */ + EditableDomainObjectCache.prototype.dirty = function () { + return Object.keys(this.dirtyObjects).length > 0; + }; + return EditableDomainObjectCache; } ); diff --git a/platform/commonUI/edit/src/objects/EditableModelCache.js b/platform/commonUI/edit/src/objects/EditableModelCache.js index b20ba98c8a..30ca3d774a 100644 --- a/platform/commonUI/edit/src/objects/EditableModelCache.js +++ b/platform/commonUI/edit/src/objects/EditableModelCache.js @@ -35,31 +35,28 @@ define( * @constructor */ function EditableModelCache() { - var cache = {}; - - // Deep-copy a model. Models are JSONifiable, so this can be - // done by stringification then destringification - function clone(model) { - return JSON.parse(JSON.stringify(model)); - } - - return { - /** - * Get this domain object's model from the cache (or - * place it in the cache if it isn't in the cache yet) - * @returns a clone of the domain object's model - * @memberof platform/commonUI/edit.EditableModelCache# - */ - getCachedModel: function (domainObject) { - var id = domainObject.getId(); - - return (cache[id] = - cache[id] || clone(domainObject.getModel())); - } - }; - + this.cache = {}; } + // Deep-copy a model. Models are JSONifiable, so this can be + // done by stringification then destringification + function clone(model) { + return JSON.parse(JSON.stringify(model)); + } + + /** + * Get this domain object's model from the cache (or + * place it in the cache if it isn't in the cache yet) + * @returns a clone of the domain object's model + */ + EditableModelCache.prototype.getCachedModel = function (domainObject) { + var id = domainObject.getId(), + cache = this.cache; + + return (cache[id] = + cache[id] || clone(domainObject.getModel())); + }; + return EditableModelCache; } ); diff --git a/platform/commonUI/edit/src/policies/EditActionPolicy.js b/platform/commonUI/edit/src/policies/EditActionPolicy.js index 825224317a..bec2fc423d 100644 --- a/platform/commonUI/edit/src/policies/EditActionPolicy.js +++ b/platform/commonUI/edit/src/policies/EditActionPolicy.js @@ -32,52 +32,44 @@ define( * (shown as buttons in the top-right of browse mode.) * @memberof platform/commonUI/edit * @constructor + * @implements {Policy.} */ function EditActionPolicy() { - // Get a count of views which are not flagged as non-editable. - function countEditableViews(context) { - var domainObject = (context || {}).domainObject, - views = domainObject && domainObject.useCapability('view'), - count = 0; + } - // A view is editable unless explicitly flagged as not - (views || []).forEach(function (view) { - count += (view.editable !== false) ? 1 : 0; - }); + // Get a count of views which are not flagged as non-editable. + function countEditableViews(context) { + var domainObject = (context || {}).domainObject, + views = domainObject && domainObject.useCapability('view'), + count = 0; - return count; + // A view is editable unless explicitly flagged as not + (views || []).forEach(function (view) { + count += (view.editable !== false) ? 1 : 0; + }); + + return count; + } + + EditActionPolicy.prototype.allow = function (action, context) { + var key = action.getMetadata().key, + category = (context || {}).category; + + // Only worry about actions in the view-control category + if (category === 'view-control') { + // Restrict 'edit' to cases where there are editable + // views (similarly, restrict 'properties' to when + // the converse is true) + if (key === 'edit') { + return countEditableViews(context) > 0; + } else if (key === 'properties') { + return countEditableViews(context) < 1; + } } - return { - /** - * Check whether or not a given action is allowed by this - * policy. - * @param {Action} action the action - * @param context the context - * @returns {boolean} true if not disallowed - * @memberof platform/commonUI/edit.EditActionPolicy# - */ - allow: function (action, context) { - var key = action.getMetadata().key, - category = (context || {}).category; - - // Only worry about actions in the view-control category - if (category === 'view-control') { - // Restrict 'edit' to cases where there are editable - // views (similarly, restrict 'properties' to when - // the converse is true) - if (key === 'edit') { - return countEditableViews(context) > 0; - } else if (key === 'properties') { - return countEditableViews(context) < 1; - } - } - - // Like all policies, allow by default. - return true; - } - }; - } + // Like all policies, allow by default. + return true; + }; return EditActionPolicy; } diff --git a/platform/commonUI/edit/src/policies/EditableViewPolicy.js b/platform/commonUI/edit/src/policies/EditableViewPolicy.js index 92fa0b5256..17194064b0 100644 --- a/platform/commonUI/edit/src/policies/EditableViewPolicy.js +++ b/platform/commonUI/edit/src/policies/EditableViewPolicy.js @@ -30,30 +30,22 @@ define( * Policy controlling which views should be visible in Edit mode. * @memberof platform/commonUI/edit * @constructor + * @implements {Policy.} */ function EditableViewPolicy() { - return { - /** - * Check whether or not a given action is allowed by this - * policy. - * @param {Action} action the action - * @param domainObject the domain object which will be viewed - * @returns {boolean} true if not disallowed - * @memberof platform/commonUI/edit.EditableViewPolicy# - */ - allow: function (view, domainObject) { - // If a view is flagged as non-editable, only allow it - // while we're not in Edit mode. - if ((view || {}).editable === false) { - return !domainObject.hasCapability('editor'); - } - - // Like all policies, allow by default. - return true; - } - }; } + EditableViewPolicy.prototype.allow = function (view, domainObject) { + // If a view is flagged as non-editable, only allow it + // while we're not in Edit mode. + if ((view || {}).editable === false) { + return !domainObject.hasCapability('editor'); + } + + // Like all policies, allow by default. + return true; + }; + return EditableViewPolicy; } ); diff --git a/platform/commonUI/edit/src/representers/EditRepresenter.js b/platform/commonUI/edit/src/representers/EditRepresenter.js index 2cca2ee59f..17a0f634b2 100644 --- a/platform/commonUI/edit/src/representers/EditRepresenter.js +++ b/platform/commonUI/edit/src/representers/EditRepresenter.js @@ -42,14 +42,16 @@ define( * representations resulting from changes there. * * @memberof platform/commonUI/edit + * @implements {Representer} * @constructor */ function EditRepresenter($q, $log, scope) { - var domainObject, - key; + var self = this; // Mutate and persist a new version of a domain object's model. function doPersist(model) { + var domainObject = self.domainObject; + // First, mutate; then, persist. return $q.when(domainObject.useCapability("mutation", function () { return model; @@ -65,7 +67,8 @@ define( // Look up from scope; these will have been populated by // mct-representation. var model = scope.model, - configuration = scope.configuration; + configuration = scope.configuration, + domainObject = self.domainObject; // Log the commit message $log.debug([ @@ -79,52 +82,33 @@ define( if (domainObject && domainObject.hasCapability("persistence")) { // Configurations for specific views are stored by // key in the "configuration" field of the model. - if (key && configuration) { + if (self.key && configuration) { model.configuration = model.configuration || {}; - model.configuration[key] = configuration; + model.configuration[self.key] = configuration; } doPersist(model); } } - // Respond to the destruction of the current representation. - function destroy() { - // Nothing to clean up - } - - // Handle a specific representation of a specific domain object - function represent(representation, representedObject) { - // Track the key, to know which view configuration to save to. - key = (representation || {}).key; - // Track the represented object - domainObject = representedObject; - // Ensure existing watches are released - destroy(); - } - // Place the "commit" method in the scope scope.commit = commit; - - return { - /** - * Set the current representation in use, and the domain - * object being represented. - * - * @param {RepresentationDefinition} representation the - * definition of the representation in use - * @param {DomainObject} domainObject the domain object - * being represented - * @memberof platform/commonUI/edit.EditRepresenter# - */ - represent: represent, - /** - * Release any resources associated with this representer. - * @memberof platform/commonUI/edit.EditRepresenter# - */ - destroy: destroy - }; } + // Handle a specific representation of a specific domain object + EditRepresenter.prototype.represent = function represent(representation, representedObject) { + // Track the key, to know which view configuration to save to. + this.key = (representation || {}).key; + // Track the represented object + this.domainObject = representedObject; + // Ensure existing watches are released + this.destroy(); + }; + + // Respond to the destruction of the current representation. + EditRepresenter.prototype.destroy = function destroy() { + // Nothing to clean up + }; + return EditRepresenter; } ); diff --git a/platform/commonUI/edit/src/representers/EditToolbar.js b/platform/commonUI/edit/src/representers/EditToolbar.js index 81d95582aa..367eaf1705 100644 --- a/platform/commonUI/edit/src/representers/EditToolbar.js +++ b/platform/commonUI/edit/src/representers/EditToolbar.js @@ -42,122 +42,19 @@ define( * @constructor */ function EditToolbar(structure, commit) { - var toolbarStructure = Object.create(structure || {}), - toolbarState, - selection, - properties = []; + var self = this; // Generate a new key for an item's property function addKey(property) { - properties.push(property); - return properties.length - 1; // Return index of property - } - - // Update value for this property in all elements of the - // selection which have this property. - function updateProperties(property, value) { - var changed = false; - - // Update property in a selected element - function updateProperty(selected) { - // Ignore selected elements which don't have this property - if (selected[property] !== undefined) { - // Check if this is a setter, or just assignable - if (typeof selected[property] === 'function') { - changed = - changed || (selected[property]() !== value); - selected[property](value); - } else { - changed = - changed || (selected[property] !== value); - selected[property] = value; - } - } - } - - // Update property in all selected elements - selection.forEach(updateProperty); - - // Return whether or not anything changed - return changed; - } - - // Look up the current value associated with a property - // in selection i - function lookupState(property, selected) { - var value = selected[property]; - return (typeof value === 'function') ? value() : value; - } - - // Get initial value for a given property - function initializeState(property) { - var result; - // Look through all selections for this property; - // values should all match by the time we perform - // this lookup anyway. - selection.forEach(function (selected) { - result = (selected[property] !== undefined) ? - lookupState(property, selected) : - result; - }); - return result; - } - - // Check if all elements of the selection which have this - // property have the same value for this property. - function isConsistent(property) { - var consistent = true, - observed = false, - state; - - // Check if a given element of the selection is consistent - // with previously-observed elements for this property. - function checkConsistency(selected) { - var next; - // Ignore selections which don't have this property - if (selected[property] !== undefined) { - // Look up state of this element in the selection - next = lookupState(property, selected); - // Detect inconsistency - if (observed) { - consistent = consistent && (next === state); - } - // Track state for next iteration - state = next; - observed = true; - } - } - - // Iterate through selections - selection.forEach(checkConsistency); - - return consistent; - } - - // Used to filter out items which are applicable (or not) - // to the current selection. - function isApplicable(item) { - var property = (item || {}).property, - method = (item || {}).method, - exclusive = !!(item || {}).exclusive; - - // Check if a selected item defines this property - function hasProperty(selected) { - return (property && (selected[property] !== undefined)) || - (method && (typeof selected[method] === 'function')); - } - - return selection.map(hasProperty).reduce( - exclusive ? and : or, - exclusive - ) && isConsistent(property); + self.properties.push(property); + return self.properties.length - 1; // Return index of property } // Invoke all functions in selections with the given name function invoke(method, value) { if (method) { // Make the change in the selection - selection.forEach(function (selected) { + self.selection.forEach(function (selected) { if (typeof selected[method] === 'function') { selected[method](value); } @@ -190,75 +87,169 @@ define( return converted; } + this.toolbarState = []; + this.selection = undefined; + this.properties = []; + this.toolbarStructure = Object.create(structure || {}); + this.toolbarStructure.sections = + ((structure || {}).sections || []).map(convertSection); + } + + // Check if all elements of the selection which have this + // property have the same value for this property. + EditToolbar.prototype.isConsistent = function (property) { + var self = this, + consistent = true, + observed = false, + state; + + // Check if a given element of the selection is consistent + // with previously-observed elements for this property. + function checkConsistency(selected) { + var next; + // Ignore selections which don't have this property + if (selected[property] !== undefined) { + // Look up state of this element in the selection + next = self.lookupState(property, selected); + // Detect inconsistency + if (observed) { + consistent = consistent && (next === state); + } + // Track state for next iteration + state = next; + observed = true; + } + } + + // Iterate through selections + self.selection.forEach(checkConsistency); + + return consistent; + }; + + // Used to filter out items which are applicable (or not) + // to the current selection. + EditToolbar.prototype.isApplicable = function (item) { + var property = (item || {}).property, + method = (item || {}).method, + exclusive = !!(item || {}).exclusive; + + // Check if a selected item defines this property + function hasProperty(selected) { + return (property && (selected[property] !== undefined)) || + (method && (typeof selected[method] === 'function')); + } + + return this.selection.map(hasProperty).reduce( + exclusive ? and : or, + exclusive + ) && this.isConsistent(property); + }; + + + // Look up the current value associated with a property + EditToolbar.prototype.lookupState = function (property, selected) { + var value = selected[property]; + return (typeof value === 'function') ? value() : value; + }; + + /** + * Set the current selection. Visibility of sections + * and items in the toolbar will be updated to match this. + * @param {Array} s the new selection + */ + EditToolbar.prototype.setSelection = function (s) { + var self = this; + // Show/hide controls in this section per applicability function refreshSectionApplicability(section) { var count = 0; // Show/hide each item (section.items || []).forEach(function (item) { - item.hidden = !isApplicable(item); + item.hidden = !self.isApplicable(item); count += item.hidden ? 0 : 1; }); // Hide this section if there are no applicable items section.hidden = !count; } - // Show/hide controls if they are applicable - function refreshApplicability() { - toolbarStructure.sections.forEach(refreshSectionApplicability); + // Get initial value for a given property + function initializeState(property) { + var result; + // Look through all selections for this property; + // values should all match by the time we perform + // this lookup anyway. + self.selection.forEach(function (selected) { + result = (selected[property] !== undefined) ? + self.lookupState(property, selected) : + result; + }); + return result; } - // Refresh toolbar state to match selection - function refreshState() { - toolbarState = properties.map(initializeState); - } + this.selection = s; + this.toolbarStructure.sections.forEach(refreshSectionApplicability); + this.toolbarState = this.properties.map(initializeState); + }; - toolbarStructure.sections = - ((structure || {}).sections || []).map(convertSection); + /** + * Get the structure of the toolbar, as appropriate to + * pass to `mct-toolbar`. + * @returns the toolbar structure + */ + EditToolbar.prototype.getStructure = function () { + return this.toolbarStructure; + }; - toolbarState = []; + /** + * Get the current state of the toolbar, as appropriate + * to two-way bind to the state handled by `mct-toolbar`. + * @returns {Array} state of the toolbar + */ + EditToolbar.prototype.getState = function () { + return this.toolbarState; + }; - return { - /** - * Set the current selection. Visisbility of sections - * and items in the toolbar will be updated to match this. - * @param {Array} s the new selection - * @memberof platform/commonUI/edit.EditToolbar# - */ - setSelection: function (s) { - selection = s; - refreshApplicability(); - refreshState(); - }, - /** - * Get the structure of the toolbar, as appropriate to - * pass to `mct-toolbar`. - * @returns the toolbar structure - * @memberof platform/commonUI/edit.EditToolbar# - */ - getStructure: function () { - return toolbarStructure; - }, - /** - * Get the current state of the toolbar, as appropriate - * to two-way bind to the state handled by `mct-toolbar`. - * @returns {Array} state of the toolbar - * @memberof platform/commonUI/edit.EditToolbar# - */ - getState: function () { - return toolbarState; - }, - /** - * Update state within the current selection. - * @param {number} index the index of the corresponding - * element in the state array - * @param value the new value to convey to the selection - * @memberof platform/commonUI/edit.EditToolbar# - */ - updateState: function (index, value) { - return updateProperties(properties[index], value); + /** + * Update state within the current selection. + * @param {number} index the index of the corresponding + * element in the state array + * @param value the new value to convey to the selection + */ + EditToolbar.prototype.updateState = function (index, value) { + var self = this; + + // Update value for this property in all elements of the + // selection which have this property. + function updateProperties(property, value) { + var changed = false; + + // Update property in a selected element + function updateProperty(selected) { + // Ignore selected elements which don't have this property + if (selected[property] !== undefined) { + // Check if this is a setter, or just assignable + if (typeof selected[property] === 'function') { + changed = + changed || (selected[property]() !== value); + selected[property](value); + } else { + changed = + changed || (selected[property] !== value); + selected[property] = value; + } + } } - }; - } + + // Update property in all selected elements + self.selection.forEach(updateProperty); + + // Return whether or not anything changed + return changed; + } + + return updateProperties(this.properties[index], value); + }; return EditToolbar; } diff --git a/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js b/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js index a574fffc77..059b5e13f8 100644 --- a/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js +++ b/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js @@ -27,7 +27,10 @@ define( "use strict"; // No operation - function noop() {} + var NOOP_REPRESENTER = { + represent: function () {}, + destroy: function () {} + }; /** * The EditToolbarRepresenter populates the toolbar in Edit mode @@ -35,10 +38,10 @@ define( * @param {Scope} scope the Angular scope of the representation * @memberof platform/commonUI/edit * @constructor + * @implements {Representer} */ function EditToolbarRepresenter(scope, element, attrs) { - var toolbar, - toolbarObject = {}; + var self = this; // Mark changes as ready to persist function commit(message) { @@ -50,31 +53,33 @@ define( // Handle changes to the current selection function updateSelection(selection) { // Only update if there is a toolbar to update - if (toolbar) { + if (self.toolbar) { // Make sure selection is array-like selection = Array.isArray(selection) ? selection : (selection ? [selection] : []); // Update the toolbar's selection - toolbar.setSelection(selection); + self.toolbar.setSelection(selection); // ...and expose its structure/state - toolbarObject.structure = toolbar.getStructure(); - toolbarObject.state = toolbar.getState(); + self.toolbarObject.structure = + self.toolbar.getStructure(); + self.toolbarObject.state = + self.toolbar.getState(); } } // Get state (to watch it) function getState() { - return toolbarObject.state; + return self.toolbarObject.state; } // Update selection models to match changed toolbar state function updateState(state) { // Update underlying state based on toolbar changes var changed = (state || []).map(function (value, index) { - return toolbar.updateState(index, value); + return self.toolbar.updateState(index, value); }).reduce(function (a, b) { return a || b; }, false); @@ -86,68 +91,62 @@ define( } } - // Initialize toolbar (expose object to parent scope) - function initialize(definition) { - // If we have been asked to expose toolbar state... - if (attrs.toolbar) { - // Initialize toolbar object - toolbar = new EditToolbar(definition, commit); - // Ensure toolbar state is exposed - scope.$parent[attrs.toolbar] = toolbarObject; - } - } - - // Represent a domain object using this definition - function represent(representation) { - // Get the newest toolbar definition from the view - var definition = (representation || {}).toolbar || {}; - // Expose the toolbar object to the parent scope - initialize(definition); - // Create a selection scope - scope.selection = new EditToolbarSelection(); - // Initialize toolbar to an empty selection - updateSelection([]); - } - - // Destroy; remove toolbar object from parent scope - function destroy() { - // Clear exposed toolbar state (if any) - if (attrs.toolbar) { - delete scope.$parent[attrs.toolbar]; - } - } + this.commit = commit; + this.scope = scope; + this.attrs = attrs; + this.updateSelection = updateSelection; + this.toolbar = undefined; + this.toolbarObject = {}; // If this representation exposes a toolbar, set up watches // to synchronize with it. - if (attrs.toolbar) { + if (attrs && attrs.toolbar) { // Detect and handle changes to state from the toolbar scope.$watchCollection(getState, updateState); // Watch for changes in the current selection state scope.$watchCollection("selection.all()", updateSelection); // Expose toolbar state under that name - scope.$parent[attrs.toolbar] = toolbarObject; + scope.$parent[attrs.toolbar] = this.toolbarObject; + } else { + // No toolbar declared, so do nothing. + return NOOP_REPRESENTER; } - return { - /** - * Set the current representation in use, and the domain - * object being represented. - * - * @param {RepresentationDefinition} representation the - * definition of the representation in use - * @param {DomainObject} domainObject the domain object - * being represented - * @memberof platform/commonUI/edit.EditToolbarRepresenter# - */ - represent: (attrs || {}).toolbar ? represent : noop, - /** - * Release any resources associated with this representer. - * @memberof platform/commonUI/edit.EditToolbarRepresenter# - */ - destroy: (attrs || {}).toolbar ? destroy : noop - }; } + // Represent a domain object using this definition + EditToolbarRepresenter.prototype.represent = function (representation) { + // Get the newest toolbar definition from the view + var definition = (representation || {}).toolbar || {}, + self = this; + + // Initialize toolbar (expose object to parent scope) + function initialize(definition) { + // If we have been asked to expose toolbar state... + if (self.attrs.toolbar) { + // Initialize toolbar object + self.toolbar = new EditToolbar(definition, self.commit); + // Ensure toolbar state is exposed + self.scope.$parent[self.attrs.toolbar] = self.toolbarObject; + } + } + + // Expose the toolbar object to the parent scope + initialize(definition); + // Create a selection scope + this.scope.selection = new EditToolbarSelection(); + // Initialize toolbar to an empty selection + this.updateSelection([]); + }; + + // Destroy; remove toolbar object from parent scope + EditToolbarRepresenter.prototype.destroy = function () { + // Clear exposed toolbar state (if any) + if (this.attrs.toolbar) { + delete this.scope.$parent[this.attrs.toolbar]; + } + }; + return EditToolbarRepresenter; } ); diff --git a/platform/commonUI/edit/src/representers/EditToolbarSelection.js b/platform/commonUI/edit/src/representers/EditToolbarSelection.js index 87483a4bbb..318ae935b5 100644 --- a/platform/commonUI/edit/src/representers/EditToolbarSelection.js +++ b/platform/commonUI/edit/src/representers/EditToolbarSelection.js @@ -41,112 +41,91 @@ define( * @constructor */ function EditToolbarSelection() { - var selection = [ {} ], - selecting = false, - selected; + this.selection = [{}]; + this.selecting = false; + this.selectedObj = undefined; + } - // Remove the currently-selected object - function deselect() { - // Nothing to do if we don't have a selected object - if (selecting) { - // Clear state tracking - selecting = false; - selected = undefined; + /** + * Check if an object is currently selected. + * @param {*} obj the object to check for selection + * @returns {boolean} true if selected, otherwise false + */ + EditToolbarSelection.prototype.selected = function (obj) { + return (obj === this.selectedObj) || (obj === this.selection[0]); + }; - // Remove the selection - selection.pop(); - - return true; - } + /** + * Select an object. + * @param obj the object to select + * @returns {boolean} true if selection changed + */ + EditToolbarSelection.prototype.select = function (obj) { + // Proxy is always selected + if (obj === this.selection[0]) { return false; } - // Select an object - function select(obj) { - // Proxy is always selected - if (obj === selection[0]) { - return false; - } + // Clear any existing selection + this.deselect(); - // Clear any existing selection - deselect(); + // Note the current selection state + this.selectedObj = obj; + this.selecting = true; - // Note the current selection state - selected = obj; - selecting = true; + // Add the selection + this.selection.push(obj); + }; - // Add the selection - selection.push(obj); + /** + * Clear the current selection. + * @returns {boolean} true if selection changed + */ + EditToolbarSelection.prototype.deselect = function () { + // Nothing to do if we don't have a selected object + if (this.selecting) { + // Clear state tracking + this.selecting = false; + this.selectedObj = undefined; + + // Remove the selection + this.selection.pop(); + + return true; } + return false; + }; + /** + * Get the currently-selected object. + * @returns the currently selected object + */ + EditToolbarSelection.prototype.get = function () { + return this.selectedObj; + }; - // Check if an object is selected - function isSelected(obj) { - return (obj === selected) || (obj === selection[0]); + /** + * Get/set the view proxy (for toolbar actions taken upon + * the view itself.) + * @param [proxy] the view proxy (if setting) + * @returns the current view proxy + */ + EditToolbarSelection.prototype.proxy = function (p) { + if (arguments.length > 0) { + this.selection[0] = p; } + return this.selection[0]; + }; - // Getter for current selection - function get() { - return selected; - } - - // Getter/setter for view proxy - function proxy(p) { - if (arguments.length > 0) { - selection[0] = p; - } - return selection[0]; - } - - // Getter for the full array of selected objects (incl. view proxy) - function all() { - return selection; - } - - return { - /** - * Check if an object is currently selected. - * @returns true if selected, otherwise false - * @memberof platform/commonUI/edit.EditToolbarSelection# - */ - selected: isSelected, - /** - * Select an object. - * @param obj the object to select - * @returns {boolean} true if selection changed - * @memberof platform/commonUI/edit.EditToolbarSelection# - */ - select: select, - /** - * Clear the current selection. - * @returns {boolean} true if selection changed - * @memberof platform/commonUI/edit.EditToolbarSelection# - */ - deselect: deselect, - /** - * Get the currently-selected object. - * @returns the currently selected object - * @memberof platform/commonUI/edit.EditToolbarSelection# - */ - get: get, - /** - * Get/set the view proxy (for toolbar actions taken upon - * the view itself.) - * @param [proxy] the view proxy (if setting) - * @returns the current view proxy - * @memberof platform/commonUI/edit.EditToolbarSelection# - */ - proxy: proxy, - /** - * Get an array containing all selections, including the - * selection proxy. It is generally not advisable to - * mutate this array directly. - * @returns {Array} all selections - * @memberof platform/commonUI/edit.EditToolbarSelection# - */ - all: all - }; - } + /** + * Get an array containing all selections, including the + * selection proxy. It is generally not advisable to + * mutate this array directly. + * @returns {Array} all selections + */ + EditToolbarSelection.prototype.all = function () { + return this.selection; + }; return EditToolbarSelection; } diff --git a/platform/commonUI/edit/test/objects/EditableDomainObjectCacheSpec.js b/platform/commonUI/edit/test/objects/EditableDomainObjectCacheSpec.js index 39cac56d9f..4eea727e26 100644 --- a/platform/commonUI/edit/test/objects/EditableDomainObjectCacheSpec.js +++ b/platform/commonUI/edit/test/objects/EditableDomainObjectCacheSpec.js @@ -112,7 +112,9 @@ define( }); it("saves objects that have been marked dirty", function () { - var objects = ['a', 'b', 'c'].map(TestObject).map(cache.getEditableObject); + var objects = ['a', 'b', 'c'].map(TestObject).map(function (domainObject) { + return cache.getEditableObject(domainObject); + }); cache.markDirty(objects[0]); cache.markDirty(objects[2]); @@ -123,7 +125,9 @@ define( }); it("does not save objects that have been marked clean", function () { - var objects = ['a', 'b', 'c'].map(TestObject).map(cache.getEditableObject); + var objects = ['a', 'b', 'c'].map(TestObject).map(function (domainObject) { + return cache.getEditableObject(domainObject); + }); cache.markDirty(objects[0]); cache.markDirty(objects[2]); diff --git a/platform/policy/src/PolicyProvider.js b/platform/policy/src/PolicyProvider.js index 9c63d154f2..a15b296b1b 100644 --- a/platform/policy/src/PolicyProvider.js +++ b/platform/policy/src/PolicyProvider.js @@ -30,6 +30,29 @@ define( function () { "use strict"; + /** + * A policy is a participant in decision-making policies. Policies + * are divided into categories (identified symbolically by strings); + * within a given category, every given policy-driven decision will + * occur by consulting all available policies and requiring their + * collective consent (that is, every individual policy has the + * power to reject the decision entirely.) + * + * @interface Policy + * @template C, X + */ + + /** + * Check if this policy allows the described decision. The types + * of the arguments expected here vary depending on policy category. + * + * @method Policy#allow + * @template C, X + * @param {C} candidate the thing to allow or disallow + * @param {X} context the context in which the decision occurs + * @returns {boolean} false if disallowed; otherwise, true + */ + /** * Provides an implementation of `policyService` which consults * various policy extensions to determine whether or not a specific From 140d7670260d7d931a278566741620393e014c11 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 11 Aug 2015 09:47:54 -0700 Subject: [PATCH 40/84] [Code Style] Use prototypes in general UI bundle WTD-1482. --- .../src/controllers/BottomBarController.js | 24 ++- .../src/controllers/ClickAwayController.js | 100 ++++++------ .../src/controllers/SelectorController.js | 147 +++++++++--------- .../src/controllers/SplitPaneController.js | 97 ++++++------ .../src/controllers/ToggleController.js | 54 +++---- .../src/controllers/TreeNodeController.js | 96 ++++++------ .../general/src/services/UrlService.js | 98 ++++++------ 7 files changed, 299 insertions(+), 317 deletions(-) diff --git a/platform/commonUI/general/src/controllers/BottomBarController.js b/platform/commonUI/general/src/controllers/BottomBarController.js index 18e3e04dfc..d53d76fce6 100644 --- a/platform/commonUI/general/src/controllers/BottomBarController.js +++ b/platform/commonUI/general/src/controllers/BottomBarController.js @@ -43,21 +43,19 @@ define( }; } - indicators = indicators.map(present); - - return { - /** - * Get all indicators to display. - * @returns {Indicator[]} all indicators - * to display in the bottom bar. - * @memberof platform/commonUI/general.BottomBarController# - */ - getIndicators: function () { - return indicators; - } - }; + this.indicators = indicators.map(present); } + /** + * Get all indicators to display. + * @returns {Indicator[]} all indicators + * to display in the bottom bar. + * @memberof platform/commonUI/general.BottomBarController# + */ + BottomBarController.prototype.getIndicators = function () { + return this.indicators; + }; + return BottomBarController; } ); diff --git a/platform/commonUI/general/src/controllers/ClickAwayController.js b/platform/commonUI/general/src/controllers/ClickAwayController.js index 390e24f50a..9c7c6f8091 100644 --- a/platform/commonUI/general/src/controllers/ClickAwayController.js +++ b/platform/commonUI/general/src/controllers/ClickAwayController.js @@ -37,69 +37,63 @@ define( * @param $document the document element, injected by Angular */ function ClickAwayController($scope, $document) { - var state = false, - clickaway; + var self = this; - // Track state, but also attach and detach a listener for - // mouseup events on the document. - function deactivate() { - state = false; - $document.off("mouseup", clickaway); - } - - function activate() { - state = true; - $document.on("mouseup", clickaway); - } - - function changeState() { - if (state) { - deactivate(); - } else { - activate(); - } - } + this.state = false; + this.$scope = $scope; + this.$document = $document; // Callback used by the document listener. Deactivates; // note also $scope.$apply is invoked to indicate that // the state of this controller has changed. - clickaway = function () { - deactivate(); + this.clickaway = function () { + self.deactivate(); $scope.$apply(); return false; }; - - return { - /** - * Get the current state of the toggle. - * @return {boolean} true if active - * @memberof platform/commonUI/general.ClickAwayController# - */ - isActive: function () { - return state; - }, - /** - * Set a new state for the toggle. - * @return {boolean} true to activate - * @memberof platform/commonUI/general.ClickAwayController# - */ - setState: function (newState) { - if (state !== newState) { - changeState(); - } - }, - /** - * Toggle the current state; activate if it is inactive, - * deactivate if it is active. - * @memberof platform/commonUI/general.ClickAwayController# - */ - toggle: function () { - changeState(); - } - }; - } + // Track state, but also attach and detach a listener for + // mouseup events on the document. + ClickAwayController.prototype.deactivate = function () { + this.state = false; + this.$document.off("mouseup", this.clickaway); + }; + ClickAwayController.prototype.activate = function () { + this.state = true; + this.$document.on("mouseup", this.clickaway); + }; + + /** + * Get the current state of the toggle. + * @return {boolean} true if active + */ + ClickAwayController.prototype.isActive =function () { + return this.state; + }; + + /** + * Set a new state for the toggle. + * @return {boolean} true to activate + */ + ClickAwayController.prototype.setState = function (newState) { + if (this.state !== newState) { + this.toggle(); + } + }; + + /** + * Toggle the current state; activate if it is inactive, + * deactivate if it is active. + */ + ClickAwayController.prototype.toggle = function () { + if (this.state) { + this.deactivate(); + } else { + this.activate(); + } + }; + return ClickAwayController; } ); diff --git a/platform/commonUI/general/src/controllers/SelectorController.js b/platform/commonUI/general/src/controllers/SelectorController.js index 87f9b22b84..26fe5f4d62 100644 --- a/platform/commonUI/general/src/controllers/SelectorController.js +++ b/platform/commonUI/general/src/controllers/SelectorController.js @@ -39,28 +39,17 @@ define( function SelectorController(objectService, $scope) { var treeModel = {}, listModel = {}, - selectedObjects = [], - rootObject, - previousSelected; + previousSelected, + self = this; // For watch; look at the user's selection in the tree function getTreeSelection() { return treeModel.selectedObject; } - // Get the value of the field being edited - function getField() { - return $scope.ngModel[$scope.field] || []; - } - - // Get the value of the field being edited - function setField(value) { - $scope.ngModel[$scope.field] = value; - } - // Store root object for subsequent exposure to template function storeRoot(objects) { - rootObject = objects[ROOT_ID]; + self.rootObject = objects[ROOT_ID]; } // Check that a selection is of the valid type @@ -83,7 +72,8 @@ define( function updateSelectedObjects(objects) { // Look up from the function getObject(id) { return objects[id]; } - selectedObjects = ids.filter(getObject).map(getObject); + self.selectedObjects = + ids.filter(getObject).map(getObject); } // Look up objects by id, then populate right-hand list @@ -94,68 +84,85 @@ define( $scope.$watch(getTreeSelection, validateTreeSelection); // Make sure right-hand list matches underlying model - $scope.$watchCollection(getField, updateList); + $scope.$watchCollection(function () { + return self.getField(); + }, updateList); // Look up root object, then store it objectService.getObjects([ROOT_ID]).then(storeRoot); - return { - /** - * Get the root object to show in the left-hand tree. - * @returns {DomainObject} the root object - * @memberof platform/commonUI/general.SelectorController# - */ - root: function () { - return rootObject; - }, - /** - * Add a domain object to the list of selected objects. - * @param {DomainObject} the domain object to select - * @memberof platform/commonUI/general.SelectorController# - */ - select: function (domainObject) { - var id = domainObject && domainObject.getId(), - list = getField() || []; - // Only select if we have a valid id, - // and it isn't already selected - if (id && list.indexOf(id) === -1) { - setField(list.concat([id])); - } - }, - /** - * Remove a domain object from the list of selected objects. - * @param {DomainObject} the domain object to select - * @memberof platform/commonUI/general.SelectorController# - */ - deselect: function (domainObject) { - var id = domainObject && domainObject.getId(), - list = getField() || []; - // Only change if this was a valid id, - // for an object which was already selected - if (id && list.indexOf(id) !== -1) { - // Filter it out of the current field - setField(list.filter(function (otherId) { - return otherId !== id; - })); - // Clear the current list selection - delete listModel.selectedObject; - } - }, - /** - * Get the currently-selected domain objects. - * @returns {DomainObject[]} the current selection - * @memberof platform/commonUI/general.SelectorController# - */ - selected: function () { - return selectedObjects; - }, - // Expose tree/list model for use in template directly - treeModel: treeModel, - listModel: listModel - }; + this.$scope = $scope; + this.selectedObjects = []; + + // Expose tree/list model for use in template directly + this.treeModel = treeModel; + this.listModel = listModel; } + + + // Set the value of the field being edited + SelectorController.prototype.setField = function (value) { + this.$scope.ngModel[this.$scope.field] = value; + }; + + // Get the value of the field being edited + SelectorController.prototype.getField = function () { + return this.$scope.ngModel[this.$scope.field] || []; + }; + + + /** + * Get the root object to show in the left-hand tree. + * @returns {DomainObject} the root object + */ + SelectorController.prototype.root = function () { + return this.rootObject; + }; + + /** + * Add a domain object to the list of selected objects. + * @param {DomainObject} the domain object to select + */ + SelectorController.prototype.select = function (domainObject) { + var id = domainObject && domainObject.getId(), + list = this.getField() || []; + // Only select if we have a valid id, + // and it isn't already selected + if (id && list.indexOf(id) === -1) { + this.setField(list.concat([id])); + } + }; + + /** + * Remove a domain object from the list of selected objects. + * @param {DomainObject} the domain object to select + */ + SelectorController.prototype.deselect = function (domainObject) { + var id = domainObject && domainObject.getId(), + list = this.getField() || []; + // Only change if this was a valid id, + // for an object which was already selected + if (id && list.indexOf(id) !== -1) { + // Filter it out of the current field + this.setField(list.filter(function (otherId) { + return otherId !== id; + })); + // Clear the current list selection + delete this.listModel.selectedObject; + } + }; + + /** + * Get the currently-selected domain objects. + * @returns {DomainObject[]} the current selection + */ + SelectorController.prototype.selected = function () { + return this.selectedObjects; + }; + + return SelectorController; } ); diff --git a/platform/commonUI/general/src/controllers/SplitPaneController.js b/platform/commonUI/general/src/controllers/SplitPaneController.js index 9eb9daa4c6..75dfed28d9 100644 --- a/platform/commonUI/general/src/controllers/SplitPaneController.js +++ b/platform/commonUI/general/src/controllers/SplitPaneController.js @@ -36,59 +36,54 @@ define( * @constructor */ function SplitPaneController() { - var current = 200, - start = 200, - assigned = false; - - return { - /** - * Get the current position of the splitter, in pixels - * from the left edge. - * @returns {number} position of the splitter, in pixels - * @memberof platform/commonUI/general.SplitPaneController# - */ - state: function (defaultState) { - // Set the state to the desired default, if we don't have a - // "real" current state yet. - if (arguments.length > 0 && !assigned) { - current = defaultState; - assigned = true; - } - return current; - }, - /** - * Begin moving the splitter; this will note the splitter's - * current position, which is necessary for correct - * interpretation of deltas provided by mct-drag. - * @memberof platform/commonUI/general.SplitPaneController# - */ - startMove: function () { - start = current; - }, - /** - * Move the splitter a number of pixels to the right - * (negative numbers move the splitter to the left.) - * This movement is relative to the position of the - * splitter when startMove was last invoked. - * @param {number} delta number of pixels to move - * @memberof platform/commonUI/general.SplitPaneController# - */ - move: function (delta, minimum, maximum) { - // Ensure defaults for minimum/maximum - maximum = isNaN(maximum) ? DEFAULT_MAXIMUM : maximum; - minimum = isNaN(minimum) ? DEFAULT_MINIMUM : minimum; - - // Update current splitter state - current = Math.min( - maximum, - Math.max(minimum, start + delta) - ); - - //console.log(current + "; minimum: " + minimum + "; max: " + maximum); - } - }; + this.current = 200; + this.start = 200; + this.assigned = false; } + /** + * Get the current position of the splitter, in pixels + * from the left edge. + * @returns {number} position of the splitter, in pixels + */ + SplitPaneController.prototype.state = function (defaultState) { + // Set the state to the desired default, if we don't have a + // "real" current state yet. + if (arguments.length > 0 && !this.assigned) { + this.current = defaultState; + this.assigned = true; + } + return this.current; + }; + + /** + * Begin moving the splitter; this will note the splitter's + * current position, which is necessary for correct + * interpretation of deltas provided by mct-drag. + */ + SplitPaneController.prototype.startMove = function () { + this.start = this.current; + }; + + /** + * Move the splitter a number of pixels to the right + * (negative numbers move the splitter to the left.) + * This movement is relative to the position of the + * splitter when startMove was last invoked. + * @param {number} delta number of pixels to move + */ + SplitPaneController.prototype.move = function (delta, minimum, maximum) { + // Ensure defaults for minimum/maximum + maximum = isNaN(maximum) ? DEFAULT_MAXIMUM : maximum; + minimum = isNaN(minimum) ? DEFAULT_MINIMUM : minimum; + + // Update current splitter state + this.current = Math.min( + maximum, + Math.max(minimum, this.start + delta) + ); + }; + return SplitPaneController; } ); diff --git a/platform/commonUI/general/src/controllers/ToggleController.js b/platform/commonUI/general/src/controllers/ToggleController.js index d6e73414a1..9d7d493f15 100644 --- a/platform/commonUI/general/src/controllers/ToggleController.js +++ b/platform/commonUI/general/src/controllers/ToggleController.js @@ -34,37 +34,33 @@ define( * @constructor */ function ToggleController() { - var state = false; - - return { - /** - * Get the current state of the toggle. - * @return {boolean} true if active - * @memberof platform/commonUI/general.ToggleController# - */ - isActive: function () { - return state; - }, - /** - * Set a new state for the toggle. - * @return {boolean} true to activate - * @memberof platform/commonUI/general.ToggleController# - */ - setState: function (newState) { - state = newState; - }, - /** - * Toggle the current state; activate if it is inactive, - * deactivate if it is active. - * @memberof platform/commonUI/general.ToggleController# - */ - toggle: function () { - state = !state; - } - }; - + this.state = false; } + /** + * Get the current state of the toggle. + * @return {boolean} true if active + */ + ToggleController.prototype.isActive = function () { + return this.state; + }; + + /** + * Set a new state for the toggle. + * @return {boolean} true to activate + */ + ToggleController.prototype.setState = function (newState) { + this.state = newState; + }; + + /** + * Toggle the current state; activate if it is inactive, + * deactivate if it is active. + */ + ToggleController.prototype.toggle = function () { + this.state = !this.state; + }; + return ToggleController; } ); diff --git a/platform/commonUI/general/src/controllers/TreeNodeController.js b/platform/commonUI/general/src/controllers/TreeNodeController.js index 3310bf2ae0..3c3829700b 100644 --- a/platform/commonUI/general/src/controllers/TreeNodeController.js +++ b/platform/commonUI/general/src/controllers/TreeNodeController.js @@ -51,10 +51,9 @@ define( * @memberof platform/commonUI/general * @constructor */ - function TreeNodeController($scope, $timeout, $rootScope) { - var selectedObject = ($scope.ngModel || {}).selectedObject, - isSelected = false, - hasBeenExpanded = false; + function TreeNodeController($scope, $timeout) { + var self = this, + selectedObject = ($scope.ngModel || {}).selectedObject; // Look up the id for a domain object. A convenience // for mapping; additionally does some undefined-checking. @@ -77,17 +76,6 @@ define( checkPath(nodePath, navPath, index + 1)); } - // Track that a node has been expanded, either by the - // user or automatically to show a selection. - function trackExpansion() { - if (!hasBeenExpanded) { - // Run on a timeout; if a lot of expansion needs to - // occur (e.g. if the selection is several nodes deep) we - // want this to be spread across multiple digest cycles. - $timeout(function () { hasBeenExpanded = true; }, 0); - } - } - // Consider the currently-navigated object and update // parameters which support display. function checkSelection() { @@ -102,7 +90,7 @@ define( // Deselect; we will reselect below, iff we are // exactly at the end of the path. - isSelected = false; + self.isSelectedFlag = false; // Expand if necessary (if the navigated object will // be in this node's subtree) @@ -121,12 +109,12 @@ define( // at the end of the path, highlight; // otherwise, expand. if (nodePath.length === navPath.length) { - isSelected = true; + self.isSelectedFlag = true; } else { // node path is shorter: Expand! if ($scope.toggle) { $scope.toggle.setState(true); } - trackExpansion(); + self.trackExpansion(); } } @@ -139,41 +127,55 @@ define( selectedObject = object; checkSelection(); } - + + this.isSelectedFlag = false; + this.hasBeenExpandedFlag = false; + this.$timeout = $timeout; + // Listen for changes which will effect display parameters $scope.$watch("ngModel.selectedObject", setSelection); $scope.$watch("domainObject", checkSelection); - 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. - * @memberof platform/commonUI/general.TreeNodeController# - */ - trackExpansion: trackExpansion, - /** - * Check if this not has ever been expanded. - * @returns true if it has been expanded - * @memberof platform/commonUI/general.TreeNodeController# - */ - hasBeenExpanded: function () { - return hasBeenExpanded; - }, - /** - * Check whether or not the domain object represented by - * this tree node should be highlighted. - * An object will be highlighted if it matches - * ngModel.selectedObject - * @returns true if this should be highlighted - * @memberof platform/commonUI/general.TreeNodeController# - */ - isSelected: function () { - return isSelected; - } - }; + + } + /** + * 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. + */ + TreeNodeController.prototype.trackExpansion = function () { + var self = this; + if (!self.hasBeenExpanded()) { + // Run on a timeout; if a lot of expansion needs to + // occur (e.g. if the selection is several nodes deep) we + // want this to be spread across multiple digest cycles. + self.$timeout(function () { + self.hasBeenExpandedFlag = true; + }, 0); + } + }; + + /** + * Check if this not has ever been expanded. + * @returns true if it has been expanded + */ + TreeNodeController.prototype.hasBeenExpanded = function () { + return this.hasBeenExpandedFlag; + }; + + /** + * Check whether or not the domain object represented by + * this tree node should be highlighted. + * An object will be highlighted if it matches + * ngModel.selectedObject + * @returns true if this should be highlighted + */ + TreeNodeController.prototype.isSelected = function () { + return this.isSelectedFlag; + }; + return TreeNodeController; } ); diff --git a/platform/commonUI/general/src/services/UrlService.js b/platform/commonUI/general/src/services/UrlService.js index 79931add04..5d57b03ca0 100644 --- a/platform/commonUI/general/src/services/UrlService.js +++ b/platform/commonUI/general/src/services/UrlService.js @@ -36,62 +36,52 @@ define( * @memberof platform/commonUI/general */ function UrlService($location) { - // Returns the url for the mode wanted - // and the domainObject passed in. A path - // is returned. The view is defaulted to - // the current location's (current object's) - // view set. - function urlForLocation(mode, domainObject) { - var context = domainObject && - domainObject.getCapability('context'), - objectPath = context ? context.getPath() : [], - ids = objectPath.map(function (domainObject) { - return domainObject.getId(); - }), - // Parses the path together. Starts with the - // default index.html file, then the mode passed - // into the service, followed by ids in the url - // joined by '/', and lastly the view path from - // the current location - path = mode + "/" + ids.slice(1).join("/"); - return path; - } - - // Uses the Url for the current location - // from the urlForLocation function and - // includes the view and the index path - function urlForNewTab(mode, domainObject) { - var viewPath = "?view=" + $location.search().view, - newTabPath = - "index.html#" + urlForLocation(mode, domainObject) + viewPath; - return newTabPath; - } - - return { - /** - * Returns the Url path for a specific domain object - * without the index.html path and the view path - * @param {value} value of the browse or edit mode - * for the path - * @param {DomainObject} value of the domain object - * to get the path of - * @memberof platform/commonUI/general.UrlService# - */ - urlForNewTab: urlForNewTab, - /** - * Returns the Url path for a specific domain object - * including the index.html path and the view path - * allowing a new tab to hold the correct characteristics - * @param {value} value of the browse or edit mode - * for the path - * @param {DomainObject} value of the domain object - * to get the path of - * @memberof platform/commonUI/general.UrlService# - */ - urlForLocation: urlForLocation - }; + this.$location = $location; } + /** + * Returns the Url path for a specific domain object + * without the index.html path and the view path + * @param {string} mode value of browse or edit mode + * for the path + * @param {DomainObject} value of the domain object + * to get the path of + * @returns {string} URL for the domain object + */ + UrlService.prototype.urlForLocation = function (mode, domainObject) { + var context = domainObject && + domainObject.getCapability('context'), + objectPath = context ? context.getPath() : [], + ids = objectPath.map(function (domainObject) { + return domainObject.getId(); + }); + + // Parses the path together. Starts with the + // default index.html file, then the mode passed + // into the service, followed by ids in the url + // joined by '/', and lastly the view path from + // the current location + return mode + "/" + ids.slice(1).join("/"); + }; + + /** + * Returns the Url path for a specific domain object + * including the index.html path and the view path + * allowing a new tab to hold the correct characteristics + * @param {string} mode value of browse or edit mode + * for the path + * @param {DomainObject} value of the domain object + * to get the path of + * @returns {string} URL for the domain object + */ + UrlService.prototype.urlForNewTab = function (mode, domainObject) { + var viewPath = "?view=" + this.$location.search().view, + newTabPath = + "index.html#" + this.urlForLocation(mode, domainObject) + + viewPath; + return newTabPath; + }; + return UrlService; } ); From de291ad3b1f4c14e7ef392eb166a28ef318c7ccc Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 11 Aug 2015 10:00:56 -0700 Subject: [PATCH 41/84] [Code Style] Use prototypes in inspection bundle WTD-1482 --- .../inspect/src/gestures/InfoGesture.js | 156 ++++++++++-------- .../inspect/src/services/InfoService.js | 101 ++++++------ 2 files changed, 137 insertions(+), 120 deletions(-) diff --git a/platform/commonUI/inspect/src/gestures/InfoGesture.js b/platform/commonUI/inspect/src/gestures/InfoGesture.js index a22c4515fa..271857a592 100644 --- a/platform/commonUI/inspect/src/gestures/InfoGesture.js +++ b/platform/commonUI/inspect/src/gestures/InfoGesture.js @@ -32,90 +32,104 @@ define( * * @memberof platform/commonUI/inspect * @constructor + * @implements {Gesture} * @param $timeout Angular's `$timeout` * @param {InfoService} infoService a service which shows info bubbles - * @param {number} DELAY delay, in milliseconds, before bubble appears + * @param {number} delay delay, in milliseconds, before bubble appears * @param element jqLite-wrapped DOM element * @param {DomainObject} domainObject the domain object for which to * show information */ - function InfoGesture($timeout, infoService, DELAY, element, domainObject) { - var dismissBubble, - pendingBubble, - mousePosition, - scopeOff; + function InfoGesture($timeout, infoService, delay, element, domainObject) { + var self = this; - function trackPosition(event) { - // Record mouse position, so bubble can be shown at latest - // mouse position (not just where the mouse entered) - mousePosition = [ event.clientX, event.clientY ]; - } - - function hideBubble() { - // If a bubble is showing, dismiss it - if (dismissBubble) { - dismissBubble(); - element.off('mouseleave', hideBubble); - dismissBubble = undefined; - } - // If a bubble will be shown on a timeout, cancel that - if (pendingBubble) { - $timeout.cancel(pendingBubble); - element.off('mousemove', trackPosition); - element.off('mouseleave', hideBubble); - pendingBubble = undefined; - } - // Also clear mouse position so we don't have a ton of tiny - // arrays allocated while user mouses over things - mousePosition = undefined; - } - - function showBubble(event) { - trackPosition(event); - - // Also need to track position during hover - element.on('mousemove', trackPosition); - - // Show the bubble, after a suitable delay (if mouse has - // left before this time is up, this will be canceled.) - pendingBubble = $timeout(function () { - dismissBubble = infoService.display( - "info-table", - domainObject.getModel().name, - domainObject.useCapability('metadata'), - mousePosition - ); - element.off('mousemove', trackPosition); - pendingBubble = undefined; - }, DELAY); - - element.on('mouseleave', hideBubble); - } - - // Show bubble (on a timeout) on mouse over - element.on('mouseenter', showBubble); + // Callback functions to preserve the "this" pointer (in the + // absence of Function.prototype.bind) + this.showBubbleCallback = function (event) { + self.showBubble(event); + }; + this.hideBubbleCallback = function (event) { + self.hideBubble(event); + }; + this.trackPositionCallback = function (event) { + self.trackPosition(event); + }; // Also make sure we dismiss bubble if representation is destroyed // before the mouse actually leaves it - scopeOff = element.scope().$on('$destroy', hideBubble); + this.scopeOff = element.scope().$on('$destroy', this.hideBubbleCallback); - return { - /** - * Detach any event handlers associated with this gesture. - * @memberof InfoGesture - * @method - * @memberof platform/commonUI/inspect.InfoGesture# - */ - destroy: function () { - // Dismiss any active bubble... - hideBubble(); - // ...and detach listeners - element.off('mouseenter', showBubble); - scopeOff(); - } - }; + this.element = element; + this.$timeout = $timeout; + this.infoService = infoService; + this.delay = delay; + this.domainObject = domainObject; + + // Show bubble (on a timeout) on mouse over + element.on('mouseenter', this.showBubbleCallback); } + InfoGesture.prototype.trackPosition = function (event) { + // Record mouse position, so bubble can be shown at latest + // mouse position (not just where the mouse entered) + this.mousePosition = [ event.clientX, event.clientY ]; + }; + + InfoGesture.prototype.hideBubble = function () { + // If a bubble is showing, dismiss it + if (this.dismissBubble) { + this.dismissBubble(); + this.element.off('mouseleave', this.hideBubbleCallback); + this.dismissBubble = undefined; + } + // If a bubble will be shown on a timeout, cancel that + if (this.pendingBubble) { + this.$timeout.cancel(this.pendingBubble); + this.element.off('mousemove', this.trackPositionCallback); + this.element.off('mouseleave', this.hideBubbleCallback); + this.pendingBubble = undefined; + } + // Also clear mouse position so we don't have a ton of tiny + // arrays allocated while user mouses over things + this.mousePosition = undefined; + }; + + InfoGesture.prototype.showBubble = function (event) { + var self = this; + + this.trackPosition(event); + + // Also need to track position during hover + this.element.on('mousemove', this.trackPositionCallback); + + // Show the bubble, after a suitable delay (if mouse has + // left before this time is up, this will be canceled.) + this.pendingBubble = this.$timeout(function () { + self.dismissBubble = self.infoService.display( + "info-table", + self.domainObject.getModel().name, + self.domainObject.useCapability('metadata'), + self.mousePosition + ); + self.element.off('mousemove', self.trackPositionCallback); + self.pendingBubble = undefined; + }, this.delay); + + this.element.on('mouseleave', this.hideBubbleCallback); + }; + + /** + * Detach any event handlers associated with this gesture. + * @method + */ + InfoGesture.prototype.destroy = function () { + // Dismiss any active bubble... + this.hideBubble(); + // ...and detach listeners + this.element.off('mouseenter', this.showBubbleCallback); + this.scopeOff(); + }; + return InfoGesture; } diff --git a/platform/commonUI/inspect/src/services/InfoService.js b/platform/commonUI/inspect/src/services/InfoService.js index ed5bbfaa48..2f9fe62eab 100644 --- a/platform/commonUI/inspect/src/services/InfoService.js +++ b/platform/commonUI/inspect/src/services/InfoService.js @@ -35,61 +35,64 @@ define( * @constructor */ function InfoService($compile, $document, $window, $rootScope) { + this.$compile = $compile; + this.$document = $document; + this.$window = $window; + this.$rootScope = $rootScope; + } - function display(templateKey, title, content, position) { - var body = $document.find('body'), - scope = $rootScope.$new(), - winDim = [$window.innerWidth, $window.innerHeight], - bubbleSpaceLR = InfoConstants.BUBBLE_MARGIN_LR + InfoConstants.BUBBLE_MAX_WIDTH, - goLeft = position[0] > (winDim[0] - bubbleSpaceLR), - goUp = position[1] > (winDim[1] / 2), - bubble; + /** + * Display an info bubble at the specified location. + * @param {string} templateKey template to place in bubble + * @param {string} title title for the bubble + * @param {*} content content to pass to the template, via + * `ng-model` + * @param {number[]} x,y position of the info bubble, in + * pixel coordinates. + * @returns {Function} a function that may be invoked to + * dismiss the info bubble + */ + InfoService.prototype.display = function (templateKey, title, content, position) { + var $compile = this.$compile, + $document = this.$document, + $window = this.$window, + $rootScope = this.$rootScope, + body = $document.find('body'), + scope = $rootScope.$new(), + winDim = [$window.innerWidth, $window.innerHeight], + bubbleSpaceLR = InfoConstants.BUBBLE_MARGIN_LR + InfoConstants.BUBBLE_MAX_WIDTH, + goLeft = position[0] > (winDim[0] - bubbleSpaceLR), + goUp = position[1] > (winDim[1] / 2), + bubble; - // Pass model & container parameters into the scope - scope.bubbleModel = content; - scope.bubbleTemplate = templateKey; - scope.bubbleLayout = (goUp ? 'arw-btm' : 'arw-top') + ' ' + - (goLeft ? 'arw-right' : 'arw-left'); - scope.bubbleTitle = title; + // Pass model & container parameters into the scope + scope.bubbleModel = content; + scope.bubbleTemplate = templateKey; + scope.bubbleLayout = (goUp ? 'arw-btm' : 'arw-top') + ' ' + + (goLeft ? 'arw-right' : 'arw-left'); + scope.bubbleTitle = title; - // Create the context menu - bubble = $compile(BUBBLE_TEMPLATE)(scope); + // Create the context menu + bubble = $compile(BUBBLE_TEMPLATE)(scope); - // Position the bubble - bubble.css('position', 'absolute'); - if (goLeft) { - bubble.css('right', (winDim[0] - position[0] + OFFSET[0]) + 'px'); - } else { - bubble.css('left', position[0] + OFFSET[0] + 'px'); - } - if (goUp) { - bubble.css('bottom', (winDim[1] - position[1] + OFFSET[1]) + 'px'); - } else { - bubble.css('top', position[1] + OFFSET[1] + 'px'); - } - - // Add the menu to the body - body.append(bubble); - - // Return a function to dismiss the bubble - return function () { bubble.remove(); }; + // Position the bubble + bubble.css('position', 'absolute'); + if (goLeft) { + bubble.css('right', (winDim[0] - position[0] + OFFSET[0]) + 'px'); + } else { + bubble.css('left', position[0] + OFFSET[0] + 'px'); + } + if (goUp) { + bubble.css('bottom', (winDim[1] - position[1] + OFFSET[1]) + 'px'); + } else { + bubble.css('top', position[1] + OFFSET[1] + 'px'); } - return { - /** - * Display an info bubble at the specified location. - * @param {string} templateKey template to place in bubble - * @param {string} title title for the bubble - * @param {*} content content to pass to the template, via - * `ng-model` - * @param {number[]} x,y position of the info bubble, in - * pixel coordinates. - * @returns {Function} a function that may be invoked to - * dismiss the info bubble - * @memberof platform/commonUI/inspect.InfoService# - */ - display: display - }; + // Add the menu to the body + body.append(bubble); + + // Return a function to dismiss the bubble + return function () { bubble.remove(); }; } return InfoService; From aa08db1050b14800bb27797b56e61729f7a075b0 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 11 Aug 2015 10:43:03 -0700 Subject: [PATCH 42/84] [Code Style] Avoid copying window/scope Avoids Angular errors; WTD-1482. --- .../commonUI/dialog/src/OverlayService.js | 15 ++++++++--- .../representers/EditToolbarRepresenter.js | 25 +++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/platform/commonUI/dialog/src/OverlayService.js b/platform/commonUI/dialog/src/OverlayService.js index 043f638700..5faba5dcf6 100644 --- a/platform/commonUI/dialog/src/OverlayService.js +++ b/platform/commonUI/dialog/src/OverlayService.js @@ -47,9 +47,16 @@ define( * @constructor */ function OverlayService($document, $compile, $rootScope) { - this.$document = $document; this.$compile = $compile; - this.$rootScope = $rootScope; + + // Don't include $document and $rootScope directly; + // avoids https://docs.angularjs.org/error/ng/cpws + this.findBody = function () { + return $document.find('body'); + }; + this.newScope = function () { + return $rootScope.$new(); + }; } /** @@ -67,7 +74,7 @@ define( */ OverlayService.prototype.createOverlay = function (key, overlayModel) { // Create a new scope for this overlay - var scope = this.$rootScope.$new(), + var scope = this.newScope(), element; // Stop showing the overlay; additionally, release the scope @@ -86,7 +93,7 @@ define( // Create the overlay element and add it to the document's body element = this.$compile(TEMPLATE)(scope); - this.$document.find('body').prepend(element); + this.findBody().prepend(element); return { dismiss: dismiss diff --git a/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js b/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js index 059b5e13f8..daf3645b69 100644 --- a/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js +++ b/platform/commonUI/edit/src/representers/EditToolbarRepresenter.js @@ -91,8 +91,22 @@ define( } } + // Avoid attaching scope to this; + // http://errors.angularjs.org/1.2.26/ng/cpws + this.setSelection = function (s) { + scope.selection = s; + }; + this.clearExposedToolbar = function () { + // Clear exposed toolbar state (if any) + if (attrs.toolbar) { + delete scope.$parent[attrs.toolbar]; + } + }; + this.exposeToolbar = function () { + scope.$parent[self.attrs.toolbar] = self.toolbarObject; + }; + this.commit = commit; - this.scope = scope; this.attrs = attrs; this.updateSelection = updateSelection; this.toolbar = undefined; @@ -127,24 +141,21 @@ define( // Initialize toolbar object self.toolbar = new EditToolbar(definition, self.commit); // Ensure toolbar state is exposed - self.scope.$parent[self.attrs.toolbar] = self.toolbarObject; + self.exposeToolbar(); } } // Expose the toolbar object to the parent scope initialize(definition); // Create a selection scope - this.scope.selection = new EditToolbarSelection(); + this.setSelection(new EditToolbarSelection()); // Initialize toolbar to an empty selection this.updateSelection([]); }; // Destroy; remove toolbar object from parent scope EditToolbarRepresenter.prototype.destroy = function () { - // Clear exposed toolbar state (if any) - if (this.attrs.toolbar) { - delete this.scope.$parent[this.attrs.toolbar]; - } + this.clearExposedToolbar(); }; return EditToolbarRepresenter; From f377c7cb716122f09cd3393f366735bd4d48e3c6 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 11 Aug 2015 11:01:13 -0700 Subject: [PATCH 43/84] [Code Style] Use prototypes in containment bundle WTD-1482. --- platform/containment/src/CapabilityTable.js | 28 +++---- .../containment/src/ComposeActionPolicy.js | 73 ++++++++++--------- .../containment/src/CompositionModelPolicy.js | 19 ++--- .../src/CompositionMutabilityPolicy.js | 22 ++---- platform/containment/src/CompositionPolicy.js | 18 ++--- platform/containment/src/ContainmentTable.js | 48 ++++++------ 6 files changed, 94 insertions(+), 114 deletions(-) diff --git a/platform/containment/src/CapabilityTable.js b/platform/containment/src/CapabilityTable.js index 5a2374af5d..db89f9e68f 100644 --- a/platform/containment/src/CapabilityTable.js +++ b/platform/containment/src/CapabilityTable.js @@ -36,7 +36,7 @@ define( * @memberof platform/containment */ function CapabilityTable(typeService, capabilityService) { - var table = {}; + var self = this; // Build an initial model for a type function buildModel(type) { @@ -54,26 +54,26 @@ define( function addToTable(type) { var typeKey = type.getKey(); Object.keys(getCapabilities(type)).forEach(function (key) { - table[key] = table[key] || {}; - table[key][typeKey] = true; + self.table[key] = self.table[key] || {}; + self.table[key][typeKey] = true; }); } // Build the table + this.table = {}; (typeService.listTypes() || []).forEach(addToTable); - - return { - /** - * Check if a type is expected to expose a specific - * capability. - * @memberof platform/containment.CapabilityTable# - */ - hasCapability: function (typeKey, capabilityKey) { - return (table[capabilityKey] || {})[typeKey]; - } - }; } + /** + * Check if a type is expected to expose a specific capability. + * @param {string} typeKey the type identifier + * @param {string} capabilityKey the capability identifier + * @returns {boolean} true if expected to be exposed + */ + CapabilityTable.prototype.hasCapability = function (typeKey, capabilityKey) { + return (this.table[capabilityKey] || {})[typeKey]; + }; + return CapabilityTable; } ); diff --git a/platform/containment/src/ComposeActionPolicy.js b/platform/containment/src/ComposeActionPolicy.js index 90c7983bc9..53a1bf0ab8 100644 --- a/platform/containment/src/ComposeActionPolicy.js +++ b/platform/containment/src/ComposeActionPolicy.js @@ -36,47 +36,48 @@ define( * Angular's `$injector`. * @constructor * @memberof platform/containment + * @implements {Policy.} */ function ComposeActionPolicy($injector) { - var policyService; - - function allowComposition(containerObject, selectedObject) { - // Get the object types involved in the compose action - var containerType = containerObject && - containerObject.getCapability('type'), - selectedType = selectedObject && - selectedObject.getCapability('type'); - - // Get a reference to the policy service if needed... - policyService = policyService || $injector.get('policyService'); - - // ...and delegate to the composition policy - return policyService.allow( - 'composition', - containerType, - selectedType - ); - } - - return { - /** - * Check whether or not a compose action should be allowed - * in this context. - * @returns {boolean} true if it may be allowed - * @memberof platform/containment.ComposeActionPolicy# - */ - allow: function (candidate, context) { - if (candidate.getMetadata().key === 'compose') { - return allowComposition( - (context || {}).domainObject, - (context || {}).selectedObject - ); - } - return true; - } + this.getPolicyService = function () { + return $injector.get('policyService'); }; } + ComposeActionPolicy.prototype.allowComposition = function (containerObject, selectedObject) { + // Get the object types involved in the compose action + var containerType = containerObject && + containerObject.getCapability('type'), + selectedType = selectedObject && + selectedObject.getCapability('type'); + + // Get a reference to the policy service if needed... + this.policyService = this.policyService || this.getPolicyService(); + + // ...and delegate to the composition policy + return this.policyService.allow( + 'composition', + containerType, + selectedType + ); + } + + /** + * Check whether or not a compose action should be allowed + * in this context. + * @returns {boolean} true if it may be allowed + * @memberof platform/containment.ComposeActionPolicy# + */ + ComposeActionPolicy.prototype.allow = function (candidate, context) { + if (candidate.getMetadata().key === 'compose') { + return this.allowComposition( + (context || {}).domainObject, + (context || {}).selectedObject + ); + } + return true; + }; + return ComposeActionPolicy; } diff --git a/platform/containment/src/CompositionModelPolicy.js b/platform/containment/src/CompositionModelPolicy.js index 0c76097ed4..d5e5cb5f72 100644 --- a/platform/containment/src/CompositionModelPolicy.js +++ b/platform/containment/src/CompositionModelPolicy.js @@ -10,22 +10,17 @@ define( * have a composition property. * @constructor * @memberof platform/containment + * @implements {Policy.} */ function CompositionModelPolicy() { - return { - /** - * Is the type identified by the candidate allowed to - * contain the type described by the context? - * @memberof platform/containment.CompositionModelPolicy# - */ - allow: function (candidate, context) { - return Array.isArray( - (candidate.getInitialModel() || {}).composition - ); - } - }; } + CompositionModelPolicy.prototype.allow = function (candidate, context) { + return Array.isArray( + (candidate.getInitialModel() || {}).composition + ); + }; + return CompositionModelPolicy; } ); diff --git a/platform/containment/src/CompositionMutabilityPolicy.js b/platform/containment/src/CompositionMutabilityPolicy.js index 375f26e405..8c5ef6a765 100644 --- a/platform/containment/src/CompositionMutabilityPolicy.js +++ b/platform/containment/src/CompositionMutabilityPolicy.js @@ -30,24 +30,18 @@ define( * Disallow composition changes to objects which are not mutable. * @memberof platform/containment * @constructor + * @implements {Policy.} */ function CompositionMutabilityPolicy() { - return { - /** - * Is the type identified by the candidate allowed to - * contain the type described by the context? - * @param {Type} candidate the type of domain object - * @memberof platform/containment.CompositionMutabilityPolicy# - */ - allow: function (candidate) { - // Equate creatability with mutability; that is, users - // can only modify objects of types they can create, and - // vice versa. - return candidate.hasFeature('creation'); - } - }; } + CompositionMutabilityPolicy.prototype.allow = function (candidate) { + // Equate creatability with mutability; that is, users + // can only modify objects of types they can create, and + // vice versa. + return candidate.hasFeature('creation'); + }; + return CompositionMutabilityPolicy; } ); diff --git a/platform/containment/src/CompositionPolicy.js b/platform/containment/src/CompositionPolicy.js index 9445803557..1f5239ec59 100644 --- a/platform/containment/src/CompositionPolicy.js +++ b/platform/containment/src/CompositionPolicy.js @@ -35,31 +35,25 @@ define( * Defines composition policy as driven by type metadata. * @constructor * @memberof platform/containment + * @implements {Policy.} */ function CompositionPolicy($injector) { // We're really just wrapping the containment table and rephrasing // it as a policy decision. var table; - function getTable() { + this.getTable = function () { return (table = table || new ContainmentTable( $injector.get('typeService'), $injector.get('capabilityService') )); - } - - return { - /** - * Is the type identified by the candidate allowed to - * contain the type described by the context? - * @memberof platform/containment.CompositionPolicy# - */ - allow: function (candidate, context) { - return getTable().canContain(candidate, context); - } }; } + CompositionPolicy.prototype.allow = function (candidate, context) { + return this.getTable().canContain(candidate, context); + }; + return CompositionPolicy; } ); diff --git a/platform/containment/src/ContainmentTable.js b/platform/containment/src/ContainmentTable.js index a71570ca3a..823c782faf 100644 --- a/platform/containment/src/ContainmentTable.js +++ b/platform/containment/src/ContainmentTable.js @@ -41,13 +41,9 @@ define( * @memberof platform/containment */ function ContainmentTable(typeService, capabilityService) { - var types = typeService.listTypes(), - capabilityTable = new CapabilityTable(typeService, capabilityService), - table = {}; - - // Check if one type can contain another - function canContain(containerType, containedType) { - } + var self = this, + types = typeService.listTypes(), + capabilityTable = new CapabilityTable(typeService, capabilityService); // Add types which have all these capabilities to the set // of allowed types @@ -84,39 +80,39 @@ define( // Check for defined containment restrictions if (contains === undefined) { // If not, accept anything - table[key] = ANY; + self.table[key] = ANY; } else { // Start with an empty set... - table[key] = {}; + self.table[key] = {}; // ...cast accepted types to array if necessary... contains = Array.isArray(contains) ? contains : [contains]; // ...and add all containment rules to that set contains.forEach(function (c) { - addToSet(table[key], c); + addToSet(self.table[key], c); }); } } // Build the table + this.table = {}; types.forEach(addToTable); - - return { - /** - * Check if domain objects of one type can contain domain - * objects of another type. - * @returns {boolean} true if allowable - * @memberof platform/containment.ContainmentTable# - */ - canContain: function (containerType, containedType) { - var set = table[containerType.getKey()] || {}; - // Recognize either the symbolic value for "can contain - // anything", or lookup the specific type from the set. - return (set === ANY) || set[containedType.getKey()]; - } - }; - } + /** + * Check if domain objects of one type can contain domain + * objects of another type. + * @param {Type} containerType type of the containing domain object + * @param {Type} containedType type of the domain object + * to be contained + * @returns {boolean} true if allowable + */ + ContainmentTable.prototype.canContain = function (containerType, containedType) { + var set = this.table[containerType.getKey()] || {}; + // Recognize either the symbolic value for "can contain + // anything", or lookup the specific type from the set. + return (set === ANY) || set[containedType.getKey()]; + }; + return ContainmentTable; } ); From b7765ff388a0eb23b3435a40c8498de374bcfa01 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 11 Aug 2015 12:54:50 -0700 Subject: [PATCH 44/84] [Code Style] Use prototypes in platform WTD-1482 --- platform/core/src/actions/ActionAggregator.js | 44 +-- platform/core/src/actions/ActionCapability.js | 106 ++++--- platform/core/src/actions/ActionProvider.js | 127 ++++----- .../src/actions/LoggingActionDecorator.js | 45 ++- .../src/capabilities/CompositionCapability.js | 103 ++++--- .../src/capabilities/ContextCapability.js | 135 +++++---- .../capabilities/ContextualDomainObject.js | 1 + .../capabilities/CoreCapabilityProvider.js | 13 + .../src/capabilities/DelegationCapability.js | 112 ++++---- .../src/capabilities/MetadataCapability.js | 38 +-- .../src/capabilities/MutationCapability.js | 161 +++++------ .../src/capabilities/PersistenceCapability.js | 145 +++++----- .../capabilities/RelationshipCapability.js | 148 +++++----- .../core/src/models/CachingModelDecorator.js | 88 +++--- .../core/src/models/MissingModelDecorator.js | 37 +-- platform/core/src/models/ModelAggregator.js | 104 +++---- .../core/src/models/PersistedModelProvider.js | 80 +++--- platform/core/src/models/RootModelProvider.js | 47 ++-- .../core/src/models/StaticModelProvider.js | 39 +-- platform/core/src/objects/DomainObject.js | 134 --------- platform/core/src/objects/DomainObjectImpl.js | 143 ++++++++++ .../core/src/objects/DomainObjectProvider.js | 75 ++--- platform/core/src/services/Now.js | 1 - platform/core/src/services/Throttle.js | 1 - platform/core/src/services/Topic.js | 1 - platform/core/src/types/TypeCapability.js | 2 + platform/core/src/types/TypeImpl.js | 264 +++++++++--------- platform/core/src/types/TypeProperty.js | 210 +++++++------- .../core/src/types/TypePropertyConversion.js | 17 ++ platform/core/src/types/TypeProvider.js | 199 +++++++------ platform/core/src/views/ViewCapability.js | 26 +- platform/core/src/views/ViewProvider.js | 56 ++-- .../core/test/objects/DomainObjectSpec.js | 2 +- platform/core/test/types/TypeImplSpec.js | 4 +- platform/core/test/types/TypeProviderSpec.js | 2 +- 35 files changed, 1331 insertions(+), 1379 deletions(-) delete mode 100644 platform/core/src/objects/DomainObject.js create mode 100644 platform/core/src/objects/DomainObjectImpl.js diff --git a/platform/core/src/actions/ActionAggregator.js b/platform/core/src/actions/ActionAggregator.js index d0094a8a90..3056ab04e8 100644 --- a/platform/core/src/actions/ActionAggregator.js +++ b/platform/core/src/actions/ActionAggregator.js @@ -108,41 +108,19 @@ define( * of action services */ function ActionAggregator(actionProviders) { - - function getActions(context) { - // Get all actions from all providers, reduce down - // to one array by concatenation - return actionProviders.map(function (provider) { - return provider.getActions(context); - }).reduce(function (a, b) { - return a.concat(b); - }, []); - } - - return { - /** - * Get a list of actions which are valid in a given - * context. - * - * @param {ActionContext} the context in which - * the action will occur; this is a - * JavaScript object containing key-value - * pairs. Typically, this will contain a - * field "domainObject" which refers to - * the domain object that will be acted - * upon, but may contain arbitrary information - * recognized by specific providers. - * @return {Action[]} an array of actions which - * may be performed in the provided context. - * - * @method - * @memberof ActionAggregator - * @memberof platform/core.ActionAggregator# - */ - getActions: getActions - }; + this.actionProviders = actionProviders; } + ActionAggregator.prototype.getActions = function (context) { + // Get all actions from all providers, reduce down + // to one array by concatenation + return this.actionProviders.map(function (provider) { + return provider.getActions(context); + }).reduce(function (a, b) { + return a.concat(b); + }, []); + }; + return ActionAggregator; } ); diff --git a/platform/core/src/actions/ActionCapability.js b/platform/core/src/actions/ActionCapability.js index b5d055bcb0..2164969a05 100644 --- a/platform/core/src/actions/ActionCapability.js +++ b/platform/core/src/actions/ActionCapability.js @@ -49,71 +49,69 @@ define( * @constructor */ function ActionCapability($q, actionService, domainObject) { + this.$q = $q; + this.actionService = actionService; + this.domainObject = domainObject; + } + /** + * Perform an action. This will find and perform the + * first matching action available for the specified + * context or key. + * + * @param {ActionContext|string} context the context in which + * to perform the action; this is passed along to + * the action service to match against available + * actions. The "domainObject" field will automatically + * be populated with the domain object that exposed + * this capability. If given as a string, this will + * be taken as the "key" field to match against + * specific actions. + * @returns {Promise} the result of the action that was + * performed, or undefined if no matching action + * was found. + * @memberof platform/core.ActionCapability# + */ + ActionCapability.prototype.getActions = function (context) { // Get all actions which are valid in this context; // this simply redirects to the action service, // but additionally adds a domainObject field. - function getActions(context) { - var baseContext = typeof context === 'string' ? - { key: context } : - (context || {}), - actionContext = Object.create(baseContext); + var baseContext = typeof context === 'string' ? + { key: context } : (context || {}), + actionContext = Object.create(baseContext); - actionContext.domainObject = domainObject; + actionContext.domainObject = this.domainObject; - return actionService.getActions(actionContext); - } + return this.actionService.getActions(actionContext); + }; + /** + * Get actions which are available for this domain object, + * in this context. + * + * @param {ActionContext|string} context the context in which + * to perform the action; this is passed along to + * the action service to match against available + * actions. The "domainObject" field will automatically + * be populated with the domain object that exposed + * this capability. If given as a string, this will + * be taken as the "key" field to match against + * specific actions. + * @returns {Action[]} an array of matching actions + * @memberof platform/core.ActionCapability# + */ + ActionCapability.prototype.perform = function (context) { // Alias to getActions(context)[0].perform, with a // check for empty arrays. - function performAction(context) { - var actions = getActions(context); + var actions = this.getActions(context); - return $q.when( - (actions && actions.length > 0) ? - actions[0].perform() : - undefined - ); - } + return this.$q.when( + (actions && actions.length > 0) ? + actions[0].perform() : + undefined + ); + }; - return { - /** - * Perform an action. This will find and perform the - * first matching action available for the specified - * context or key. - * - * @param {ActionContext|string} context the context in which - * to perform the action; this is passed along to - * the action service to match against available - * actions. The "domainObject" field will automatically - * be populated with the domain object that exposed - * this capability. If given as a string, this will - * be taken as the "key" field to match against - * specific actions. - * @returns {Promise} the result of the action that was - * performed, or undefined if no matching action - * was found. - * @memberof platform/core.ActionCapability# - */ - perform: performAction, - /** - * Get actions which are available for this domain object, - * in this context. - * - * @param {ActionContext|string} context the context in which - * to perform the action; this is passed along to - * the action service to match against available - * actions. The "domainObject" field will automatically - * be populated with the domain object that exposed - * this capability. If given as a string, this will - * be taken as the "key" field to match against - * specific actions. - * @returns {Action[]} an array of matching actions - * @memberof platform/core.ActionCapability# - */ - getActions: getActions - }; - } return ActionCapability; } diff --git a/platform/core/src/actions/ActionProvider.js b/platform/core/src/actions/ActionProvider.js index 67bc56520f..dcb17eb6ce 100644 --- a/platform/core/src/actions/ActionProvider.js +++ b/platform/core/src/actions/ActionProvider.js @@ -36,11 +36,45 @@ define( * category of extension.) * * @memberof platform/core + * @imeplements {ActionService} * @constructor */ function ActionProvider(actions) { - var actionsByKey = {}, - actionsByCategory = {}; + var self = this; + + // Build up look-up tables + this.actions = actions; + this.actionsByKey = {}; + this.actionsByCategory = {}; + actions.forEach(function (Action) { + // Get an action's category or categories + var categories = Action.category || []; + + // Convert to an array if necessary + categories = Array.isArray(categories) ? + categories : [categories]; + + // Store action under all relevant categories + categories.forEach(function (category) { + self.actionsByCategory[category] = + self.actionsByCategory[category] || []; + self.actionsByCategory[category].push(Action); + }); + + // Store action by ekey as well + if (Action.key) { + self.actionsByKey[Action.key] = + self.actionsByKey[Action.key] || []; + self.actionsByKey[Action.key].push(Action); + } + }); + } + + ActionProvider.prototype.getActions = function (actionContext) { + var context = (actionContext || {}), + category = context.category, + key = context.key, + candidates; // Instantiate an action; invokes the constructor and // additionally fills in the action's getMetadata method @@ -71,86 +105,31 @@ define( function createIfApplicable(actions, context) { return (actions || []).filter(function (Action) { return Action.appliesTo ? - Action.appliesTo(context) : true; + Action.appliesTo(context) : true; }).map(function (Action) { return instantiateAction(Action, context); }); } - // Get an array of actions that are valid in the supplied context. - function getActions(actionContext) { - var context = (actionContext || {}), - category = context.category, - key = context.key, - candidates; - - // Match actions to the provided context by comparing "key" - // and/or "category" parameters, if specified. - candidates = actions; - if (key) { - candidates = actionsByKey[key]; - if (category) { - candidates = candidates.filter(function (Action) { - return Action.category === category; - }); - } - } else if (category) { - candidates = actionsByCategory[category]; + // Match actions to the provided context by comparing "key" + // and/or "category" parameters, if specified. + candidates = this.actions; + if (key) { + candidates = this.actionsByKey[key]; + if (category) { + candidates = candidates.filter(function (Action) { + return Action.category === category; + }); } - - // Instantiate those remaining actions, with additional - // filtering per any appliesTo methods defined on those - // actions. - return createIfApplicable(candidates, context); + } else if (category) { + candidates = this.actionsByCategory[category]; } - // Build up look-up tables - actions.forEach(function (Action) { - // Get an action's category or categories - var categories = Action.category || []; - - // Convert to an array if necessary - categories = Array.isArray(categories) ? - categories : [categories]; - - // Store action under all relevant categories - categories.forEach(function (category) { - actionsByCategory[category] = - actionsByCategory[category] || []; - actionsByCategory[category].push(Action); - }); - - // Store action by ekey as well - if (Action.key) { - actionsByKey[Action.key] = - actionsByKey[Action.key] || []; - actionsByKey[Action.key].push(Action); - } - }); - - return { - /** - * Get a list of actions which are valid in a given - * context. - * - * @param {ActionContext} the context in which - * the action will occur; this is a - * JavaScript object containing key-value - * pairs. Typically, this will contain a - * field "domainObject" which refers to - * the domain object that will be acted - * upon, but may contain arbitrary information - * recognized by specific providers. - * @return {Action[]} an array of actions which - * may be performed in the provided context. - * - * @method - * @memberof ActionProvider - * @memberof platform/core.ActionProvider# - */ - getActions: getActions - }; - } + // Instantiate those remaining actions, with additional + // filtering per any appliesTo methods defined on those + // actions. + return createIfApplicable(candidates, context); + }; return ActionProvider; } diff --git a/platform/core/src/actions/LoggingActionDecorator.js b/platform/core/src/actions/LoggingActionDecorator.js index cb6efa245e..0d6f170261 100644 --- a/platform/core/src/actions/LoggingActionDecorator.js +++ b/platform/core/src/actions/LoggingActionDecorator.js @@ -36,8 +36,19 @@ define( * * @memberof platform/core * @constructor + * @implements {ActionService} + * @param $log Angular's logging service + * @param {ActionService} actionService the decorated action service */ function LoggingActionDecorator($log, actionService) { + this.$log = $log; + this.actionService = actionService; + } + + LoggingActionDecorator.prototype.getActions = function () { + var actionService = this.actionService, + $log = this.$log; + // Decorate the perform method of the specified action, such that // it emits a log message whenever performed. function addLogging(action) { @@ -59,35 +70,11 @@ define( return logAction; } - return { - /** - * Get a list of actions which are valid in a given - * context. These actions will additionally log - * themselves when performed. - * - * @param {ActionContext} the context in which - * the action will occur; this is a - * JavaScript object containing key-value - * pairs. Typically, this will contain a - * field "domainObject" which refers to - * the domain object that will be acted - * upon, but may contain arbitrary information - * recognized by specific providers. - * @return {Action[]} an array of actions which - * may be performed in the provided context. - * - * @method - * @memberof LoggingActionDecorator - * @memberof platform/core.LoggingActionDecorator# - */ - getActions: function () { - return actionService.getActions.apply( - actionService, - arguments - ).map(addLogging); - } - }; - } + return actionService.getActions.apply( + actionService, + arguments + ).map(addLogging); + }; return LoggingActionDecorator; } diff --git a/platform/core/src/capabilities/CompositionCapability.js b/platform/core/src/capabilities/CompositionCapability.js index 88ed279dd7..f1b2532040 100644 --- a/platform/core/src/capabilities/CompositionCapability.js +++ b/platform/core/src/capabilities/CompositionCapability.js @@ -39,68 +39,59 @@ define( * * @memberof platform/core * @constructor + * @implements {Capability} */ function CompositionCapability($injector, domainObject) { - var objectService, - lastPromise, - lastModified; - // Get a reference to the object service from $injector - function injectObjectService() { - objectService = $injector.get("objectService"); - return objectService; - } - - // Get a reference to the object service (either cached or - // from the injector) - function getObjectService() { - return objectService || injectObjectService(); - } - - // Promise this domain object's composition (an array of domain - // object instances corresponding to ids in its model.) - function promiseComposition() { - var model = domainObject.getModel(), - ids; - - // Then filter out non-existent objects, - // and wrap others (such that they expose a - // "context" capability) - function contextualize(objects) { - return ids.filter(function (id) { - return objects[id]; - }).map(function (id) { - return new ContextualDomainObject( - objects[id], - domainObject - ); - }); - } - - // Make a new request if we haven't made one, or if the - // object has been modified. - if (!lastPromise || lastModified !== model.modified) { - ids = model.composition || []; - lastModified = model.modified; - // Load from the underlying object service - lastPromise = getObjectService().getObjects(ids) - .then(contextualize); - } - - return lastPromise; - } - - return { - /** - * Request the composition of this object. - * @returns {Promise.} a list of all domain - * objects which compose this domain object. - * @memberof platform/core.CompositionCapability# - */ - invoke: promiseComposition + this.injectObjectService = function () { + this.objectService = $injector.get("objectService"); }; + + this.domainObject = domainObject; } + /** + * Request the composition of this object. + * @returns {Promise.} a list of all domain + * objects which compose this domain object. + */ + CompositionCapability.prototype.invoke = function () { + var domainObject = this.domainObject, + model = domainObject.getModel(), + ids; + + // Then filter out non-existent objects, + // and wrap others (such that they expose a + // "context" capability) + function contextualize(objects) { + return ids.filter(function (id) { + return objects[id]; + }).map(function (id) { + return new ContextualDomainObject( + objects[id], + domainObject + ); + }); + } + + // Lazily acquire object service (avoids cyclical dependency) + if (!this.objectService) { + this.injectObjectService(); + } + + // Make a new request if we haven't made one, or if the + // object has been modified. + if (!this.lastPromise || this.lastModified !== model.modified) { + ids = model.composition || []; + this.lastModified = model.modified; + // Load from the underlying object service + this.lastPromise = this.objectService.getObjects(ids) + .then(contextualize); + } + + return this.lastPromise; + }; + /** * Test to determine whether or not this capability should be exposed * by a domain object based on its model. Checks for the presence of diff --git a/platform/core/src/capabilities/ContextCapability.js b/platform/core/src/capabilities/ContextCapability.js index d94c7ed3f6..9ffaf4a5bb 100644 --- a/platform/core/src/capabilities/ContextCapability.js +++ b/platform/core/src/capabilities/ContextCapability.js @@ -38,79 +38,76 @@ define( * * @memberof platform/core * @constructor + * @implements {Capability} */ function ContextCapability(parentObject, domainObject) { - return { - /** - * Get the immediate parent of a domain object. - * - * A domain object may be contained in multiple places; its - * parent (as exposed by this capability) is the domain - * object from which this object was accessed, usually - * by way of a `composition` capability. - * - * @returns {DomainObject} the immediate parent of this - * domain object. - * @memberof platform/core.ContextCapability# - */ - getParent: function () { - return parentObject; - }, - /** - * Get an array containing the complete direct ancestry - * of this domain object, including the domain object - * itself. - * - * A domain object may be contained in multiple places; its - * parent and all ancestors (as exposed by this capability) - * serve as a record of how this specific domain object - * instance was reached. - * - * The first element in the returned array is the deepest - * ancestor; subsequent elements are progressively more - * recent ancestors, with the domain object which exposed - * the capability occupying the last element of the array. - * - * @returns {DomainObject[]} the full composition ancestry - * of the domain object which exposed this - * capability. - * @memberof platform/core.ContextCapability# - */ - getPath: function () { - var parentPath = [], - parentContext; - - if (parentObject) { - parentContext = parentObject.getCapability("context"); - parentPath = parentContext ? - parentContext.getPath() : - [parentObject]; - } - - return parentPath.concat([domainObject]); - }, - /** - * Get the deepest ancestor available for this domain object; - * equivalent to `getPath()[0]`. - * - * See notes on `getPath()` for how ancestry is defined in - * the context of this capability. - * - * @returns {DomainObject} the deepest ancestor of the domain - * object which exposed this capability. - * @memberof platform/core.ContextCapability# - */ - getRoot: function () { - var parentContext = parentObject && - parentObject.getCapability('context'); - - return parentContext ? - parentContext.getRoot() : - (parentObject || domainObject); - } - }; + this.parentObject = parentObject; + this.domainObject = domainObject; } + /** + * Get the immediate parent of a domain object. + * + * A domain object may be contained in multiple places; its + * parent (as exposed by this capability) is the domain + * object from which this object was accessed, usually + * by way of a `composition` capability. + * + * @returns {DomainObject} the immediate parent of this + * domain object. + */ + ContextCapability.prototype.getParent = function () { + return this.parentObject; + }; + + /** + * Get an array containing the complete direct ancestry + * of this domain object, including the domain object + * itself. + * + * A domain object may be contained in multiple places; its + * parent and all ancestors (as exposed by this capability) + * serve as a record of how this specific domain object + * instance was reached. + * + * The first element in the returned array is the deepest + * ancestor; subsequent elements are progressively more + * recent ancestors, with the domain object which exposed + * the capability occupying the last element of the array. + * + * @returns {DomainObject[]} the full composition ancestry + * of the domain object which exposed this + * capability. + */ + ContextCapability.prototype.getPath = function () { + var parentObject = this.parentObject, + parentContext = + parentObject && parentObject.getCapability('context'), + parentPath = parentContext ? + parentContext.getPath() : [ this.parentObject ]; + + return parentPath.concat([this.domainObject]); + }; + + /** + * Get the deepest ancestor available for this domain object; + * equivalent to `getPath()[0]`. + * + * See notes on `getPath()` for how ancestry is defined in + * the context of this capability. + * + * @returns {DomainObject} the deepest ancestor of the domain + * object which exposed this capability. + */ + ContextCapability.prototype.getRoot = function () { + var parentContext = this.parentObject && + this.parentObject.getCapability('context'); + + return parentContext ? + parentContext.getRoot() : + (this.parentObject || this.domainObject); + }; + return ContextCapability; } ); diff --git a/platform/core/src/capabilities/ContextualDomainObject.js b/platform/core/src/capabilities/ContextualDomainObject.js index 1475d3d384..2955515ead 100644 --- a/platform/core/src/capabilities/ContextualDomainObject.js +++ b/platform/core/src/capabilities/ContextualDomainObject.js @@ -44,6 +44,7 @@ define( * * @memberof platform/core * @constructor + * @implements {DomainObject} */ function ContextualDomainObject(domainObject, parentObject) { // Prototypally inherit from the domain object, and diff --git a/platform/core/src/capabilities/CoreCapabilityProvider.js b/platform/core/src/capabilities/CoreCapabilityProvider.js index a1148430f2..7b1ba070d7 100644 --- a/platform/core/src/capabilities/CoreCapabilityProvider.js +++ b/platform/core/src/capabilities/CoreCapabilityProvider.js @@ -29,6 +29,19 @@ define( function () { "use strict"; + /** + * A capability provides an interface with dealing with some + * dynamic behavior associated with a domain object. + * @interface Capability + */ + + /** + * Optional; if present, will be used by `DomainObject#useCapability` + * to simplify interaction with a specific capability. Parameters + * and return values vary depending on capability type. + * @method Capability#invoke + */ + /** * Provides capabilities based on extension definitions, * matched to domain object models. diff --git a/platform/core/src/capabilities/DelegationCapability.js b/platform/core/src/capabilities/DelegationCapability.js index 2259e5c420..0c62c05f00 100644 --- a/platform/core/src/capabilities/DelegationCapability.js +++ b/platform/core/src/capabilities/DelegationCapability.js @@ -45,13 +45,40 @@ define( * in the type's definition, which contains an array of names of * capabilities to be delegated. * - * @param domainObject + * @param $q Angular's $q, for promises + * @param {DomainObject} domainObject the delegating domain object * @memberof platform/core * @constructor + * @implements {Capability} */ function DelegationCapability($q, domainObject) { - var delegateCapabilities = {}, - type = domainObject.getCapability("type"); + var type = domainObject.getCapability("type"), + self = this; + + this.$q = $q; + this.delegateCapabilities = {}; + this.domainObject = domainObject; + + // Generate set for easy lookup of capability delegation + if (type && type.getDefinition) { + (type.getDefinition().delegates || []).forEach(function (key) { + self.delegateCapabilities[key] = true; + }); + } + } + + + /** + * Get the domain objects which are intended to be delegated + * responsibility for some specific capability. + * + * @param {string} key the name of the delegated capability + * @returns {DomainObject[]} the domain objects to which + * responsibility for this capability is delegated. + * @memberof platform/core.DelegationCapability# + */ + DelegationCapability.prototype.getDelegates = function (key) { + var domainObject = this.domainObject; function filterObjectsWithCapability(capability) { return function (objects) { @@ -65,55 +92,40 @@ define( return domainObject.useCapability('composition'); } - function doesDelegate(key) { - return delegateCapabilities[key] || false; - } + return this.doesDelegateCapability(key) ? + promiseChildren().then( + filterObjectsWithCapability(key) + ) : + this.$q.when([]); + }; - function getDelegates(capability) { - return doesDelegate(capability) ? - promiseChildren().then( - filterObjectsWithCapability(capability) - ) : - $q.when([]); - } - - // Generate set for easy lookup of capability delegation - if (type && type.getDefinition) { - (type.getDefinition().delegates || []).forEach(function (key) { - delegateCapabilities[key] = true; - }); - } - - return { - /** - * Invoke this capability; alias of `getDelegates`, used to - * simplify usage, e.g.: - * - * `domainObject.useCapability("delegation", "telemetry")` - * - * ...will retrieve all members of a domain object's - * composition which have a "telemetry" capability. - * - * @param {string} the name of the delegated capability - * @returns {DomainObject[]} the domain objects to which - * responsibility for this capability is delegated. - * @memberof platform/core.DelegationCapability# - */ - invoke: getDelegates, - /** - * Get the domain objects which are intended to be delegated - * responsibility for some specific capability. - * - * @param {string} the name of the delegated capability - * @returns {DomainObject[]} the domain objects to which - * responsibility for this capability is delegated. - * @memberof platform/core.DelegationCapability# - */ - getDelegates: getDelegates, - doesDelegateCapability: doesDelegate - }; - } + /** + * Check if the domain object which exposed this capability + * wishes to delegate another capability. + * + * @param {string} key the capability to check for + * @returns {boolean} true if the capability is delegated + */ + DelegationCapability.prototype.doesDelegateCapability = function (key) { + return !!(this.delegateCapabilities[key]); + }; + /** + * Invoke this capability; alias of `getDelegates`, used to + * simplify usage, e.g.: + * + * `domainObject.useCapability("delegation", "telemetry")` + * + * ...will retrieve all members of a domain object's + * composition which have a "telemetry" capability. + * + * @param {string} the name of the delegated capability + * @returns {DomainObject[]} the domain objects to which + * responsibility for this capability is delegated. + * @memberof platform/core.DelegationCapability# + */ + DelegationCapability.prototype.invoke = + DelegationCapability.prototype.getDelegates; return DelegationCapability; diff --git a/platform/core/src/capabilities/MetadataCapability.js b/platform/core/src/capabilities/MetadataCapability.js index 027c9ffe1d..242b35b6dc 100644 --- a/platform/core/src/capabilities/MetadataCapability.js +++ b/platform/core/src/capabilities/MetadataCapability.js @@ -11,8 +11,6 @@ define( * @property {string} name the human-readable name of this property * @property {string} value the human-readable value of this property, * for this specific domain object - * @constructor - * @memberof platform/core */ var TIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; @@ -27,10 +25,23 @@ define( * `value` properties describing that domain object (suitable for * display.) * + * @param {DomainObject} domainObject the domain object whose + * metadata is to be exposed + * @implements {Capability} * @constructor + * @memberof platform/core */ function MetadataCapability(domainObject) { - var model = domainObject.getModel(); + this.domainObject = domainObject; + } + + /** + * Get metadata about this object. + * @returns {MetadataProperty[]} metadata about this object + */ + MetadataCapability.prototype.invoke = function () { + var domainObject = this.domainObject, + model = domainObject.getModel(); function hasDisplayableValue(metadataProperty) { var t = typeof metadataProperty.value; @@ -39,8 +50,8 @@ define( function formatTimestamp(timestamp) { return typeof timestamp === 'number' ? - (moment.utc(timestamp).format(TIME_FORMAT) + " UTC") : - undefined; + (moment.utc(timestamp).format(TIME_FORMAT) + " UTC") : + undefined; } function getProperties() { @@ -75,20 +86,9 @@ define( ]; } - function getMetadata() { - return getProperties().concat(getCommonMetadata()) - .filter(hasDisplayableValue); - } - - return { - /** - * Get metadata about this object. - * @returns {MetadataProperty[]} metadata about this object - * @memberof platform/core.MetadataCapability# - */ - invoke: getMetadata - }; - } + return getProperties().concat(getCommonMetadata()) + .filter(hasDisplayableValue); + }; return MetadataCapability; } diff --git a/platform/core/src/capabilities/MutationCapability.js b/platform/core/src/capabilities/MutationCapability.js index 8ba11be13b..b9f49ca969 100644 --- a/platform/core/src/capabilities/MutationCapability.js +++ b/platform/core/src/capabilities/MutationCapability.js @@ -69,100 +69,103 @@ define( * }); * ``` * + * @param {Function} topic a service for creating listeners + * @param {Function} now a service to get the current time * @param {DomainObject} domainObject the domain object * which will expose this capability * @memberof platform/core * @constructor + * @implements {Capability} */ function MutationCapability(topic, now, domainObject) { - var t = topic(TOPIC_PREFIX + domainObject.getId()); + this.mutationTopic = topic(TOPIC_PREFIX + domainObject.getId()); + this.now = now; + this.domainObject = domainObject; + } - function mutate(mutator, timestamp) { - // Get the object's model and clone it, so the - // mutator function has a temporary copy to work with. - var model = domainObject.getModel(), - clone = JSON.parse(JSON.stringify(model)), - useTimestamp = arguments.length > 1; + /** + * Modify the domain object's model, using a provided + * function. This function will receive a copy of the + * domain object's model as an argument; behavior + * varies depending on that function's return value: + * + * * If no value (or undefined) is returned by the mutator, + * the state of the model object delivered as the mutator's + * argument will become the domain object's new model. + * This is useful for writing code that modifies the model + * directly. + * * If a plain object is returned, that object will be used + * as the domain object's new model. + * * If boolean `false` is returned, the mutation will be + * cancelled. + * * If a promise is returned, its resolved value will be + * handled as one of the above. + * + * + * @param {Function} mutator the function which will make + * changes to the domain object's model. + * @param {number} [timestamp] timestamp to record for + * this mutation (otherwise, system time will be + * used) + * @returns {Promise.} a promise for the result + * of the mutation; true if changes were made. + */ + MutationCapability.prototype.mutate = function (mutator, timestamp) { + // Get the object's model and clone it, so the + // mutator function has a temporary copy to work with. + var domainObject = this.domainObject, + now = this.now, + t = this.mutationTopic, + model = domainObject.getModel(), + clone = JSON.parse(JSON.stringify(model)), + useTimestamp = arguments.length > 1; - // Function to handle copying values to the actual - function handleMutation(mutationResult) { - // If mutation result was undefined, just use - // the clone; this allows the mutator to omit return - // values and just change the model directly. - var result = mutationResult || clone; + // Function to handle copying values to the actual + function handleMutation(mutationResult) { + // If mutation result was undefined, just use + // the clone; this allows the mutator to omit return + // values and just change the model directly. + var result = mutationResult || clone; - // Allow mutators to change their mind by - // returning false. - if (mutationResult !== false) { - // Copy values if result was a different object - // (either our clone or some other new thing) - if (model !== result) { - copyValues(model, result); - } - model.modified = useTimestamp ? timestamp : now(); - t.notify(model); + // Allow mutators to change their mind by + // returning false. + if (mutationResult !== false) { + // Copy values if result was a different object + // (either our clone or some other new thing) + if (model !== result) { + copyValues(model, result); } - - // Report the result of the mutation - return mutationResult !== false; + model.modified = useTimestamp ? timestamp : now(); + t.notify(model); } - // Invoke the provided mutator, then make changes to - // the underlying model (if applicable.) - return fastPromise(mutator(clone)).then(handleMutation); + // Report the result of the mutation + return mutationResult !== false; } - function listen(listener) { - return t.listen(listener); - } + // Invoke the provided mutator, then make changes to + // the underlying model (if applicable.) + return fastPromise(mutator(clone)).then(handleMutation); + }; - return { - /** - * Alias of `mutate`, used to support useCapability. - * @memberof platform/core.MutationCapability# - */ - invoke: mutate, - /** - * Modify the domain object's model, using a provided - * function. This function will receive a copy of the - * domain object's model as an argument; behavior - * varies depending on that function's return value: - * - * * If no value (or undefined) is returned by the mutator, - * the state of the model object delivered as the mutator's - * argument will become the domain object's new model. - * This is useful for writing code that modifies the model - * directly. - * * If a plain object is returned, that object will be used - * as the domain object's new model. - * * If boolean `false` is returned, the mutation will be - * cancelled. - * * If a promise is returned, its resolved value will be - * handled as one of the above. - * - * - * @param {function} mutator the function which will make - * changes to the domain object's model. - * @param {number} [timestamp] timestamp to record for - * this mutation (otherwise, system time will be - * used) - * @returns {Promise.} a promise for the result - * of the mutation; true if changes were made. - * @memberof platform/core.MutationCapability# - */ - mutate: mutate, - /** - * Listen for mutations of this domain object's model. - * The provided listener will be invoked with the domain - * object's new model after any changes. To stop listening, - * invoke the function returned by this method. - * @param {Function} listener function to call on mutation - * @returns {Function} a function to stop listening - * @memberof platform/core.MutationCapability# - */ - listen: listen - }; - } + /** + * Listen for mutations of this domain object's model. + * The provided listener will be invoked with the domain + * object's new model after any changes. To stop listening, + * invoke the function returned by this method. + * @param {Function} listener function to call on mutation + * @returns {Function} a function to stop listening + * @memberof platform/core.MutationCapability# + */ + MutationCapability.prototype.listen = function (listener) { + return this.mutationTopic.listen(listener); + }; + + /** + * Alias of `mutate`, used to support useCapability. + */ + MutationCapability.prototype.invoke = + MutationCapability.prototype.mutate; return MutationCapability; } diff --git a/platform/core/src/capabilities/PersistenceCapability.js b/platform/core/src/capabilities/PersistenceCapability.js index de18b69222..8c7e08e17d 100644 --- a/platform/core/src/capabilities/PersistenceCapability.js +++ b/platform/core/src/capabilities/PersistenceCapability.js @@ -33,7 +33,7 @@ define( * * @param {PersistenceService} persistenceService the underlying * provider of persistence capabilities. - * @param {string} SPACE the name of the persistence space to + * @param {string} space the name of the persistence space to * use (this is an arbitrary string, useful in principle * for distinguishing different persistence stores from * one another.) @@ -42,10 +42,60 @@ define( * * @memberof platform/core * @constructor + * @implements {Capability} */ - function PersistenceCapability(persistenceService, SPACE, domainObject) { + function PersistenceCapability(persistenceService, space, domainObject) { // Cache modified timestamp - var modified = domainObject.getModel().modified; + this.modified = domainObject.getModel().modified; + + this.domainObject = domainObject; + this.space = space; + this.persistenceService = persistenceService; + } + + // Utility function for creating promise-like objects which + // resolve synchronously when possible + function fastPromise(value) { + return (value || {}).then ? value : { + then: function (callback) { + return fastPromise(callback(value)); + } + }; + } + + /** + * Persist any changes which have been made to this + * domain object's model. + * @returns {Promise} a promise which will be resolved + * if persistence is successful, and rejected + * if not. + */ + PersistenceCapability.prototype.persist = function () { + var domainObject = this.domainObject, + modified = domainObject.getModel().modified; + + // Update persistence timestamp... + domainObject.useCapability("mutation", function (model) { + model.persisted = modified; + }, modified); + + // ...and persist + return this.persistenceService.updateObject( + this.getSpace(), + domainObject.getId(), + domainObject.getModel() + ); + }; + + /** + * Update this domain object to match the latest from + * persistence. + * @returns {Promise} a promise which will be resolved + * when the update is complete + */ + PersistenceCapability.prototype.refresh = function () { + var domainObject = this.domainObject, + model = domainObject.getModel(); // Update a domain object's model upon refresh function updateModel(model) { @@ -55,75 +105,28 @@ define( }, modified); } - // For refresh; update a domain object model, only if there - // are no unsaved changes. - function updatePersistenceTimestamp() { - var modified = domainObject.getModel().modified; - domainObject.useCapability("mutation", function (model) { - model.persisted = modified; - }, modified); - } + // Only update if we don't have unsaved changes + return (model.modified === model.persisted) ? + this.persistenceService.readObject( + this.getSpace(), + this.domainObject.getId() + ).then(updateModel) : + fastPromise(false); + }; - // Utility function for creating promise-like objects which - // resolve synchronously when possible - function fastPromise(value) { - return (value || {}).then ? value : { - then: function (callback) { - return fastPromise(callback(value)); - } - }; - } - - return { - /** - * Persist any changes which have been made to this - * domain object's model. - * @returns {Promise} a promise which will be resolved - * if persistence is successful, and rejected - * if not. - * @memberof platform/core.PersistenceCapability# - */ - persist: function () { - updatePersistenceTimestamp(); - return persistenceService.updateObject( - SPACE, - domainObject.getId(), - domainObject.getModel() - ); - }, - /** - * Update this domain object to match the latest from - * persistence. - * @returns {Promise} a promise which will be resolved - * when the update is complete - * @memberof platform/core.PersistenceCapability# - */ - refresh: function () { - var model = domainObject.getModel(); - // Only update if we don't have unsaved changes - return (model.modified === model.persisted) ? - persistenceService.readObject( - SPACE, - domainObject.getId() - ).then(updateModel) : - fastPromise(false); - }, - /** - * Get the space in which this domain object is persisted; - * this is useful when, for example, decided which space a - * newly-created domain object should be persisted to (by - * default, this should be the space of its containing - * object.) - * - * @returns {string} the name of the space which should - * be used to persist this object - * @memberof platform/core.PersistenceCapability# - */ - getSpace: function () { - return SPACE; - } - }; - } + /** + * Get the space in which this domain object is persisted; + * this is useful when, for example, decided which space a + * newly-created domain object should be persisted to (by + * default, this should be the space of its containing + * object.) + * + * @returns {string} the name of the space which should + * be used to persist this object + */ + PersistenceCapability.prototype.getSpace = function () { + return this.space; + }; return PersistenceCapability; } diff --git a/platform/core/src/capabilities/RelationshipCapability.js b/platform/core/src/capabilities/RelationshipCapability.js index 3bbc210b36..7eb6d01bb9 100644 --- a/platform/core/src/capabilities/RelationshipCapability.js +++ b/platform/core/src/capabilities/RelationshipCapability.js @@ -40,92 +40,80 @@ define( * * @memberof platform/core * @constructor + * @implements {Capability} */ function RelationshipCapability($injector, domainObject) { - var objectService, - lastPromise = {}, - lastModified; - // Get a reference to the object service from $injector - function injectObjectService() { - objectService = $injector.get("objectService"); - return objectService; - } - - // Get a reference to the object service (either cached or - // from the injector) - function getObjectService() { - return objectService || injectObjectService(); - } - - // Promise this domain object's composition (an array of domain - // object instances corresponding to ids in its model.) - function promiseRelationships(key) { - var model = domainObject.getModel(), - ids; - - // Package objects as an array - function packageObject(objects) { - return ids.map(function (id) { - return objects[id]; - }).filter(function (obj) { - return obj; - }); - } - - // Clear cached promises if modification has occurred - if (lastModified !== model.modified) { - lastPromise = {}; - lastModified = model.modified; - } - - // Make a new request if needed - if (!lastPromise[key]) { - ids = (model.relationships || {})[key] || []; - lastModified = model.modified; - // Load from the underlying object service - lastPromise[key] = getObjectService().getObjects(ids) - .then(packageObject); - } - - return lastPromise[key]; - } - - // List types of relationships which this object has - function listRelationships() { - var relationships = - (domainObject.getModel() || {}).relationships || {}; - - // Check if this key really does expose an array of ids - // (to filter out malformed relationships) - function isArray(key) { - return Array.isArray(relationships[key]); - } - - return Object.keys(relationships).filter(isArray).sort(); - } - - return { - /** - * List all types of relationships exposed by this - * object. - * @returns {string[]} a list of all relationship types - * @memberof platform/core.RelationshipCapability# - */ - listRelationships: listRelationships, - /** - * Request related objects, with a given relationship type. - * This will typically require asynchronous lookup, so this - * returns a promise. - * @param {string} key the type of relationship - * @returns {Promise.} a promise for related - * domain objects - * @memberof platform/core.RelationshipCapability# - */ - getRelatedObjects: promiseRelationships + this.injectObjectService = function () { + this.objectService = $injector.get("objectService"); }; + + this.lastPromise = {}; + this.domainObject = domainObject; } + /** + * List all types of relationships exposed by this + * object. + * @returns {string[]} a list of all relationship types + */ + RelationshipCapability.prototype.listRelationships = function listRelationships() { + var relationships = + (this.domainObject.getModel() || {}).relationships || {}; + + // Check if this key really does expose an array of ids + // (to filter out malformed relationships) + function isArray(key) { + return Array.isArray(relationships[key]); + } + + return Object.keys(relationships).filter(isArray).sort(); + }; + + /** + * Request related objects, with a given relationship type. + * This will typically require asynchronous lookup, so this + * returns a promise. + * @param {string} key the type of relationship + * @returns {Promise.} a promise for related + * domain objects + */ + RelationshipCapability.prototype.getRelatedObjects = function (key) { + var model = this.domainObject.getModel(), + ids; + + // Package objects as an array + function packageObject(objects) { + return ids.map(function (id) { + return objects[id]; + }).filter(function (obj) { + return obj; + }); + } + + // Clear cached promises if modification has occurred + if (this.lastModified !== model.modified) { + this.lastPromise = {}; + this.lastModified = model.modified; + } + + // Make a new request if needed + if (!this.lastPromise[key]) { + ids = (model.relationships || {})[key] || []; + this.lastModified = model.modified; + // Lazily initialize object service now that we need it + if (!this.objectService) { + this.injectObjectService(); + } + // Load from the underlying object service + this.lastPromise[key] = this.objectService.getObjects(ids) + .then(packageObject); + } + + return this.lastPromise[key]; + }; + + /** * Test to determine whether or not this capability should be exposed * by a domain object based on its model. Checks for the presence of diff --git a/platform/core/src/models/CachingModelDecorator.js b/platform/core/src/models/CachingModelDecorator.js index c74cea05f0..a338d6770f 100644 --- a/platform/core/src/models/CachingModelDecorator.js +++ b/platform/core/src/models/CachingModelDecorator.js @@ -32,10 +32,30 @@ define( * object are not provided. * @memberof platform/core * @constructor + * @param {ModelService} modelService this service to decorate + * @implements {ModelService} */ function CachingModelDecorator(modelService) { - var cache = {}, - cached = {}; + this.cache = {}; + this.cached = {}; + this.modelService = modelService; + } + + // Fast-resolving promise + function fastPromise(value) { + return (value || {}).then ? value : { + then: function (callback) { + return fastPromise(callback(value)); + } + }; + } + + CachingModelDecorator.prototype.getModels = function (ids) { + var cache = this.cache, + cached = this.cached, + neededIds = ids.filter(function notCached(id) { + return !cached[id]; + }); // Update the cached instance of a model to a new value. // We update in-place to ensure there is only ever one instance @@ -68,30 +88,12 @@ define( return oldModel; } - // Fast-resolving promise - function fastPromise(value) { - return (value || {}).then ? value : { - then: function (callback) { - return fastPromise(callback(value)); - } - }; - } - - // Store this model in the cache - function cacheModel(id, model) { - cache[id] = cached[id] ? updateModel(id, model) : model; - cached[id] = true; - } - - // Check if an id is not in cache, for lookup filtering - function notCached(id) { - return !cached[id]; - } - // Store the provided models in our cache function cacheAll(models) { Object.keys(models).forEach(function (id) { - cacheModel(id, models[id]); + cache[id] = cached[id] ? + updateModel(id, models[id]) : models[id]; + cached[id] = true; }); } @@ -100,38 +102,16 @@ define( return cache; } - return { - /** - * Get models for these specified string identifiers. - * These will be given as an object containing keys - * and values, where keys are object identifiers and - * values are models. - * This result may contain either a subset or a - * superset of the total objects. - * - * @param {Array} ids the string identifiers for - * models of interest. - * @returns {Promise} a promise for an object - * containing key-value pairs, where keys are - * ids and values are models - * @method - * @memberof platform/core.CachingModelDecorator# - */ - getModels: function (ids) { - var neededIds = ids.filter(notCached); + // Look up if we have unknown IDs + if (neededIds.length > 0) { + return this.modelService.getModels(neededIds) + .then(cacheAll) + .then(giveCache); + } - // Look up if we have unknown IDs - if (neededIds.length > 0) { - return modelService.getModels(neededIds) - .then(cacheAll) - .then(giveCache); - } - - // Otherwise, just expose the cache directly - return fastPromise(cache); - } - }; - } + // Otherwise, just expose the cache directly + return fastPromise(cache); + }; return CachingModelDecorator; } diff --git a/platform/core/src/models/MissingModelDecorator.js b/platform/core/src/models/MissingModelDecorator.js index fca716733e..d3eb8f3159 100644 --- a/platform/core/src/models/MissingModelDecorator.js +++ b/platform/core/src/models/MissingModelDecorator.js @@ -29,33 +29,34 @@ define( /** * Adds placeholder domain object models for any models which * fail to load from the underlying model service. - * @implements {ModelService} * @constructor * @memberof platform/core + * @param {ModelService} modelService this service to decorate + * @implements {ModelService} */ function MissingModelDecorator(modelService) { - function missingModel(id) { - return { - type: "unknown", - name: "Missing: " + id - }; - } + this.modelService = modelService; + } + function missingModel(id) { return { - getModels: function (ids) { - function addMissingModels(models) { - var result = {}; - ids.forEach(function (id) { - result[id] = models[id] || missingModel(id); - }); - return result; - } - - return modelService.getModels(ids).then(addMissingModels); - } + type: "unknown", + name: "Missing: " + id }; } + MissingModelDecorator.prototype.getModels = function (ids) { + function addMissingModels(models) { + var result = {}; + ids.forEach(function (id) { + result[id] = models[id] || missingModel(id); + }); + return result; + } + + return this.modelService.getModels(ids).then(addMissingModels); + }; + return MissingModelDecorator; } ); diff --git a/platform/core/src/models/ModelAggregator.js b/platform/core/src/models/ModelAggregator.js index 437bba4ec3..d5f4060415 100644 --- a/platform/core/src/models/ModelAggregator.js +++ b/platform/core/src/models/ModelAggregator.js @@ -29,67 +29,71 @@ define( function () { "use strict"; + /** + * Allow domain object models to be looked up by their identifiers. + * + * @interface ModelService + */ + + /** + * Get domain object models. + * + * This may provide either a superset or a subset of the models + * requested. Absence of a model means it does not exist within + * this service instance. + * + * @method ModelService#getModels + * @param {string[]} ids identifiers for models desired. + * @returns {Promise.} a promise for an object mapping + * string identifiers to domain object models. + */ + /** * Allows multiple services which provide models for domain objects * to be treated as one. * * @memberof platform/core * @constructor - * @param {ModelProvider[]} providers the model providers to be + * @implements {ModelService} + * @param $q Angular's $q, for promises + * @param {ModelService[]} providers the model providers to be * aggregated */ function ModelAggregator($q, providers) { - - // Pick a domain object model to use, favoring the one - // with the most recent timestamp - function pick(a, b) { - var aModified = (a || {}).modified || Number.NEGATIVE_INFINITY, - bModified = (b || {}).modified || Number.NEGATIVE_INFINITY; - return (aModified > bModified) ? a : (b || a); - } - - // Merge results from multiple providers into one - // large result object. - function mergeModels(provided, ids) { - var result = {}; - ids.forEach(function (id) { - provided.forEach(function (models) { - if (models[id]) { - result[id] = pick(result[id], models[id]); - } - }); - }); - return result; - } - - return { - /** - * Get models with the specified identifiers. - * - * This will invoke the `getModels()` method of all providers - * given at constructor-time, and aggregate the result into - * one object. - * - * Note that the returned object may contain a subset or a - * superset of the models requested. - * - * @param {string[]} ids an array of domain object identifiers - * @returns {Promise.} a promise for an object - * containing key-value pairs, - * where keys are object identifiers and values - * are object models. - * @memberof platform/core.ModelAggregator# - */ - getModels: function (ids) { - return $q.all(providers.map(function (provider) { - return provider.getModels(ids); - })).then(function (provided) { - return mergeModels(provided, ids); - }); - } - }; + this.providers = providers; + this.$q = $q; } + // Pick a domain object model to use, favoring the one + // with the most recent timestamp + function pick(a, b) { + var aModified = (a || {}).modified || Number.NEGATIVE_INFINITY, + bModified = (b || {}).modified || Number.NEGATIVE_INFINITY; + return (aModified > bModified) ? a : (b || a); + } + + // Merge results from multiple providers into one + // large result object. + function mergeModels(provided, ids) { + var result = {}; + ids.forEach(function (id) { + provided.forEach(function (models) { + if (models[id]) { + result[id] = pick(result[id], models[id]); + } + }); + }); + return result; + } + + ModelAggregator.prototype.getModels = function (ids) { + return this.$q.all(this.providers.map(function (provider) { + return provider.getModels(ids); + })).then(function (provided) { + return mergeModels(provided, ids); + }); + }; + return ModelAggregator; } ); diff --git a/platform/core/src/models/PersistedModelProvider.js b/platform/core/src/models/PersistedModelProvider.js index 311f40eeaa..59ab020b14 100644 --- a/platform/core/src/models/PersistedModelProvider.js +++ b/platform/core/src/models/PersistedModelProvider.js @@ -35,61 +35,47 @@ define( * * @memberof platform/core * @constructor + * @implements {ModelService} * @param {PersistenceService} persistenceService the service in which * domain object models are persisted. * @param $q Angular's $q service, for working with promises * @param {string} SPACE the name of the persistence space from which * models should be retrieved. */ - function PersistedModelProvider(persistenceService, $q, SPACE) { - // Load a single object model from persistence - function loadModel(id) { - return persistenceService.readObject(SPACE, id); - } - - // Promise all persisted models (in id->model form) - function promiseModels(ids) { - // Package the result as id->model - function packageResult(models) { - var result = {}; - ids.forEach(function (id, index) { - result[id] = models[index]; - }); - return result; - } - - // Filter out "namespaced" identifiers; these are - // not expected to be found in database. See WTD-659. - ids = ids.filter(function (id) { - return id.indexOf(":") === -1; - }); - - // Give a promise for all persistence lookups... - return $q.all(ids.map(loadModel)).then(packageResult); - } - - return { - /** - * Get models with the specified identifiers. - * - * This will invoke the underlying persistence service to - * retrieve object models which match the provided - * identifiers. - * - * Note that the returned object may contain a subset or a - * superset of the models requested. - * - * @param {string[]} ids an array of domain object identifiers - * @returns {Promise.} a promise for an object - * containing key-value pairs, - * where keys are object identifiers and values - * are object models. - * @memberof platform/core.PersistedModelProvider# - */ - getModels: promiseModels - }; + function PersistedModelProvider(persistenceService, $q, space) { + this.persistenceService = persistenceService; + this.$q = $q; + this.space = space; } + PersistedModelProvider.prototype.getModels = function (ids) { + var persistenceService = this.persistenceService, + $q = this.$q, + space = this.space; + + // Load a single object model from persistence + function loadModel(id) { + return persistenceService.readObject(space, id); + } + + // Package the result as id->model + function packageResult(models) { + var result = {}; + ids.forEach(function (id, index) { + result[id] = models[index]; + }); + return result; + } + + // Filter out "namespaced" identifiers; these are + // not expected to be found in database. See WTD-659. + ids = ids.filter(function (id) { + return id.indexOf(":") === -1; + }); + + // Give a promise for all persistence lookups... + return $q.all(ids.map(loadModel)).then(packageResult); + }; return PersistedModelProvider; } diff --git a/platform/core/src/models/RootModelProvider.js b/platform/core/src/models/RootModelProvider.js index bf819d51ae..f218504b64 100644 --- a/platform/core/src/models/RootModelProvider.js +++ b/platform/core/src/models/RootModelProvider.js @@ -41,42 +41,31 @@ define( * * @memberof platform/core * @constructor + * @implements {ModelService} + * @param {Array} roots all `roots[]` extensions + * @param $q Angular's $q, for promises + * @param $log Anuglar's $log, for logging */ function RootModelProvider(roots, $q, $log) { // Pull out identifiers to used as ROOT's - var ids = roots.map(function (root) { return root.id; }), - baseProvider = new StaticModelProvider(roots, $q, $log); + var ids = roots.map(function (root) { return root.id; }); - function addRoot(models) { - models.ROOT = { - name: "The root object", - type: "root", - composition: ids - }; - return models; - } - - return { - - /** - * Get models with the specified identifiers. - * - * Note that the returned object may contain a subset or a - * superset of the models requested. - * - * @param {string[]} ids an array of domain object identifiers - * @returns {Promise.} a promise for an object - * containing key-value pairs, - * where keys are object identifiers and values - * are object models. - * @memberof platform/core.RootModelProvider# - */ - getModels: function (ids) { - return baseProvider.getModels(ids).then(addRoot); - } + this.baseProvider = new StaticModelProvider(roots, $q, $log); + this.rootModel = { + name: "The root object", + type: "root", + composition: ids }; } + RootModelProvider.prototype.getModels = function (ids) { + var rootModel = this.rootModel; + return this.baseProvider.getModels(ids).then(function (models) { + models.ROOT = rootModel; + return models; + }); + }; + return RootModelProvider; } ); diff --git a/platform/core/src/models/StaticModelProvider.js b/platform/core/src/models/StaticModelProvider.js index 68b76d6b43..ea5846b07a 100644 --- a/platform/core/src/models/StaticModelProvider.js +++ b/platform/core/src/models/StaticModelProvider.js @@ -41,7 +41,7 @@ define( // Skip models which don't look right if (typeof model !== 'object' || typeof model.id !== 'string' || - typeof model.model !== 'object') { + typeof model.model !== 'object') { $log.warn([ "Skipping malformed domain object model exposed by ", ((model || {}).bundle || {}).path @@ -54,34 +54,19 @@ define( // Prepoulate maps with models to make subsequent lookup faster. models.forEach(addModelToMap); - return { - /** - * Get models for these specified string identifiers. - * These will be given as an object containing keys - * and values, where keys are object identifiers and - * values are models. - * This result may contain either a subset or a - * superset of the total objects. - * - * @param {Array} ids the string identifiers for - * models of interest. - * @returns {Promise} a promise for an object - * containing key-value pairs, where keys are - * ids and values are models - * @method - * @memberof StaticModelProvider# - * @memberof platform/core.StaticModelProvider# - */ - getModels: function (ids) { - var result = {}; - ids.forEach(function (id) { - result[id] = modelMap[id]; - }); - return $q.when(result); - } - }; + this.modelMap = modelMap; + this.$q = $q; } + StaticModelProvider.prototype.getModels = function (ids) { + var modelMap = this.modelMap, + result = {}; + ids.forEach(function (id) { + result[id] = modelMap[id]; + }); + return this.$q.when(result); + }; + return StaticModelProvider; } ); diff --git a/platform/core/src/objects/DomainObject.js b/platform/core/src/objects/DomainObject.js deleted file mode 100644 index c36e5db516..0000000000 --- a/platform/core/src/objects/DomainObject.js +++ /dev/null @@ -1,134 +0,0 @@ -/***************************************************************************** - * 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*/ - -/** - * Module defining DomainObject. Created by vwoeltje on 11/7/14. - */ -define( - [], - function () { - "use strict"; - - /** - * Construct a new domain object with the specified - * identifier, model, and capabilities. - * - * @param {string} id the object's unique identifier - * @param {object} model the "JSONifiable" state of the object - * @param {Object.|function} capabilities all - * capabilities to be exposed by this object - * @memberof platform/core - * @constructor - */ - function DomainObject(id, model, capabilities) { - return { - /** - * Get the unique identifier for this domain object. - * @return {string} the domain object's unique identifier - * @memberof DomainObject# - * @memberof platform/core.DomainObject# - */ - getId: function () { - return id; - }, - - /** - * Get the domain object's model. This is useful to - * directly look up known properties of an object, but - * direct modification of a returned model is generally - * discouraged and may result in errors. Instead, an - * object's "mutation" capability should be used. - * - * @return {object} the domain object's persistent state - * @memberof DomainObject# - * @memberof platform/core.DomainObject# - */ - getModel: function () { - return model; - }, - - /** - * Get a capability associated with this object. - * Capabilities are looked up by string identifiers; - * prior knowledge of a capability's interface is - * necessary. - * - * @return {Capability} the named capability, or undefined - * if not present. - * @memberof DomainObject# - * @memberof platform/core.DomainObject# - */ - getCapability: function (name) { - var capability = capabilities[name]; - return typeof capability === 'function' ? - capability(this) : capability; - }, - - /**g - * Check if this domain object supports a capability - * with the provided name. - * - * @param {string} name the name of the capability to - * check for - * @returns {boolean} true if provided - * @memberof platform/core.DomainObject# - */ - hasCapability: function hasCapability(name) { - return this.getCapability(name) !== undefined; - }, - - /** - * Use a capability of an object; this is a shorthand - * for: - * - * ``` - * hasCapability(name) ? - * getCapability(name).invoke(args...) : - * undefined - * ``` - * - * That is, it handles both the check-for-existence and - * invocation of the capability, and checks for existence - * before invoking the capability. - * - * @param {string} name the name of the capability to invoke - * @param {...*} [arguments] to pass to the invocation - * @returns {*} - * @memberof DomainObject# - * @memberof platform/core.DomainObject# - */ - useCapability: function (name) { - // Get tail of args to pass to invoke - var args = Array.prototype.slice.apply(arguments, [1]), - capability = this.getCapability(name); - - return (capability && capability.invoke) ? - capability.invoke.apply(capability, args) : - capability; - } - }; - } - - return DomainObject; - } -); diff --git a/platform/core/src/objects/DomainObjectImpl.js b/platform/core/src/objects/DomainObjectImpl.js new file mode 100644 index 0000000000..5c2c270a23 --- /dev/null +++ b/platform/core/src/objects/DomainObjectImpl.js @@ -0,0 +1,143 @@ +/***************************************************************************** + * 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*/ + +/** + * Module defining DomainObject. Created by vwoeltje on 11/7/14. + */ +define( + [], + function () { + "use strict"; + + /** + * A domain object is an entity of interest to the user. + * + * @interface DomainObject + */ + + /** + * Get the unique identifier for this domain object. + * + * @method DomainObject#getId + * @return {string} the domain object's unique identifier + */ + + /** + * Get the domain object's model. This is useful to + * directly look up known properties of an object, but + * direct modification of a returned model is generally + * discouraged and may result in errors. Instead, an + * object's `mutation` capability should be used. + * + * @method DomainObject#getModel + * @return {object} the domain object's persistent state + */ + + /** + * Get a capability associated with this object. + * Capabilities are looked up by string identifiers; + * prior knowledge of a capability's interface is + * necessary. + * + * @method DomainObject#getCapability + * @param {string} key the identifier for the capability + * @return {Capability} the named capability, or undefined + * if not present. + */ + + /** + * Check if this domain object supports a capability + * with the provided name. + * + * @method DomainObject#hasCapability + * @param {string} key the identifier for the capability + * @return {boolean} true if this domain object has this capability + */ + + /** + * Use a capability of an object; the behavior of this method + * depends on the interface of the capability, and whether + * or not it is present. + * + * * If the capability is not present for this object, + * no operation occurs. + * * If the capability is present and has an `invoke` method, + * that method is called with any additional arguments + * provided, and its return value is returned. + * * If the capability is present but has no `invoke` method, + * this capability itself is returned. + * + * @method DomainObject#useCapability + * @param {string} name the name of the capability to invoke + * @param {...*} [arguments] to pass to the invocation + * @returns {*|Capability} the result of invocation (see description) + */ + + /** + * Construct a new domain object with the specified + * identifier, model, and capabilities. + * + * @param {string} id the object's unique identifier + * @param {object} model the "JSONifiable" state of the object + * @param {Object.|function} capabilities all + * capabilities to be exposed by this object + * @memberof platform/core + * @constructor + */ + function DomainObjectImpl(id, model, capabilities) { + this.id = id; + this.model = model; + this.capabilities = capabilities; + } + + DomainObjectImpl.prototype.getId = function () { + return this.id; + }; + + DomainObjectImpl.prototype.getModel = function () { + return this.model; + }; + + DomainObjectImpl.prototype.getCapability = function (name) { + var capability = this.capabilities[name]; + return typeof capability === 'function' ? + capability(this) : capability; + }; + + DomainObjectImpl.prototype.hasCapability = function (name) { + return this.getCapability(name) !== undefined; + }; + + DomainObjectImpl.prototype.useCapability = function (name) { + // Get tail of args to pass to invoke + var args = Array.prototype.slice.apply(arguments, [1]), + capability = this.getCapability(name); + + return (capability && capability.invoke) ? + capability.invoke.apply(capability, args) : + capability; + }; + + return DomainObjectImpl; + } +); diff --git a/platform/core/src/objects/DomainObjectProvider.js b/platform/core/src/objects/DomainObjectProvider.js index 732da80518..c846cbf665 100644 --- a/platform/core/src/objects/DomainObjectProvider.js +++ b/platform/core/src/objects/DomainObjectProvider.js @@ -27,10 +27,31 @@ * @namespace platform/core */ define( - ["./DomainObject"], - function (DomainObject) { + ["./DomainObjectImpl"], + function (DomainObjectImpl) { "use strict"; + /** + * Provides instances of domain objects, as retrieved by their + * identifiers. + * + * @interface ObjectService + */ + + /** + * Get a set of objects associated with a list of identifiers. + * The provided result may contain a subset or a superset of + * the total number of objects. + * + * @method ObjectService#getObjects + * @param {string[]} ids the identifiers for domain objects + * of interest. + * @return {Promise>} a promise + * for an object containing key-value pairs, where keys + * are string identifiers for domain objects, and + * values are the corresponding domain objects themselves. + */ + /** * Construct a new provider for domain objects. * @@ -44,6 +65,16 @@ define( * @constructor */ function DomainObjectProvider(modelService, capabilityService, $q) { + this.modelService = modelService; + this.capabilityService = capabilityService; + this.$q = $q; + } + + DomainObjectProvider.prototype.getObjects = function getObjects(ids) { + var modelService = this.modelService, + capabilityService = this.capabilityService, + $q = this.$q; + // Given a models object (containing key-value id-model pairs) // create a function that will look up from the capability // service based on id; for handy mapping below. @@ -51,8 +82,8 @@ define( return function (id) { var model = models[id]; return model ? - capabilityService.getCapabilities(model) : - undefined; + capabilityService.getCapabilities(model) : + undefined; }; } @@ -65,7 +96,7 @@ define( ids.forEach(function (id, index) { if (models[id]) { // Create the domain object - result[id] = new DomainObject( + result[id] = new DomainObjectImpl( id, models[id], capabilities[index] @@ -75,36 +106,14 @@ define( return result; } - // Get object instances; this is the useful API exposed by the - // domain object provider. - function getObjects(ids) { - return modelService.getModels(ids).then(function (models) { - return $q.all( - ids.map(capabilityResolver(models)) - ).then(function (capabilities) { + return modelService.getModels(ids).then(function (models) { + return $q.all( + ids.map(capabilityResolver(models)) + ).then(function (capabilities) { return assembleResult(ids, models, capabilities); }); - }); - } - - return { - /** - * Get a set of objects associated with a list of identifiers. - * The provided result may contain a subset or a superset of - * the total number of objects. - * - * @param {Array} ids the identifiers for domain objects - * of interest. - * @return {Promise>} a promise - * for an object containing key-value pairs, where keys - * are string identifiers for domain objects, and - * values are the corresponding domain objects themselves. - * @memberof module:core/object/object-provider.ObjectProvider# - * @memberof platform/core.DomainObjectProvider# - */ - getObjects: getObjects - }; - } + }); + }; return DomainObjectProvider; } diff --git a/platform/core/src/services/Now.js b/platform/core/src/services/Now.js index b799d80391..e1a639fe11 100644 --- a/platform/core/src/services/Now.js +++ b/platform/core/src/services/Now.js @@ -31,7 +31,6 @@ define( * `Date.now()` which can be injected to support testability. * * @returns {Function} a function which returns current system time - * @constructor * @memberof platform/core */ function Now() { diff --git a/platform/core/src/services/Throttle.js b/platform/core/src/services/Throttle.js index 16b258ba13..3d68988d6b 100644 --- a/platform/core/src/services/Throttle.js +++ b/platform/core/src/services/Throttle.js @@ -42,7 +42,6 @@ define( * resolve to the returned value of `fn` whenever that is invoked. * * @returns {Function} - * @constructor * @memberof platform/core */ function Throttle($timeout) { diff --git a/platform/core/src/services/Topic.js b/platform/core/src/services/Topic.js index cc57b4314c..ca38dfcde7 100644 --- a/platform/core/src/services/Topic.js +++ b/platform/core/src/services/Topic.js @@ -44,7 +44,6 @@ define( * arguments) are private; each call returns a new instance. * * @returns {Function} - * @constructor * @memberof platform/core */ function Topic() { diff --git a/platform/core/src/types/TypeCapability.js b/platform/core/src/types/TypeCapability.js index ca311aab2a..883c8dc7ab 100644 --- a/platform/core/src/types/TypeCapability.js +++ b/platform/core/src/types/TypeCapability.js @@ -36,6 +36,8 @@ define( * * @memberof platform/core * @constructor + * @augments {Type} + * @implements {Capability} * @param {TypeService} typeService the service which * provides type information * @param {DomainObject} domainObject the domain object diff --git a/platform/core/src/types/TypeImpl.js b/platform/core/src/types/TypeImpl.js index 526675e611..dbecaa2e6a 100644 --- a/platform/core/src/types/TypeImpl.js +++ b/platform/core/src/types/TypeImpl.js @@ -26,10 +26,95 @@ define( function (TypeProperty) { "use strict"; + /** + * Describes a type of domain object. + * + * @interface Type + */ + + /** + * Get the string key which identifies this type. + * This is the type's machine-readable name/identifier, + * and will correspond to the "type" field of the models + * of domain objects of this type. + * + * @returns {string} the key which identifies this type + * @method Type#getKey + */ + /** + * Get the human-readable name for this type, as should + * be displayed in the user interface when referencing + * this type. + * + * @returns {string} the human-readable name of this type + * @method Type#getName + */ + /** + * Get the human-readable description for this type, as should + * be displayed in the user interface when describing + * this type. + * + * @returns {string} the human-readable description of this type + * @method Type#getDescription + */ + /** + * Get the glyph associated with this type. Glyphs are + * single-character strings which will appear as icons (when + * displayed in an appropriate font) which visually + * distinguish types from one another. + * + * @returns {string} the glyph to be displayed + * @method Type#getGlyph + */ + /** + * Get an array of properties associated with objects of + * this type, as might be shown in a Create wizard or + * an Edit Properties view. + * + * @return {Array} properties associated with - * objects of this type - * @memberof platform/core.TypeImpl# - */ - getProperties: function () { - return (typeDef.properties || []).map(TypeProperty); - }, - /** - * Get the initial state of a model for domain objects of - * this type. - * - * @return {object} initial domain object model - * @memberof platform/core.TypeImpl# - */ - getInitialModel: function () { - return typeDef.model || {}; - }, - /** - * Get the raw type definition for this type. This is an - * object containing key-value pairs of type metadata; - * this allows the retrieval and use of custom type - * properties which are not recognized within this interface. - * - * @returns {object} the raw definition for this type - * @memberof module:core/type/type-impl.TypeImpl# - * @memberof platform/core.TypeImpl# - */ - getDefinition: function () { - return typeDef; - }, - /** - * Check if this type is or inherits from some other type. - * - * TODO: Rename, "instanceOf" is a misnomer (since there is - * no "instance", so to speak.) - * - * @param {string|module:core/type/type-implTypeImpl} key either - * a string key for a type, or an instance of a type - * object, which this - * @returns {boolean} true - * @memberof module:core/type/type-impl.TypeImpl# - * @memberof platform/core.TypeImpl# - */ - instanceOf: function instanceOf(key) { - - if (key === typeDef.key) { - return true; - } else if (inheritList.indexOf(key) > -1) { - return true; - } else if (!key) { - return true; - } else if (key !== null && typeof key === 'object') { - return key.getKey ? instanceOf(key.getKey()) : false; - } else { - return false; - } - }, - /** - * Check if a type should support a given feature. This simply - * checks for the presence or absence of the feature key in - * the type definition's "feature" field. - * @param {string} feature a string identifying the feature - * @returns {boolean} true if the feature is supported - * @memberof platform/core.TypeImpl# - */ - hasFeature: function (feature) { - return featureSet[feature] || false; - } - }; + this.typeDef = typeDef; + this.featureSet = featureSet; + this.inheritList = inheritList; } + TypeImpl.prototype.getKey = function () { + return this.typeDef.key; + }; + + TypeImpl.prototype.getName = function () { + return this.typeDef.name; + }; + + TypeImpl.prototype.getDescription = function () { + return this.typeDef.description; + }; + + TypeImpl.prototype.getGlyph = function () { + return this.typeDef.glyph; + }; + + TypeImpl.prototype.getProperties = function () { + return (this.typeDef.properties || []).map(function (propertyDef) { + return new TypeProperty(propertyDef); + }); + }; + + TypeImpl.prototype.getInitialModel = function () { + return this.typeDef.model || {}; + }; + + TypeImpl.prototype.getDefinition = function () { + return this.typeDef; + }; + + TypeImpl.prototype.instanceOf = function instanceOf(key) { + var typeDef = this.typeDef, + inheritList = this.inheritList; + + if (key === typeDef.key) { + return true; + } else if (inheritList.indexOf(key) > -1) { + return true; + } else if (!key) { + return true; + } else if (key !== null && typeof key === 'object') { + return key.getKey ? this.instanceOf(key.getKey()) : false; + } else { + return false; + } + } + + TypeImpl.prototype.hasFeature = function (feature) { + return this.featureSet[feature] || false; + }; + return TypeImpl; } ); diff --git a/platform/core/src/types/TypeProperty.js b/platform/core/src/types/TypeProperty.js index 2b1cfea0ac..70aaf8fbf8 100644 --- a/platform/core/src/types/TypeProperty.js +++ b/platform/core/src/types/TypeProperty.js @@ -35,128 +35,130 @@ define( */ function TypeProperty(propertyDefinition) { // Load an appropriate conversion - var conversion = new TypePropertyConversion( + this.conversion = new TypePropertyConversion( propertyDefinition.conversion || "identity" ); + this.propertyDefinition = propertyDefinition; + } - // Check if a value is defined; used to check if initial array - // values have been populated. - function isUnpopulatedArray(value) { - var i; + // Check if a value is defined; used to check if initial array + // values have been populated. + function isUnpopulatedArray(value) { + var i; - if (!Array.isArray(value) || value.length === 0) { - return false; - } - - for (i = 0; i < value.length; i += 1) { - if (value[i] !== undefined) { - return false; - } - } - - return true; + if (!Array.isArray(value) || value.length === 0) { + return false; } - // Perform a lookup for a value from an object, - // which may recursively look at contained objects - // based on the path provided. - function lookupValue(object, propertyPath) { - var value; - - // Can't look up from a non-object - if (!object) { - return undefined; + for (i = 0; i < value.length; i += 1) { + if (value[i] !== undefined) { + return false; } + } - // If path is not an array, just look up the property - if (!Array.isArray(propertyPath)) { - return object[propertyPath]; - } + return true; + } - // Otherwise, look up in the sequence defined in the array - if (propertyPath.length > 0) { - value = object[propertyPath[0]]; - return propertyPath.length > 1 ? - lookupValue(value, propertyPath.slice(1)) : - value; - } + // Specify a field deeply within an object + function specifyValue(object, propertyPath, value) { + // If path is not an array, just set the property + if (!Array.isArray(propertyPath)) { + object[propertyPath] = value; + } else if (propertyPath.length > 1) { + // Otherwise, look up in defined sequence + object[propertyPath[0]] = object[propertyPath[0]] || {}; + specifyValue( + object[propertyPath[0]], + propertyPath.slice(1), + value + ); + } else if (propertyPath.length === 1) { + object[propertyPath[0]] = value; + } + } - // Fallback; property path was empty + // Perform a lookup for a value from an object, + // which may recursively look at contained objects + // based on the path provided. + function lookupValue(object, propertyPath) { + var value; + + // Can't look up from a non-object + if (!object) { return undefined; } - function specifyValue(object, propertyPath, value) { - - // If path is not an array, just set the property - if (!Array.isArray(propertyPath)) { - object[propertyPath] = value; - } else if (propertyPath.length > 1) { - // Otherwise, look up in defined sequence - object[propertyPath[0]] = object[propertyPath[0]] || {}; - specifyValue( - object[propertyPath[0]], - propertyPath.slice(1), - value - ); - } else if (propertyPath.length === 1) { - object[propertyPath[0]] = value; - } - + // If path is not an array, just look up the property + if (!Array.isArray(propertyPath)) { + return object[propertyPath]; } - return { - /** - * Retrieve the value associated with this property - * from a given model. - * @memberof platform/core.TypeProperty# - */ - getValue: function (model) { - var property = propertyDefinition.property || - propertyDefinition.key, - initialValue = - property && lookupValue(model, property); + // Otherwise, look up in the sequence defined in the array + if (propertyPath.length > 0) { + value = object[propertyPath[0]]; + return propertyPath.length > 1 ? + lookupValue(value, propertyPath.slice(1)) : + value; + } - // Provide an empty array if this is a multi-item - // property. - if (Array.isArray(propertyDefinition.items)) { - initialValue = initialValue || - new Array(propertyDefinition.items.length); - } - - return conversion.toFormValue(initialValue); - }, - /** - * Set a value associated with this property in - * an object's model. - * @memberof platform/core.TypeProperty# - */ - setValue: function setValue(model, value) { - var property = propertyDefinition.property || - propertyDefinition.key; - - // If an array contains all undefined values, treat it - // as undefined, to filter back out arrays for input - // that never got entered. - value = isUnpopulatedArray(value) ? undefined : value; - - // Convert to a value suitable for storage in the - // domain object's model - value = conversion.toModelValue(value); - - return property ? - specifyValue(model, property, value) : - undefined; - }, - /** - * Get the raw definition for this property. - * @memberof platform/core.TypeProperty# - */ - getDefinition: function () { - return propertyDefinition; - } - }; + // Fallback; property path was empty + return undefined; } + /** + * Retrieve the value associated with this property + * from a given model. + * @param {object} model a domain object model to read from + * @returns {*} the value for this property, as read from the model + */ + TypeProperty.prototype.getValue = function (model) { + var property = this.propertyDefinition.property || + this.propertyDefinition.key, + initialValue = + property && lookupValue(model, property); + + // Provide an empty array if this is a multi-item + // property. + if (Array.isArray(this.propertyDefinition.items)) { + initialValue = initialValue || + new Array(this.propertyDefinition.items.length); + } + + return this.conversion.toFormValue(initialValue); + }; + + /** + * Set a value associated with this property in + * an object's model. + * @param {object} model a domain object model to update + * @param {*} value the new value to set for this property + */ + TypeProperty.prototype.setValue = function (model, value) { + var property = this.propertyDefinition.property || + this.propertyDefinition.key; + + // If an array contains all undefined values, treat it + // as undefined, to filter back out arrays for input + // that never got entered. + value = isUnpopulatedArray(value) ? undefined : value; + + // Convert to a value suitable for storage in the + // domain object's model + value = this.conversion.toModelValue(value); + + return property ? + specifyValue(model, property, value) : + undefined; + }; + + /** + * Get the raw definition for this property. + * @returns {TypePropertyDefinition} + */ + TypeProperty.prototype.getDefinition = function () { + return this.propertyDefinition; + }; + return TypeProperty; } ); diff --git a/platform/core/src/types/TypePropertyConversion.js b/platform/core/src/types/TypePropertyConversion.js index 56ce1cc5e5..6f8344e3d7 100644 --- a/platform/core/src/types/TypePropertyConversion.js +++ b/platform/core/src/types/TypePropertyConversion.js @@ -76,6 +76,23 @@ define( } } + /** + * Convert a value from its format as read from a form, to a + * format appropriate to store in a model. + * @method platform/core.TypePropertyConversion#toModelValue + * @param {*} formValue value as read from a form + * @returns {*} value to store in a model + */ + + /** + * Convert a value from its format as stored in a model, to a + * format appropriate to display in a form. + * @method platform/core.TypePropertyConversion#toFormValue + * @param {*} modelValue value as stored in a model + * @returns {*} value to display within a form + */ + + return TypePropertyConversion; } ); diff --git a/platform/core/src/types/TypeProvider.js b/platform/core/src/types/TypeProvider.js index a55c834da8..ca3f6e641e 100644 --- a/platform/core/src/types/TypeProvider.js +++ b/platform/core/src/types/TypeProvider.js @@ -26,6 +26,27 @@ define( function (TypeImpl, mergeModels) { 'use strict'; + /** + * Provides domain object types that are available/recognized within + * the system. + * + * @interface TypeService + */ + /** + * Get a specific type by name. + * + * @method TypeService#getType + * @param {string} key the key (machine-readable identifier) + * for the type of interest + * @returns {Type} the type identified by this key + */ + /** + * List all known types. + * + * @method TypeService#listTypes + * @returns {Type[]} all known types + */ + var TO_CONCAT = ['inherits', 'capabilities', 'properties', 'features'], TO_MERGE = ['model']; @@ -49,11 +70,44 @@ define( }) : array; } + // Reduce an array of type definitions to a single type definiton, + // which has merged all properties in order. + function collapse(typeDefs) { + var collapsed = typeDefs.reduce(function (a, b) { + var result = {}; + copyKeys(result, a); + copyKeys(result, b); + + // Special case: Do a merge, e.g. on "model" + TO_MERGE.forEach(function (k) { + if (a[k] && b[k]) { + result[k] = mergeModels(a[k], b[k]); + } + }); + + // Special case: Concatenate certain arrays + TO_CONCAT.forEach(function (k) { + if (a[k] || b[k]) { + result[k] = (a[k] || []).concat(b[k] || []); + } + }); + return result; + }, {}); + + // Remove any duplicates from the collapsed array + TO_CONCAT.forEach(function (k) { + if (collapsed[k]) { + collapsed[k] = removeDuplicates(collapsed[k]); + } + }); + return collapsed; + } + /** * A type provider provides information about types of domain objects * within the running Open MCT Web instance. * - * @param {Array} options.definitions the raw type + * @param {Array} types the raw type * definitions for this type. * @memberof platform/core * @constructor @@ -69,46 +123,34 @@ define( } }); return result; - }(rawTypeDefinitions)), - typeMap = {}, - undefinedType; + }(rawTypeDefinitions)); - // Reduce an array of type definitions to a single type definiton, - // which has merged all properties in order. - function collapse(typeDefs) { - var collapsed = typeDefs.reduce(function (a, b) { - var result = {}; - copyKeys(result, a); - copyKeys(result, b); - // Special case: Do a merge, e.g. on "model" - TO_MERGE.forEach(function (k) { - if (a[k] && b[k]) { - result[k] = mergeModels(a[k], b[k]); - } - }); + this.typeMap = {}; + this.typeDefinitions = typeDefinitions; + this.rawTypeDefinitions = types; + } - // Special case: Concatenate certain arrays - TO_CONCAT.forEach(function (k) { - if (a[k] || b[k]) { - result[k] = (a[k] || []).concat(b[k] || []); - } - }); - return result; - }, {}); + TypeProvider.prototype.listTypes = function () { + var self = this; + return removeDuplicates( + this.rawTypeDefinitions.filter(function (def) { + return def.key; + }).map(function (def) { + return def.key; + }).map(function (key) { + return self.getType(key); + }) + ); + }; - // Remove any duplicates from the collapsed array - TO_CONCAT.forEach(function (k) { - if (collapsed[k]) { - collapsed[k] = removeDuplicates(collapsed[k]); - } - }); - return collapsed; - } + TypeProvider.prototype.getType = function (key) { + var typeDefinitions = this.typeDefinitions, + self = this; function getUndefinedType() { - return (undefinedType = undefinedType || collapse( - rawTypeDefinitions.filter(function (typeDef) { + return (self.undefinedType = self.undefinedType || collapse( + self.rawTypeDefinitions.filter(function (typeDef) { return !typeDef.key; }) )); @@ -118,79 +160,36 @@ define( return Array.isArray(value) ? value : [value]; } - function lookupTypeDef(typeKey) { - function buildTypeDef(typeKey) { - var typeDefs = typeDefinitions[typeKey] || [], - inherits = typeDefs.map(function (typeDef) { - return asArray(typeDef.inherits || []); - }).reduce(function (a, b) { - return a.concat(b); - }, []), - def = collapse( - [getUndefinedType()].concat( - inherits.map(lookupTypeDef) - ).concat(typeDefs) - ); - - // Always provide a default name - def.model = def.model || {}; - def.model.name = def.model.name || ( - "Unnamed " + (def.name || "Object") + function buildTypeDef(typeKey) { + var typeDefs = typeDefinitions[typeKey] || [], + inherits = typeDefs.map(function (typeDef) { + return asArray(typeDef.inherits || []); + }).reduce(function (a, b) { + return a.concat(b); + }, []), + def = collapse( + [getUndefinedType()].concat( + inherits.map(lookupTypeDef) + ).concat(typeDefs) ); - return def; + // Always provide a default name + def.model = def.model || {}; + def.model.name = def.model.name || + ("Unnamed " + (def.name || "Object")); - } - - return (typeMap[typeKey] = typeMap[typeKey] || buildTypeDef(typeKey)); + return def; } + function lookupTypeDef(typeKey) { + return (self.typeMap[typeKey] = + self.typeMap[typeKey] || buildTypeDef(typeKey)); + } - return { - /** - * Get a list of all types defined by this service. - * - * @returns {Promise>} a - * promise for an array of all type instances defined - * by this service. - * @memberof module:core/type/type-provider.TypeProvider# - * @memberof platform/core.TypeProvider# - */ - listTypes: function () { - var self = this; - return removeDuplicates( - rawTypeDefinitions.filter(function (def) { - return def.key; - }).map(function (def) { - return def.key; - }).map(function (key) { - return self.getType(key); - }) - ); - }, - - /** - * Get a specific type by name. - * - * @param {string} [key] the key (machine-readable identifier) - * for the type of interest - * @returns {Promise} a - * promise for a type object identified by this key. - * @memberof module:core/type/type-provider.TypeProvider# - * @memberof platform/core.TypeProvider# - */ - getType: function (key) { - return new TypeImpl(lookupTypeDef(key)); - } - }; - } - - // Services framework is designed to expect factories - TypeProvider.instantiate = TypeProvider; + return new TypeImpl(lookupTypeDef(key)); + }; return TypeProvider; - - } ); diff --git a/platform/core/src/views/ViewCapability.js b/platform/core/src/views/ViewCapability.js index 8cdf7eaecb..38862cf2fc 100644 --- a/platform/core/src/views/ViewCapability.js +++ b/platform/core/src/views/ViewCapability.js @@ -36,23 +36,25 @@ define( * object. * * @memberof platform/core + * @implements {Capability} * @constructor */ function ViewCapability(viewService, domainObject) { - return { - /** - * Get all view definitions which are applicable to - * this object. - * @returns {View[]} an array of view definitions - * which are applicable to this object. - * @memberof platform/core.ViewCapability# - */ - invoke: function () { - return viewService.getViews(domainObject); - } - }; + this.viewService = viewService; + this.domainObject = domainObject; } + /** + * Get all view definitions which are applicable to + * this object. + * @returns {View[]} an array of view definitions + * which are applicable to this object. + * @memberof platform/core.ViewCapability# + */ + ViewCapability.prototype.invoke = function () { + return this.viewService.getViews(this.domainObject); + }; + return ViewCapability; } ); diff --git a/platform/core/src/views/ViewProvider.js b/platform/core/src/views/ViewProvider.js index e3e9e550d2..e2034c3d6b 100644 --- a/platform/core/src/views/ViewProvider.js +++ b/platform/core/src/views/ViewProvider.js @@ -29,6 +29,22 @@ define( function () { "use strict"; + /** + * Provides definitions for views that are available for specific + * domain objects. + * + * @interface ViewService + */ + + /** + * Get all views which are applicable to this domain object. + * + * @method ViewService#getViews + * @param {DomainObject} domainObject the domain object to view + * @returns {View[]} all views which can be used to visualize + * this domain object. + */ + /** * A view provider allows view definitions (defined as extensions) * to be read, and takes responsibility for filtering these down @@ -58,6 +74,8 @@ define( * @memberof platform/core * @constructor * @param {View[]} an array of view definitions + * @param $log Angular's logging service + * @implements {ViewService} */ function ViewProvider(views, $log) { @@ -79,6 +97,13 @@ define( return key; } + // Filter out any key-less views + this.views = views.filter(validate); + } + + ViewProvider.prototype.getViews = function (domainObject) { + var type = domainObject.useCapability("type"); + // Check if an object has all capabilities designated as `needs` // for a view. Exposing a capability via delegation is taken to // satisfy this filter if `allowDelegation` is true. @@ -122,35 +147,16 @@ define( return matches; } - function getViews(domainObject) { - var type = domainObject.useCapability("type"); - - // First, filter views by type (matched to domain object type.) - // Second, filter by matching capabilities. - return views.filter(function (view) { - return viewMatchesType(view, type) && capabilitiesMatch( + // First, filter views by type (matched to domain object type.) + // Second, filter by matching capabilities. + return this.views.filter(function (view) { + return viewMatchesType(view, type) && capabilitiesMatch( domainObject, view.needs || [], view.delegation || false ); - }); - } - - // Filter out any key-less views - views = views.filter(validate); - - return { - /** - * Get all views which are applicable to this domain object. - * - * @param {DomainObject} domainObject the domain object to view - * @returns {View[]} all views which can be used to visualize - * this domain object. - * @memberof platform/core.ViewProvider# - */ - getViews: getViews - }; - } + }); + }; return ViewProvider; } diff --git a/platform/core/test/objects/DomainObjectSpec.js b/platform/core/test/objects/DomainObjectSpec.js index 29862461b3..13e8968e0d 100644 --- a/platform/core/test/objects/DomainObjectSpec.js +++ b/platform/core/test/objects/DomainObjectSpec.js @@ -25,7 +25,7 @@ * DomainObjectSpec. Created by vwoeltje on 11/6/14. */ define( - ["../../src/objects/DomainObject"], + ["../../src/objects/DomainObjectImpl"], function (DomainObject) { "use strict"; diff --git a/platform/core/test/types/TypeImplSpec.js b/platform/core/test/types/TypeImplSpec.js index c11075870c..d29c4f2712 100644 --- a/platform/core/test/types/TypeImplSpec.js +++ b/platform/core/test/types/TypeImplSpec.js @@ -23,7 +23,7 @@ define( ['../../src/types/TypeImpl'], - function (typeImpl) { + function (TypeImpl) { "use strict"; describe("Type definition wrapper", function () { @@ -41,7 +41,7 @@ define( properties: [ {} ], model: {someKey: "some value"} }; - type = typeImpl(testTypeDef); + type = new TypeImpl(testTypeDef); }); it("exposes key from definition", function () { diff --git a/platform/core/test/types/TypeProviderSpec.js b/platform/core/test/types/TypeProviderSpec.js index 0da1f5910e..24f0a77c73 100644 --- a/platform/core/test/types/TypeProviderSpec.js +++ b/platform/core/test/types/TypeProviderSpec.js @@ -128,7 +128,7 @@ define( }); it("includes capabilities from undefined type in all types", function () { - captured.type = TypeProvider.instantiate( + captured.type = new TypeProvider( testTypeDefinitions.concat([ { capabilities: ['a', 'b', 'c'] }, { capabilities: ['x', 'y', 'z'] } From c19b3384caf4bfc73eaa90b5babf4124e588e6f2 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 11 Aug 2015 12:58:51 -0700 Subject: [PATCH 45/84] [Code Style] Remove JSDoc script Remove script which added extra JSDoc annotations, WTD-1482. --- jsdocify.js | 98 ----------------------------------------------------- 1 file changed, 98 deletions(-) delete mode 100644 jsdocify.js diff --git a/jsdocify.js b/jsdocify.js deleted file mode 100644 index 881e27e9c6..0000000000 --- a/jsdocify.js +++ /dev/null @@ -1,98 +0,0 @@ -(function () { - "use strict"; - - var glob = require("glob"), - split = require("split"), - fs = require("fs"), - stream = require("stream"); - - function bundleName(file) { - return file.substr(0, file.indexOf('/src')); - } - - function className(file) { - return file.substr(file.lastIndexOf('/') + 1).replace(/\.js$/, ""); - } - - function qualifiedName(file) { - return bundleName(file) + '.' + className(file); - } - - function spaces(count) { - return count < 1 ? '' : (spaces(count - 1) + " "); - } - - function jsdocRewriter(filename) { - var rewriter = new stream.Transform(), - reachedConstructor = false, - inMember = false, - starDepth = 0; - - rewriter._transform = function (chunk, encoding, done) { - var data = String(chunk); - if (!reachedConstructor) { - // First, check for constructors missing @constructor - if (data.match(/^ *\*\//) && data.indexOf("*") > 3) { - // Track position to detect inner methods - starDepth = data.indexOf("*"); - reachedConstructor = true; - // Add a @memberof annotation - this.push(spaces(starDepth) + "* @constructor\n"); - this.push([ - spaces(starDepth), - "* @memberof ", - bundleName(filename), - "\n" - ].join("")); - } else if (data.match(/^ *\* @constructor/)) { - // Track position to detect inner methods - starDepth = data.indexOf("*"); - reachedConstructor = true; - // Add a @memberof annotation - this.push([ - spaces(starDepth), - "* @memberof ", - bundleName(filename), - "\n" - ].join("")); - } - } else if (!inMember) { - // Start of JSdoc for a member - if (data.match(/^ *\/\*\*/) && data.indexOf('/') > starDepth) { - inMember = true; - } - } else { - // End of JSdoc for a member - if (data.match(/^ *\*\//)) { - this.push([ - spaces(data.indexOf('*')), - "* @memberof ", - qualifiedName(filename), - "#\n" - ].join("")); - inMember = false; - } - } - this.push(data + '\n'); - done(); - }; - - return rewriter; - } - - - glob("platform/**/src/**/*.js", function (err, files) { - files.forEach(function (file) { - var tmp = file + '.tmp'; - fs.createReadStream(file, { encoding: 'utf8' }) - .pipe(split()) - .pipe(jsdocRewriter(file)) - .pipe(fs.createWriteStream(tmp, { encoding: 'utf8' })) - .on('close', function () { - fs.renameSync(tmp, file); - }); - }); - }); - - -}()); \ No newline at end of file From c450c22dddafb42e802dff774d08fcf9e3a2bdfc Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 11 Aug 2015 13:03:06 -0700 Subject: [PATCH 46/84] [Code Style] Satisfy JSLint Add missing semicolons etc. to satisfy JSLint after changes for WTD-1482. --- .../browse/src/navigation/NavigateAction.js | 4 +- .../src/navigation/NavigationService.js | 4 +- .../browse/src/windowing/NewTabAction.js | 2 +- .../edit/src/capabilities/EditorCapability.js | 2 +- .../inspect/src/services/InfoService.js | 2 +- .../containment/src/ComposeActionPolicy.js | 2 +- platform/core/src/types/TypeImpl.js | 2 +- platform/core/src/types/TypeProvider.js | 42 +++++++++---------- 8 files changed, 30 insertions(+), 30 deletions(-) diff --git a/platform/commonUI/browse/src/navigation/NavigateAction.js b/platform/commonUI/browse/src/navigation/NavigateAction.js index 47a8fa3e16..7b258afafe 100644 --- a/platform/commonUI/browse/src/navigation/NavigateAction.js +++ b/platform/commonUI/browse/src/navigation/NavigateAction.js @@ -51,14 +51,14 @@ define( return this.$q.when( this.navigationService.setNavigation(this.domainObject) ); - } + }; /** * 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 + * @returns {boolean} 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 0779ce3026..87e5582ef7 100644 --- a/platform/commonUI/browse/src/navigation/NavigationService.js +++ b/platform/commonUI/browse/src/navigation/NavigationService.js @@ -70,7 +70,7 @@ define( */ NavigationService.prototype.addListener = function (callback) { this.callbacks.push(callback); - } + }; /** * Stop listening for changes in navigation state. @@ -82,7 +82,7 @@ define( this.callbacks = this.callbacks.filter(function (cb) { return cb !== callback; }); - } + }; return NavigationService; } diff --git a/platform/commonUI/browse/src/windowing/NewTabAction.js b/platform/commonUI/browse/src/windowing/NewTabAction.js index 8e253ad52e..301c204bbd 100644 --- a/platform/commonUI/browse/src/windowing/NewTabAction.js +++ b/platform/commonUI/browse/src/windowing/NewTabAction.js @@ -42,7 +42,7 @@ define( this.urlService = urlService; this.open = function () { - $window.open.apply($window, arguments) + $window.open.apply($window, arguments); }; // Choose the object to be opened into a new tab diff --git a/platform/commonUI/edit/src/capabilities/EditorCapability.js b/platform/commonUI/edit/src/capabilities/EditorCapability.js index 34b3044c17..7094d1142c 100644 --- a/platform/commonUI/edit/src/capabilities/EditorCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditorCapability.js @@ -118,7 +118,7 @@ define( * @memberof platform/commonUI/edit.EditorCapability# */ EditorCapability.prototype.dirty = function () { - return cache.dirty(); + return this.cache.dirty(); }; return EditorCapability; diff --git a/platform/commonUI/inspect/src/services/InfoService.js b/platform/commonUI/inspect/src/services/InfoService.js index 2f9fe62eab..ef2b35411f 100644 --- a/platform/commonUI/inspect/src/services/InfoService.js +++ b/platform/commonUI/inspect/src/services/InfoService.js @@ -93,7 +93,7 @@ define( // Return a function to dismiss the bubble return function () { bubble.remove(); }; - } + }; return InfoService; } diff --git a/platform/containment/src/ComposeActionPolicy.js b/platform/containment/src/ComposeActionPolicy.js index 53a1bf0ab8..3468cd3107 100644 --- a/platform/containment/src/ComposeActionPolicy.js +++ b/platform/containment/src/ComposeActionPolicy.js @@ -60,7 +60,7 @@ define( containerType, selectedType ); - } + }; /** * Check whether or not a compose action should be allowed diff --git a/platform/core/src/types/TypeImpl.js b/platform/core/src/types/TypeImpl.js index dbecaa2e6a..a89b010f1d 100644 --- a/platform/core/src/types/TypeImpl.js +++ b/platform/core/src/types/TypeImpl.js @@ -179,7 +179,7 @@ define( } else { return false; } - } + }; TypeImpl.prototype.hasFeature = function (feature) { return this.featureSet[feature] || false; diff --git a/platform/core/src/types/TypeProvider.js b/platform/core/src/types/TypeProvider.js index ca3f6e641e..d8b6475d58 100644 --- a/platform/core/src/types/TypeProvider.js +++ b/platform/core/src/types/TypeProvider.js @@ -160,28 +160,28 @@ define( return Array.isArray(value) ? value : [value]; } - function buildTypeDef(typeKey) { - var typeDefs = typeDefinitions[typeKey] || [], - inherits = typeDefs.map(function (typeDef) { - return asArray(typeDef.inherits || []); - }).reduce(function (a, b) { - return a.concat(b); - }, []), - def = collapse( - [getUndefinedType()].concat( - inherits.map(lookupTypeDef) - ).concat(typeDefs) - ); - - // Always provide a default name - def.model = def.model || {}; - def.model.name = def.model.name || - ("Unnamed " + (def.name || "Object")); - - return def; - } - function lookupTypeDef(typeKey) { + function buildTypeDef(typeKey) { + var typeDefs = typeDefinitions[typeKey] || [], + inherits = typeDefs.map(function (typeDef) { + return asArray(typeDef.inherits || []); + }).reduce(function (a, b) { + return a.concat(b); + }, []), + def = collapse( + [getUndefinedType()].concat( + inherits.map(lookupTypeDef) + ).concat(typeDefs) + ); + + // Always provide a default name + def.model = def.model || {}; + def.model.name = def.model.name || + ("Unnamed " + (def.name || "Object")); + + return def; + } + return (self.typeMap[typeKey] = self.typeMap[typeKey] || buildTypeDef(typeKey)); } From 5e4dcc1e35cefdbc39cf30390086b212adfcbf49 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 11 Aug 2015 14:53:45 -0700 Subject: [PATCH 47/84] [Code Style] Fix typo Fix typo in JSDoc annotation, WTD-1482 --- platform/core/src/types/TypeImpl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/core/src/types/TypeImpl.js b/platform/core/src/types/TypeImpl.js index a89b010f1d..deb23873e5 100644 --- a/platform/core/src/types/TypeImpl.js +++ b/platform/core/src/types/TypeImpl.js @@ -71,7 +71,7 @@ define( * this type, as might be shown in a Create wizard or * an Edit Properties view. * - * @return {Array Date: Tue, 11 Aug 2015 14:54:01 -0700 Subject: [PATCH 48/84] [Code Style] Use prototypes in entanglement bundle WTD-1482 --- .../src/actions/AbstractComposeAction.js | 126 +++++++++++++ .../entanglement/src/actions/CopyAction.js | 65 +------ .../entanglement/src/actions/LinkAction.js | 61 +----- .../entanglement/src/actions/MoveAction.js | 62 +----- .../entanglement/src/services/CopyService.js | 115 +++++------- .../entanglement/src/services/LinkService.js | 68 +++---- .../entanglement/src/services/MoveService.js | 83 ++++----- .../test/actions/AbstractComposeActionSpec.js | 176 ++++++++++++++++++ platform/entanglement/test/suite.json | 4 +- 9 files changed, 446 insertions(+), 314 deletions(-) create mode 100644 platform/entanglement/src/actions/AbstractComposeAction.js create mode 100644 platform/entanglement/test/actions/AbstractComposeActionSpec.js diff --git a/platform/entanglement/src/actions/AbstractComposeAction.js b/platform/entanglement/src/actions/AbstractComposeAction.js new file mode 100644 index 0000000000..cc78eb1888 --- /dev/null +++ b/platform/entanglement/src/actions/AbstractComposeAction.js @@ -0,0 +1,126 @@ +/***************************************************************************** + * 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 */ +define( + function () { + "use strict"; + + /** + * Common interface exposed by services which support move, copy, + * and link actions. + * @interface platform/entanglement.AbstractComposeService + * @private + */ + /** + * Change the composition of the specified objects. + * + * @param {DomainObject} domainObject the domain object to + * move, copy, or link. + * @param {DomainObject} parent the domain object whose composition + * will be changed to contain the domainObject (or its duplicate) + * @returns {Promise} A promise that is fulfilled when the + * duplicate operation has completed. + * @method platform/entanglement.AbstractComposeService#perform + */ + /** + * Check if one object can be composed into another. + * @param {DomainObject} domainObject the domain object to + * move, copy, or link. + * @param {DomainObject} parent the domain object whose composition + * will be changed to contain the domainObject (or its duplicate) + * @returns {boolean} true if this composition change is allowed + * @method platform/entanglement.AbstractComposeService#validate + */ + + + /** + * Template class for Move, Copy, and Link actions. + * + * @implements {Action} + * @constructor + * @private + * @memberof platform/entanglement + * @param {platform/entanglement.LocationService} locationService a + * service to request destinations from the user + * @param {platform/entanglement.AbstractComposeService} composeService + * a service which will handle actual changes to composition + * @param {ActionContext} the context in which the action will be performed + * @param {string} verb the verb to display for the action (e.g. "Move") + * @param {string} [suffix] a string to display in the dialog title; + * default is "to a new location" + */ + function AbstractComposeAction(locationService, composeService, context, verb, suffix) { + if (context.selectedObject) { + this.newParent = context.domainObject; + this.object = context.selectedObject; + } else { + this.object = context.domainObject; + } + + this.currentParent = this.object + .getCapability('context') + .getParent(); + + this.locationService = locationService; + this.composeService = composeService; + this.verb = verb || "Compose"; + this.suffix = suffix || "to a new location"; + } + + AbstractComposeAction.prototype.perform = function () { + var dialogTitle, + label, + validateLocation, + locationService = this.locationService, + composeService = this.composeService, + currentParent = this.currentParent, + newParent = this.newParent, + object = this.object; + + if (newParent) { + return composeService.perform(object, newParent); + } + + dialogTitle = [this.verb, object.getModel().name, this.suffix] + .join(" "); + + label = this.verb + " To"; + + validateLocation = function (newParent) { + return composeService.validate(object, newParent); + }; + + return locationService.getLocationFromUser( + dialogTitle, + label, + validateLocation, + currentParent + ).then(function (newParent) { + return composeService.perform(object, newParent); + }); + }; + + return AbstractComposeAction; + } +); + diff --git a/platform/entanglement/src/actions/CopyAction.js b/platform/entanglement/src/actions/CopyAction.js index 33fe826ace..3411fdba85 100644 --- a/platform/entanglement/src/actions/CopyAction.js +++ b/platform/entanglement/src/actions/CopyAction.js @@ -22,71 +22,26 @@ /*global define */ define( - function () { + ['./AbstractComposeAction'], + function (AbstractComposeAction) { "use strict"; - /** * The CopyAction is available from context menus and allows a user to * deep copy an object to another location of their choosing. * - * @implements Action + * @implements {Action} * @constructor * @memberof platform/entanglement */ function CopyAction(locationService, copyService, context) { - - var object, - newParent, - currentParent; - - if (context.selectedObject) { - newParent = context.domainObject; - object = context.selectedObject; - } else { - object = context.domainObject; - } - - currentParent = object - .getCapability('context') - .getParent(); - - return { - perform: function () { - - if (newParent) { - return copyService - .perform(object, newParent); - } - - var dialogTitle, - label, - validateLocation; - - dialogTitle = [ - "Duplicate ", - object.getModel().name, - " to a location" - ].join(""); - - label = "Duplicate To"; - - validateLocation = function (newParent) { - return copyService - .validate(object, newParent); - }; - - return locationService.getLocationFromUser( - dialogTitle, - label, - validateLocation, - currentParent - ).then(function (newParent) { - return copyService - .perform(object, newParent); - }); - } - }; + return new AbstractComposeAction( + locationService, + copyService, + context, + "Duplicate", + "to a location" + ); } return CopyAction; diff --git a/platform/entanglement/src/actions/LinkAction.js b/platform/entanglement/src/actions/LinkAction.js index 42bc446758..c791310886 100644 --- a/platform/entanglement/src/actions/LinkAction.js +++ b/platform/entanglement/src/actions/LinkAction.js @@ -22,68 +22,25 @@ /*global define */ define( - function () { + ['./AbstractComposeAction'], + function (AbstractComposeAction) { "use strict"; /** * The LinkAction is available from context menus and allows a user to * link an object to another location of their choosing. * - * @implements Action + * @implements {Action} * @constructor * @memberof platform/entanglement */ function LinkAction(locationService, linkService, context) { - - var object, - newParent, - currentParent; - - if (context.selectedObject) { - newParent = context.domainObject; - object = context.selectedObject; - } else { - object = context.domainObject; - } - - currentParent = object - .getCapability('context') - .getParent(); - - return { - perform: function () { - if (newParent) { - return linkService - .perform(object, newParent); - } - var dialogTitle, - label, - validateLocation; - - dialogTitle = [ - "Link ", - object.getModel().name, - " to a new location" - ].join(""); - - label = "Link To"; - - validateLocation = function (newParent) { - return linkService - .validate(object, newParent); - }; - - return locationService.getLocationFromUser( - dialogTitle, - label, - validateLocation, - currentParent - ).then(function (newParent) { - return linkService - .perform(object, newParent); - }); - } - }; + return new AbstractComposeAction( + locationService, + linkService, + context, + "Link" + ); } return LinkAction; diff --git a/platform/entanglement/src/actions/MoveAction.js b/platform/entanglement/src/actions/MoveAction.js index 7a89279766..4fdd4b59df 100644 --- a/platform/entanglement/src/actions/MoveAction.js +++ b/platform/entanglement/src/actions/MoveAction.js @@ -22,69 +22,25 @@ /*global define */ define( - function () { + ['./AbstractComposeAction'], + function (AbstractComposeAction) { "use strict"; /** * The MoveAction is available from context menus and allows a user to * move an object to another location of their choosing. * - * @implements Action + * @implements {Action} * @constructor * @memberof platform/entanglement */ function MoveAction(locationService, moveService, context) { - - var object, - newParent, - currentParent; - - if (context.selectedObject) { - newParent = context.domainObject; - object = context.selectedObject; - } else { - object = context.domainObject; - } - - currentParent = object - .getCapability('context') - .getParent(); - - return { - perform: function () { - if (newParent) { - return moveService - .perform(object, newParent); - } - - var dialogTitle, - label, - validateLocation; - - dialogTitle = [ - "Move ", - object.getModel().name, - " to a new location" - ].join(""); - - label = "Move To"; - - validateLocation = function (newParent) { - return moveService - .validate(object, newParent); - }; - - return locationService.getLocationFromUser( - dialogTitle, - label, - validateLocation, - currentParent - ).then(function (newParent) { - return moveService - .perform(object, newParent); - }); - } - }; + return new AbstractComposeAction( + locationService, + moveService, + context, + "Move" + ); } return MoveAction; diff --git a/platform/entanglement/src/services/CopyService.js b/platform/entanglement/src/services/CopyService.js index 2b6c4063f8..d62eb2a0ed 100644 --- a/platform/entanglement/src/services/CopyService.js +++ b/platform/entanglement/src/services/CopyService.js @@ -32,79 +32,62 @@ define( * an object can be copied to a specific location. * @constructor * @memberof platform/entanglement + * @implements {platform/entanglement.AbstractComposeService} */ function CopyService($q, creationService, policyService) { + this.$q = $q; + this.creationService = creationService; + this.policyService = policyService; + } - /** - * duplicateObject duplicates a `domainObject` into the composition - * of `parent`, and then duplicates the composition of - * `domainObject` into the new object. - * - * This function is a recursive deep copy. - * - * @param {DomainObject} domainObject - the domain object to - * duplicate. - * @param {DomainObject} parent - the parent domain object to - * create the duplicate in. - * @returns {Promise} A promise that is fulfilled when the - * duplicate operation has completed. - * @memberof platform/entanglement.CopyService# - */ + CopyService.prototype.validate = function (object, parentCandidate) { + if (!parentCandidate || !parentCandidate.getId) { + return false; + } + if (parentCandidate.getId() === object.getId()) { + return false; + } + return this.policyService.allow( + "composition", + parentCandidate.getCapability('type'), + object.getCapability('type') + ); + }; + + CopyService.prototype.perform = function (domainObject, parent) { + var model = JSON.parse(JSON.stringify(domainObject.getModel())), + $q = this.$q, + self = this; + + // Wrapper for the recursive step function duplicateObject(domainObject, parent) { - var model = JSON.parse(JSON.stringify(domainObject.getModel())); - if (domainObject.hasCapability('composition')) { - model.composition = []; - } - - return creationService - .createObject(model, parent) - .then(function (newObject) { - if (!domainObject.hasCapability('composition')) { - return; - } - - return domainObject - .useCapability('composition') - .then(function (composees) { - // Duplicate composition serially to prevent - // write conflicts. - return composees.reduce(function (promise, composee) { - return promise.then(function () { - return duplicateObject(composee, newObject); - }); - }, $q.when(undefined)); - }); - }); + return self.perform(domainObject, parent); } - return { - /** - * Returns true if `object` can be copied into - * `parentCandidate`'s composition. - * @memberof platform/entanglement.CopyService# - */ - validate: function (object, parentCandidate) { - if (!parentCandidate || !parentCandidate.getId) { - return false; + if (domainObject.hasCapability('composition')) { + model.composition = []; + } + + return this.creationService + .createObject(model, parent) + .then(function (newObject) { + if (!domainObject.hasCapability('composition')) { + return; } - if (parentCandidate.getId() === object.getId()) { - return false; - } - return policyService.allow( - "composition", - parentCandidate.getCapability('type'), - object.getCapability('type') - ); - }, - /** - * Wrapper, @see {@link duplicateObject} for implementation. - * @memberof platform/entanglement.CopyService# - */ - perform: function (object, parentObject) { - return duplicateObject(object, parentObject); - } - }; - } + + return domainObject + .useCapability('composition') + .then(function (composees) { + // Duplicate composition serially to prevent + // write conflicts. + return composees.reduce(function (promise, composee) { + return promise.then(function () { + return duplicateObject(composee, newObject); + }); + }, $q.when(undefined)); + }); + }); + }; return CopyService; } diff --git a/platform/entanglement/src/services/LinkService.js b/platform/entanglement/src/services/LinkService.js index 163e80e647..a78f5f6368 100644 --- a/platform/entanglement/src/services/LinkService.js +++ b/platform/entanglement/src/services/LinkService.js @@ -32,49 +32,39 @@ define( * can be copied to a specific location. * @constructor * @memberof platform/entanglement + * @implements {platform/entanglement.AbstractComposeService} */ function LinkService(policyService) { - return { - /** - * Returns `true` if `object` can be linked into - * `parentCandidate`'s composition. - * @memberof platform/entanglement.LinkService# - */ - validate: function (object, parentCandidate) { - if (!parentCandidate || !parentCandidate.getId) { - return false; - } - if (parentCandidate.getId() === object.getId()) { - return false; - } - if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) { - return false; - } - return policyService.allow( - "composition", - parentCandidate.getCapability('type'), - object.getCapability('type') - ); - }, - /** - * Link `object` into `parentObject`'s composition. - * - * @returns {Promise} A promise that is fulfilled when the - * linking operation has completed. - * @memberof platform/entanglement.LinkService# - */ - perform: function (object, parentObject) { - return parentObject.useCapability('mutation', function (model) { - if (model.composition.indexOf(object.getId()) === -1) { - model.composition.push(object.getId()); - } - }).then(function () { - return parentObject.getCapability('persistence').persist(); - }); - } - }; + this.policyService = policyService; } + LinkService.prototype.validate = function (object, parentCandidate) { + if (!parentCandidate || !parentCandidate.getId) { + return false; + } + if (parentCandidate.getId() === object.getId()) { + return false; + } + if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) { + return false; + } + return this.policyService.allow( + "composition", + parentCandidate.getCapability('type'), + object.getCapability('type') + ); + }; + + LinkService.prototype.perform = function (object, parentObject) { + return parentObject.useCapability('mutation', function (model) { + if (model.composition.indexOf(object.getId()) === -1) { + model.composition.push(object.getId()); + } + }).then(function () { + return parentObject.getCapability('persistence').persist(); + }); + }; + return LinkService; } ); diff --git a/platform/entanglement/src/services/MoveService.js b/platform/entanglement/src/services/MoveService.js index 2fbe2d69bf..9c374ee37d 100644 --- a/platform/entanglement/src/services/MoveService.js +++ b/platform/entanglement/src/services/MoveService.js @@ -32,56 +32,47 @@ define( * an object can be copied to a specific location. * @constructor * @memberof platform/entanglement + * @implements {platform/entanglement.AbstractComposeService} */ function MoveService(policyService, linkService) { - return { - /** - * Returns `true` if `object` can be moved into - * `parentCandidate`'s composition. - * @memberof platform/entanglement.MoveService# - */ - validate: function (object, parentCandidate) { - var currentParent = object - .getCapability('context') - .getParent(); - - if (!parentCandidate || !parentCandidate.getId) { - return false; - } - if (parentCandidate.getId() === currentParent.getId()) { - return false; - } - if (parentCandidate.getId() === object.getId()) { - return false; - } - if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) { - return false; - } - return policyService.allow( - "composition", - parentCandidate.getCapability('type'), - object.getCapability('type') - ); - }, - /** - * Move `object` into `parentObject`'s composition. - * - * @returns {Promise} A promise that is fulfilled when the - * move operation has completed. - * @memberof platform/entanglement.MoveService# - */ - perform: function (object, parentObject) { - return linkService - .perform(object, parentObject) - .then(function () { - return object - .getCapability('action') - .perform('remove'); - }); - } - }; + this.policyService = policyService; + this.linkService = linkService; } + MoveService.prototype.validate = function (object, parentCandidate) { + var currentParent = object + .getCapability('context') + .getParent(); + + if (!parentCandidate || !parentCandidate.getId) { + return false; + } + if (parentCandidate.getId() === currentParent.getId()) { + return false; + } + if (parentCandidate.getId() === object.getId()) { + return false; + } + if (parentCandidate.getModel().composition.indexOf(object.getId()) !== -1) { + return false; + } + return this.policyService.allow( + "composition", + parentCandidate.getCapability('type'), + object.getCapability('type') + ); + }; + + MoveService.prototype.perform = function (object, parentObject) { + return this.linkService + .perform(object, parentObject) + .then(function () { + return object + .getCapability('action') + .perform('remove'); + }); + }; + return MoveService; } ); diff --git a/platform/entanglement/test/actions/AbstractComposeActionSpec.js b/platform/entanglement/test/actions/AbstractComposeActionSpec.js new file mode 100644 index 0000000000..5be0604ec3 --- /dev/null +++ b/platform/entanglement/test/actions/AbstractComposeActionSpec.js @@ -0,0 +1,176 @@ +/***************************************************************************** + * 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,describe,beforeEach,it,jasmine,expect */ + +define( + [ + '../../src/actions/AbstractComposeAction', + '../services/MockCopyService', + '../DomainObjectFactory' + ], + function (AbstractComposeAction, MockCopyService, domainObjectFactory) { + "use strict"; + + describe("Move/copy/link Actions", function () { + + var action, + locationService, + locationServicePromise, + composeService, + context, + selectedObject, + selectedObjectContextCapability, + currentParent, + newParent; + + beforeEach(function () { + selectedObjectContextCapability = jasmine.createSpyObj( + 'selectedObjectContextCapability', + [ + 'getParent' + ] + ); + + selectedObject = domainObjectFactory({ + name: 'selectedObject', + model: { + name: 'selectedObject' + }, + capabilities: { + context: selectedObjectContextCapability + } + }); + + currentParent = domainObjectFactory({ + name: 'currentParent' + }); + + selectedObjectContextCapability + .getParent + .andReturn(currentParent); + + newParent = domainObjectFactory({ + name: 'newParent' + }); + + locationService = jasmine.createSpyObj( + 'locationService', + [ + 'getLocationFromUser' + ] + ); + + locationServicePromise = jasmine.createSpyObj( + 'locationServicePromise', + [ + 'then' + ] + ); + + locationService + .getLocationFromUser + .andReturn(locationServicePromise); + + composeService = new MockCopyService(); + }); + + + describe("with context from context-action", function () { + beforeEach(function () { + context = { + domainObject: selectedObject + }; + + action = new AbstractComposeAction( + locationService, + composeService, + context, + "Compose" + ); + }); + + it("initializes happily", function () { + expect(action).toBeDefined(); + }); + + describe("when performed it", function () { + beforeEach(function () { + action.perform(); + }); + + it("prompts for location", function () { + expect(locationService.getLocationFromUser) + .toHaveBeenCalledWith( + "Compose selectedObject to a new location", + "Compose To", + jasmine.any(Function), + currentParent + ); + }); + + it("waits for location from user", function () { + expect(locationServicePromise.then) + .toHaveBeenCalledWith(jasmine.any(Function)); + }); + + it("copies object to selected location", function () { + locationServicePromise + .then + .mostRecentCall + .args[0](newParent); + + expect(composeService.perform) + .toHaveBeenCalledWith(selectedObject, newParent); + }); + }); + }); + + describe("with context from drag-drop", function () { + beforeEach(function () { + context = { + selectedObject: selectedObject, + domainObject: newParent + }; + + action = new AbstractComposeAction( + locationService, + composeService, + context, + "Compose" + ); + }); + + it("initializes happily", function () { + expect(action).toBeDefined(); + }); + + + it("performs copy immediately", function () { + action.perform(); + expect(composeService.perform) + .toHaveBeenCalledWith(selectedObject, newParent); + }); + }); + }); + } +); diff --git a/platform/entanglement/test/suite.json b/platform/entanglement/test/suite.json index 40c300e213..2f91b5635c 100644 --- a/platform/entanglement/test/suite.json +++ b/platform/entanglement/test/suite.json @@ -1,7 +1,5 @@ [ - "actions/CopyAction", - "actions/LinkAction", - "actions/MoveAction", + "actions/AbstractComposeAction", "services/CopyService", "services/LinkService", "services/MoveService", From 7911909c5fa8b85458e11a5d6eab7ff39d77cfa2 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 11 Aug 2015 15:02:52 -0700 Subject: [PATCH 49/84] [Code Style] Use prototypes for execution bundle WTD-1482. --- platform/execution/src/WorkerService.js | 35 ++++++++++++------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/platform/execution/src/WorkerService.js b/platform/execution/src/WorkerService.js index a428947a5c..68eb171b0f 100644 --- a/platform/execution/src/WorkerService.js +++ b/platform/execution/src/WorkerService.js @@ -38,8 +38,7 @@ define( * @constructor */ function WorkerService($window, workers) { - var workerUrls = {}, - Worker = $window.Worker; + var workerUrls = {}; function addWorker(worker) { var key = worker.key; @@ -53,24 +52,24 @@ define( } (workers || []).forEach(addWorker); - - return { - /** - * Start running a new web worker. This will run a worker - * that has been registered under the `workers` category - * of extension. - * - * @param {string} key symbolic identifier for the worker - * @returns {Worker} the running Worker - * @memberof platform/execution.WorkerService# - */ - run: function (key) { - var scriptUrl = workerUrls[key]; - return scriptUrl && Worker && new Worker(scriptUrl); - } - }; + this.workerUrls = workerUrls; + this.Worker = $window.Worker; } + /** + * Start running a new web worker. This will run a worker + * that has been registered under the `workers` category + * of extension. + * + * @param {string} key symbolic identifier for the worker + * @returns {Worker} the running Worker + */ + WorkerService.prototype.run = function (key) { + var scriptUrl = this.workerUrls[key], + Worker = this.Worker; + return scriptUrl && Worker && new Worker(scriptUrl); + }; + return WorkerService; } ); From d701567b7030015a54c9dd83e134d5b167ecf50e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Tue, 11 Aug 2015 16:01:14 -0700 Subject: [PATCH 50/84] [Code Style] Use prototypes for Events bundle WTD-1482 --- platform/features/events/src/DomainColumn.js | 35 ++- .../events/src/EventListController.js | 24 ++ .../features/events/src/EventListPopulator.js | 225 +++++++++--------- platform/features/events/src/RangeColumn.js | 34 +-- .../events/src/policies/MessagesViewPolicy.js | 59 ++--- 5 files changed, 189 insertions(+), 188 deletions(-) diff --git a/platform/features/events/src/DomainColumn.js b/platform/features/events/src/DomainColumn.js index c906b45624..5ea23fa804 100644 --- a/platform/features/events/src/DomainColumn.js +++ b/platform/features/events/src/DomainColumn.js @@ -35,6 +35,7 @@ define( * * @memberof platform/features/events * @constructor + * @implements {platform/features/events.EventsColumn} * @param domainMetadata an object with the machine- and human- * readable names for this domain (in `key` and `name` * fields, respectively.) @@ -42,29 +43,21 @@ define( * formatting service, for making values human-readable. */ function DomainColumn(domainMetadata, telemetryFormatter) { - return { - /** - * Get the title to display in this column's header. - * @returns {string} the title to display - * @memberof platform/features/events.DomainColumn# - */ - getTitle: function () { - return domainMetadata.name; - }, - /** - * Get the text to display inside a row under this - * column. - * @returns {string} the text to display - * @memberof platform/features/events.DomainColumn# - */ - getValue: function (domainObject, data, index) { - return telemetryFormatter.formatDomainValue( - data.getDomainValue(index, domainMetadata.key) - ); - } - }; + this.domainMetadata = domainMetadata; + this.telemetryFormatter = telemetryFormatter; } + DomainColumn.prototype.getTitle = function () { + return this.domainMetadata.name; + }; + + DomainColumn.prototype.getValue = function (domainObject, data, index) { + var domainKey = this.domainMetadata.key; + return this.telemetryFormatter.formatDomainValue( + data.getDomainValue(index, domainKey) + ); + }; + return DomainColumn; } ); diff --git a/platform/features/events/src/EventListController.js b/platform/features/events/src/EventListController.js index c2247dde8c..dbb76712bd 100644 --- a/platform/features/events/src/EventListController.js +++ b/platform/features/events/src/EventListController.js @@ -135,6 +135,30 @@ define( } return EventListController; + + /** + * A description of how to display a certain column of data in an + * Events view. + * @interface platform/features/events.EventColumn + * @private + */ + /** + * Get the title to display in this column's header. + * @returns {string} the title to display + * @method platform/features/events.EventColumn#getTitle + */ + /** + * Get the text to display inside a row under this + * column. + * @param {DomainObject} domainObject the domain object associated + * with this row + * @param {TelemetrySeries} series the telemetry data associated + * with this row + * @param {number} index the index of the telemetry datum associated + * with this row + * @returns {string} the text to display + * @method platform/features/events.EventColumn#getValue + */ } ); diff --git a/platform/features/events/src/EventListPopulator.js b/platform/features/events/src/EventListPopulator.js index f9581e0890..fca5bea74d 100644 --- a/platform/features/events/src/EventListPopulator.js +++ b/platform/features/events/src/EventListPopulator.js @@ -35,129 +35,130 @@ define( * @param {Column[]} columns the columns to be populated */ function EventListPopulator(columns) { - /* - * Look up the most recent values from a set of data objects. - * Returns an array of objects in the order in which data - * should be displayed; each element is an object with - * two properties: - * - * * objectIndex: The index of the domain object associated - * with the data point to be displayed in that - * row. - * * pointIndex: The index of the data point itself, within - * its data set. - * - * @param {Array} datas an array of the most recent - * data objects; expected to be in the same order - * as the domain objects provided at constructor - * @param {number} count the number of rows to provide - */ - function getLatestDataValues(datas, count) { - var latest = [], - candidate, - candidateTime, - used = datas.map(function () { return 0; }); + this.columns = columns; + } - // This algorithm is O(nk) for n rows and k telemetry elements; - // one O(k) linear search for a max is made for each of n rows. - // This could be done in O(n lg k + k lg k), using a priority - // queue (where priority is max-finding) containing k initial - // values. For n rows, pop the max from the queue and replenish - // the queue with a value from the data at the same - // objectIndex, if available. - // But k is small, so this might not give an observable - // improvement in performance. + /* + * Look up the most recent values from a set of data objects. + * Returns an array of objects in the order in which data + * should be displayed; each element is an object with + * two properties: + * + * * objectIndex: The index of the domain object associated + * with the data point to be displayed in that + * row. + * * pointIndex: The index of the data point itself, within + * its data set. + * + * @param {Array} datas an array of the most recent + * data objects; expected to be in the same order + * as the domain objects provided at constructor + * @param {number} count the number of rows to provide + */ + function getLatestDataValues(datas, count) { + var latest = [], + candidate, + candidateTime, + used = datas.map(function () { return 0; }); - // Find the most recent unused data point (this will be used - // in a loop to find and the N most recent data points) - function findCandidate(data, i) { - var nextTime, - pointCount = data.getPointCount(), - pointIndex = pointCount - used[i] - 1; - if (data && pointIndex >= 0) { - nextTime = data.getDomainValue(pointIndex); - if (nextTime > candidateTime) { - candidateTime = nextTime; - candidate = { - objectIndex: i, - pointIndex: pointIndex - }; - } + // This algorithm is O(nk) for n rows and k telemetry elements; + // one O(k) linear search for a max is made for each of n rows. + // This could be done in O(n lg k + k lg k), using a priority + // queue (where priority is max-finding) containing k initial + // values. For n rows, pop the max from the queue and replenish + // the queue with a value from the data at the same + // objectIndex, if available. + // But k is small, so this might not give an observable + // improvement in performance. + + // Find the most recent unused data point (this will be used + // in a loop to find and the N most recent data points) + function findCandidate(data, i) { + var nextTime, + pointCount = data.getPointCount(), + pointIndex = pointCount - used[i] - 1; + if (data && pointIndex >= 0) { + nextTime = data.getDomainValue(pointIndex); + if (nextTime > candidateTime) { + candidateTime = nextTime; + candidate = { + objectIndex: i, + pointIndex: pointIndex + }; } } - - // Assemble a list of the most recent data points - while (latest.length < count) { - // Reset variables pre-search - candidateTime = Number.NEGATIVE_INFINITY; - candidate = undefined; - - // Linear search for most recent - datas.forEach(findCandidate); - - if (candidate) { - // Record this data point - it is the most recent - latest.push(candidate); - - // Track the data points used so we can look farther back - // in the data set on the next iteration - used[candidate.objectIndex] = used[candidate.objectIndex] + 1; - } else { - // Ran out of candidates; not enough data points - // available to fill all rows. - break; - } - } - - return latest; } + // Assemble a list of the most recent data points + while (latest.length < count) { + // Reset variables pre-search + candidateTime = Number.NEGATIVE_INFINITY; + candidate = undefined; - return { - /** - * Get the text which should appear in headers for the - * provided columns. - * @memberof platform/features/events.EventListPopulator - * @returns {string[]} column headers - */ - getHeaders: function () { - return columns.map(function (column) { - return column.getTitle(); - }); - }, - /** - * Get the contents of rows for the event list view. - * @param {TelemetrySeries[]} datas the data sets - * @param {DomainObject[]} objects the domain objects which - * provided the data sets; these should match - * index-to-index with the `datas` argument - * @param {number} count the number of rows to populate - * @memberof platform/features/events.EventListPopulator - * @returns {string[][]} an array of rows, each of which - * is an array of values which should appear - * in that row - */ - getRows: function (datas, objects, count) { - var values = getLatestDataValues(datas, count); + // Linear search for most recent + datas.forEach(findCandidate); - // Each value will become a row, which will contain - // some value in each column (rendering by the - // column object itself) - // Additionally, we want to display the rows in reverse - // order. (i.e. from the top to the bottom of the page) - return values.map(function (value) { - return columns.map(function (column) { - return column.getValue( - objects[value.objectIndex], - datas[value.objectIndex], - value.pointIndex - ); - }); - }).reverse(); + if (candidate) { + // Record this data point - it is the most recent + latest.push(candidate); + + // Track the data points used so we can look farther back + // in the data set on the next iteration + used[candidate.objectIndex] = used[candidate.objectIndex] + 1; + } else { + // Ran out of candidates; not enough data points + // available to fill all rows. + break; } - }; + } + + return latest; } + /** + * Get the text which should appear in headers for the + * provided columns. + * @memberof platform/features/events.EventListPopulator + * @returns {string[]} column headers + */ + EventListPopulator.prototype.getHeaders = function () { + return this.columns.map(function (column) { + return column.getTitle(); + }); + }; + + /** + * Get the contents of rows for the event list view. + * @param {TelemetrySeries[]} datas the data sets + * @param {DomainObject[]} objects the domain objects which + * provided the data sets; these should match + * index-to-index with the `datas` argument + * @param {number} count the number of rows to populate + * @memberof platform/features/events.EventListPopulator + * @returns {string[][]} an array of rows, each of which + * is an array of values which should appear + * in that row + */ + EventListPopulator.prototype.getRows = function (datas, objects, count) { + var values = getLatestDataValues(datas, count), + columns = this.columns; + + // Each value will become a row, which will contain + // some value in each column (rendering by the + // column object itself) + // Additionally, we want to display the rows in reverse + // order. (i.e. from the top to the bottom of the page) + return values.map(function (value) { + return columns.map(function (column) { + return column.getValue( + objects[value.objectIndex], + datas[value.objectIndex], + value.pointIndex + ); + }); + }).reverse(); + }; + return EventListPopulator; } diff --git a/platform/features/events/src/RangeColumn.js b/platform/features/events/src/RangeColumn.js index 56d9231a01..f31e1d9550 100644 --- a/platform/features/events/src/RangeColumn.js +++ b/platform/features/events/src/RangeColumn.js @@ -35,6 +35,7 @@ define( * * @memberof platform/features/events * @constructor + * @implements {platform/features/events.EventsColumn} * @param rangeMetadata an object with the machine- and human- * readable names for this range (in `key` and `name` * fields, respectively.) @@ -42,29 +43,20 @@ define( * formatting service, for making values human-readable. */ function RangeColumn(rangeMetadata, telemetryFormatter) { - return { - /** - * Get the title to display in this column's header. - * @returns {string} the title to display - * @memberof platform/features/events.RangeColumn# - */ - getTitle: function () { - return rangeMetadata.name; - }, - /** - * Get the text to display inside a row under this - * column. - * @returns {string} the text to display - * @memberof platform/features/events.RangeColumn# - */ - getValue: function (domainObject, data, index) { - return telemetryFormatter.formatRangeValue( - data.getRangeValue(index, rangeMetadata.key) - ); - } - }; + this.rangeMetadata = rangeMetadata; + this.telemetryFormatter = telemetryFormatter; } + RangeColumn.prototype.getTitle = function () { + return this.rangeMetadata.name; + }; + RangeColumn.prototype.getValue = function (domainObject, data, index) { + var rangeKey = this.rangeMetadata.key; + return this.telemetryFormatter.formatRangeValue( + data.getRangeValue(index, rangeKey) + ); + }; + return RangeColumn; } ); diff --git a/platform/features/events/src/policies/MessagesViewPolicy.js b/platform/features/events/src/policies/MessagesViewPolicy.js index 1458b9d8eb..712992c0a2 100644 --- a/platform/features/events/src/policies/MessagesViewPolicy.js +++ b/platform/features/events/src/policies/MessagesViewPolicy.js @@ -33,44 +33,35 @@ define( * Policy controlling when the Messages view should be avaliable. * @memberof platform/features/events * @constructor + * @implements {Policy.} */ - function MessagesViewPolicy() { - - function hasStringTelemetry(domainObject) { - var telemetry = domainObject && - domainObject.getCapability('telemetry'), - metadata = telemetry ? telemetry.getMetadata() : {}, - ranges = metadata.ranges || []; + function MessagesViewPolicy() {} - return ranges.some(function (range) { - return range.format === 'string'; - }); - } - return { - /** - * Check whether or not a given action is allowed by this - * policy. - * @param {Action} action the action - * @param domainObject the domain object which will be viewed - * @returns {boolean} true if not disallowed - * @memberof platform/features/events.MessagesViewPolicy# - */ - allow: function (view, domainObject) { - // This policy only applies for the Messages view - if (view.key === 'messages') { - // The Messages view is allowed only if the domain - // object has string telemetry - if (!hasStringTelemetry(domainObject)) { - return false; - } - } - - // Like all policies, allow by default. - return true; - } - }; + function hasStringTelemetry(domainObject) { + var telemetry = domainObject && + domainObject.getCapability('telemetry'), + metadata = telemetry ? telemetry.getMetadata() : {}, + ranges = metadata.ranges || []; + + return ranges.some(function (range) { + return range.format === 'string'; + }); } + MessagesViewPolicy.prototype.allow = function (view, domainObject) { + // This policy only applies for the Messages view + if (view.key === 'messages') { + // The Messages view is allowed only if the domain + // object has string telemetry + if (!hasStringTelemetry(domainObject)) { + return false; + } + } + + // Like all policies, allow by default. + return true; + }; + return MessagesViewPolicy; } ); From a9e2d480362f6c8357df05ff7a0e9e21e3c4ff34 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 12 Aug 2015 09:57:05 -0700 Subject: [PATCH 51/84] [Code Style] Use prototypes in Imagery bundle WTD-1482 --- .../src/controllers/ImageryController.js | 151 +++++++++--------- .../imagery/src/policies/ImageryViewPolicy.js | 40 +++-- 2 files changed, 94 insertions(+), 97 deletions(-) diff --git a/platform/features/imagery/src/controllers/ImageryController.js b/platform/features/imagery/src/controllers/ImageryController.js index 30513e7e6b..8bd8c36034 100644 --- a/platform/features/imagery/src/controllers/ImageryController.js +++ b/platform/features/imagery/src/controllers/ImageryController.js @@ -40,40 +40,29 @@ define( * @memberof platform/features/imagery */ function ImageryController($scope, telemetryHandler) { - var date = "", - time = "", - imageUrl = "", - paused = false, - handle; + var self = this; function releaseSubscription() { - if (handle) { - handle.unsubscribe(); - handle = undefined; + if (self.handle) { + self.handle.unsubscribe(); + self.handle = undefined; } } - function updateValues() { - var imageObject = handle && handle.getTelemetryObjects()[0], - m; - if (imageObject && !paused) { - m = moment.utc(handle.getDomainValue(imageObject)); - date = m.format(DATE_FORMAT); - time = m.format(TIME_FORMAT); - imageUrl = handle.getRangeValue(imageObject); - } + function updateValuesCallback() { + return self.updateValues(); } // Create a new subscription; telemetrySubscriber gets // to do the meaningful work here. function subscribe(domainObject) { releaseSubscription(); - date = ""; - time = ""; - imageUrl = ""; - handle = domainObject && telemetryHandler.handle( + self.date = ""; + self.time = ""; + self.imageUrl = ""; + self.handle = domainObject && telemetryHandler.handle( domainObject, - updateValues, + updateValuesCallback, true // Lossless ); } @@ -83,62 +72,72 @@ define( // Unsubscribe when the plot is destroyed $scope.$on("$destroy", releaseSubscription); - - return { - /** - * Get the time portion (hours, minutes, seconds) of the - * timestamp associated with the incoming image telemetry. - * @returns {string} the time - * @memberof platform/features/imagery.ImageryController# - */ - getTime: function () { - return time; - }, - /** - * Get the date portion (month, year) of the - * timestamp associated with the incoming image telemetry. - * @returns {string} the date - * @memberof platform/features/imagery.ImageryController# - */ - getDate: function () { - return date; - }, - /** - * Get the time zone for the displayed time/date corresponding - * to the timestamp associated with the incoming image - * telemetry. - * @returns {string} the time - * @memberof platform/features/imagery.ImageryController# - */ - getZone: function () { - return "UTC"; - }, - /** - * Get the URL of the image telemetry to display. - * @returns {string} URL for telemetry image - * @memberof platform/features/imagery.ImageryController# - */ - getImageUrl: function () { - return imageUrl; - }, - /** - * Getter-setter for paused state of the view (true means - * paused, false means not.) - * @param {boolean} [state] the state to set - * @returns {boolean} the current state - * @memberof platform/features/imagery.ImageryController# - */ - paused: function (state) { - if (arguments.length > 0 && state !== paused) { - paused = state; - // Switch to latest image - updateValues(); - } - return paused; - } - }; } + // Update displayable values to reflect latest image telemetry + ImageryController.prototype.updateValues = function () { + var imageObject = + this.handle && this.handle.getTelemetryObjects()[0], + m; + if (imageObject && !this.isPaused) { + m = moment.utc(this.handle.getDomainValue(imageObject)); + this.date = m.format(DATE_FORMAT); + this.time = m.format(TIME_FORMAT); + this.imageUrl = this.handle.getRangeValue(imageObject); + } + }; + + /** + * Get the time portion (hours, minutes, seconds) of the + * timestamp associated with the incoming image telemetry. + * @returns {string} the time + */ + ImageryController.prototype.getTime = function () { + return this.time; + }; + + /** + * Get the date portion (month, year) of the + * timestamp associated with the incoming image telemetry. + * @returns {string} the date + */ + ImageryController.prototype.getDate = function () { + return this.date; + }; + + /** + * Get the time zone for the displayed time/date corresponding + * to the timestamp associated with the incoming image + * telemetry. + * @returns {string} the time + */ + ImageryController.prototype.getZone = function () { + return "UTC"; + }; + + /** + * Get the URL of the image telemetry to display. + * @returns {string} URL for telemetry image + */ + ImageryController.prototype.getImageUrl = function () { + return this.imageUrl; + }; + + /** + * Getter-setter for paused state of the view (true means + * paused, false means not.) + * @param {boolean} [state] the state to set + * @returns {boolean} the current state + */ + ImageryController.prototype.paused = function (state) { + if (arguments.length > 0 && state !== this.isPaused) { + this.isPaused = state; + // Switch to latest image + this.updateValues(); + } + return this.isPaused; + }; + return ImageryController; } ); diff --git a/platform/features/imagery/src/policies/ImageryViewPolicy.js b/platform/features/imagery/src/policies/ImageryViewPolicy.js index 127174d50a..f9f2e9c074 100644 --- a/platform/features/imagery/src/policies/ImageryViewPolicy.js +++ b/platform/features/imagery/src/policies/ImageryViewPolicy.js @@ -28,33 +28,31 @@ define( /** * Policy preventing the Imagery view from being made available for * domain objects which do not have associated image telemetry. - * @implements {Policy} + * @implements {Policy.} * @constructor - * @memberof platform/features/imagery */ function ImageryViewPolicy() { - function hasImageTelemetry(domainObject) { - var telemetry = domainObject && - domainObject.getCapability('telemetry'), - metadata = telemetry ? telemetry.getMetadata() : {}, - ranges = metadata.ranges || []; + } - return ranges.some(function (range) { - return range.format === 'imageUrl' || - range.format === 'image'; - }); + function hasImageTelemetry(domainObject) { + var telemetry = domainObject && + domainObject.getCapability('telemetry'), + metadata = telemetry ? telemetry.getMetadata() : {}, + ranges = metadata.ranges || []; + + return ranges.some(function (range) { + return range.format === 'imageUrl' || + range.format === 'image'; + }); + } + + ImageryViewPolicy.prototype.allow = function (view, domainObject) { + if (view.key === 'imagery') { + return hasImageTelemetry(domainObject); } - return { - allow: function (view, domainObject) { - if (view.key === 'imagery') { - return hasImageTelemetry(domainObject); - } - - return true; - } - }; - } + return true; + }; return ImageryViewPolicy; } From ed53808556d7fbd3e01a288838f3dbb6f2b6ce7d Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 12 Aug 2015 13:45:48 -0700 Subject: [PATCH 52/84] [Code Style] Use prototypes in Layout bundle WTD-1482 --- .../features/layout/src/FixedController.js | 199 ++++++------ .../features/layout/src/FixedDragHandle.js | 147 +++++---- platform/features/layout/src/FixedProxy.js | 58 ++-- .../layout/src/LayoutCompositionPolicy.js | 25 +- .../features/layout/src/LayoutController.js | 292 +++++++++--------- platform/features/layout/src/LayoutDrag.js | 110 +++---- .../features/layout/src/elements/BoxProxy.js | 1 - .../layout/src/elements/ElementFactory.js | 41 ++- .../layout/src/elements/ElementProxy.js | 186 +++++------ .../layout/src/elements/ImageProxy.js | 1 + .../layout/src/elements/LineHandle.js | 82 ++--- .../features/layout/src/elements/LineProxy.js | 1 + .../layout/src/elements/ResizeHandle.js | 66 ++-- .../layout/src/elements/TelemetryProxy.js | 1 + .../features/layout/src/elements/TextProxy.js | 1 + 15 files changed, 615 insertions(+), 596 deletions(-) diff --git a/platform/features/layout/src/FixedController.js b/platform/features/layout/src/FixedController.js index 4458e988ea..410c0d2f94 100644 --- a/platform/features/layout/src/FixedController.js +++ b/platform/features/layout/src/FixedController.js @@ -39,20 +39,16 @@ define( * @param {Scope} $scope the controller's Angular scope */ function FixedController($scope, $q, dialogService, telemetrySubscriber, telemetryFormatter) { - var gridSize = DEFAULT_GRID_SIZE, - dragging, + var self = this, subscription, - elementProxies = [], names = {}, // Cache names by ID values = {}, // Cache values by ID - elementProxiesById = {}, - handles = [], - moveHandle, - selection; + elementProxiesById = {}; // Convert from element x/y/width/height to an - // apropriate ng-style argument, to position elements. + // appropriate ng-style argument, to position elements. function convertPosition(elementProxy) { + var gridSize = self.gridSize; // Multiply position/dimensions by grid size return { left: (gridSize[0] * elementProxy.x()) + 'px', @@ -64,7 +60,7 @@ define( // Update the style for a selected element function updateSelectionStyle() { - var element = selection && selection.get(); + var element = self.selection && self.selection.get(); if (element) { element.style = convertPosition(element); } @@ -74,7 +70,7 @@ define( function generateDragHandle(elementHandle) { return new FixedDragHandle( elementHandle, - gridSize, + self.gridSize, updateSelectionStyle, $scope.commit ); @@ -85,17 +81,6 @@ define( return element.handles().map(generateDragHandle); } - // Select an element - function select(element) { - if (selection) { - // Update selection... - selection.select(element); - // ...as well as move, resize handles - moveHandle = generateDragHandle(element); - handles = generateDragHandles(element); - } - } - // Update the displayed value for this object function updateValue(telemetryObject) { var id = telemetryObject && telemetryObject.getId(), @@ -121,9 +106,9 @@ define( // Update element positions when grid size changes function updateElementPositions(layoutGrid) { // Update grid size from model - gridSize = layoutGrid || DEFAULT_GRID_SIZE; + self.gridSize = layoutGrid || DEFAULT_GRID_SIZE; - elementProxies.forEach(function (elementProxy) { + self.elementProxies.forEach(function (elementProxy) { elementProxy.style = convertPosition(elementProxy); }); } @@ -154,7 +139,7 @@ define( function refreshElements() { // Cache selection; we are instantiating new proxies // so we may want to restore this. - var selected = selection && selection.get(), + var selected = self.selection && self.selection.get(), elements = (($scope.configuration || {}).elements || []), index = -1; // Start with a 'not-found' value @@ -164,20 +149,20 @@ define( } // Create the new proxies... - elementProxies = elements.map(makeProxyElement); + self.elementProxies = elements.map(makeProxyElement); // Clear old selection, and restore if appropriate - if (selection) { - selection.deselect(); + if (self.selection) { + self.selection.deselect(); if (index > -1) { - select(elementProxies[index]); + self.select(self.elementProxies[index]); } } // Finally, rebuild lists of elements by id to // facilitate faster update when new telemetry comes in. elementProxiesById = {}; - elementProxies.forEach(function (elementProxy) { + self.elementProxies.forEach(function (elementProxy) { var id = elementProxy.id; if (elementProxy.element.type === 'fixed.telemetry') { // Provide it a cached name/value to avoid flashing @@ -232,7 +217,9 @@ define( // Refresh displayed elements refreshElements(); // Select the newly-added element - select(elementProxies[elementProxies.length - 1]); + self.select( + self.elementProxies[self.elementProxies.length - 1] + ); // Mark change as persistable if ($scope.commit) { $scope.commit("Dropped an element."); @@ -249,8 +236,8 @@ define( // Store the position of this element. addElement({ type: "fixed.telemetry", - x: Math.floor(position.x / gridSize[0]), - y: Math.floor(position.y / gridSize[1]), + x: Math.floor(position.x / self.gridSize[0]), + y: Math.floor(position.y / self.gridSize[1]), id: id, stroke: "transparent", color: "#cccccc", @@ -260,12 +247,17 @@ define( }); } + this.gridSize = DEFAULT_GRID_SIZE; + this.elementProxies = []; + this.generateDragHandle = generateDragHandle; + this.generateDragHandles = generateDragHandles; + // Track current selection state - selection = $scope.selection; + this.selection = $scope.selection; // Expose the view's selection proxy - if (selection) { - selection.proxy(new FixedProxy(addElement, $q, dialogService)); + if (this.selection) { + this.selection.proxy(new FixedProxy(addElement, $q, dialogService)); } // Refresh list of elements whenever model changes @@ -285,73 +277,80 @@ define( // Position panes where they are dropped $scope.$on("mctDrop", handleDrop); - - return { - /** - * Get the size of the grid, in pixels. The returned array - * is in the form `[x, y]`. - * @returns {number[]} the grid size - * @memberof platform/features/layout.FixedController# - */ - getGridSize: function () { - return gridSize; - }, - /** - * Get an array of elements in this panel; these are - * decorated proxies for both selection and display. - * @returns {Array} elements in this panel - * @memberof platform/features/layout.FixedController# - */ - getElements: function () { - return elementProxies; - }, - /** - * Check if the element is currently selected, or (if no - * argument is supplied) get the currently selected element. - * @returns {boolean} true if selected - * @memberof platform/features/layout.FixedController# - */ - selected: function (element) { - return selection && ((arguments.length > 0) ? - selection.selected(element) : selection.get()); - }, - /** - * Set the active user selection in this view. - * @param element the element to select - * @memberof platform/features/layout.FixedController# - */ - select: select, - /** - * Clear the current user selection. - * @memberof platform/features/layout.FixedController# - */ - clearSelection: function () { - if (selection) { - selection.deselect(); - handles = []; - moveHandle = undefined; - } - }, - /** - * Get drag handles. - * @returns {Array} drag handles for the current selection - * @memberof platform/features/layout.FixedController# - */ - handles: function () { - return handles; - }, - /** - * Get the handle to handle dragging to reposition an element. - * @returns {FixedDragHandle} the drag handle - * @memberof platform/features/layout.FixedController# - */ - moveHandle: function () { - return moveHandle; - } - }; - } + /** + * Get the size of the grid, in pixels. The returned array + * is in the form `[x, y]`. + * @returns {number[]} the grid size + * @memberof platform/features/layout.FixedController# + */ + FixedController.prototype.getGridSize = function () { + return this.gridSize; + }; + + /** + * Get an array of elements in this panel; these are + * decorated proxies for both selection and display. + * @returns {Array} elements in this panel + */ + FixedController.prototype.getElements = function () { + return this.elementProxies; + }; + + /** + * Check if the element is currently selected, or (if no + * argument is supplied) get the currently selected element. + * @returns {boolean} true if selected + */ + FixedController.prototype.selected = function (element) { + var selection = this.selection; + return selection && ((arguments.length > 0) ? + selection.selected(element) : selection.get()); + }; + + /** + * Set the active user selection in this view. + * @param element the element to select + */ + FixedController.prototype.select = function select(element) { + if (this.selection) { + // Update selection... + this.selection.select(element); + // ...as well as move, resize handles + this.mvHandle = this.generateDragHandle(element); + this.resizeHandles = this.generateDragHandles(element); + } + }; + + /** + * Clear the current user selection. + */ + FixedController.prototype.clearSelection = function () { + if (this.selection) { + this.selection.deselect(); + this.resizeHandles = []; + this.mvHandle = undefined; + } + }; + + /** + * Get drag handles. + * @returns {platform/features/layout.FixedDragHandle[]} + * drag handles for the current selection + */ + FixedController.prototype.handles = function () { + return this.resizeHandles; + }; + + /** + * Get the handle to handle dragging to reposition an element. + * @returns {platform/features/layout.FixedDragHandle} the drag handle + */ + FixedController.prototype.moveHandle = function () { + return this.mvHandle; + }; + return FixedController; } ); diff --git a/platform/features/layout/src/FixedDragHandle.js b/platform/features/layout/src/FixedDragHandle.js index a72bbbadb6..afc98eabaf 100644 --- a/platform/features/layout/src/FixedDragHandle.js +++ b/platform/features/layout/src/FixedDragHandle.js @@ -37,86 +37,77 @@ define( * @constructor */ function FixedDragHandle(elementHandle, gridSize, update, commit) { - var self = {}, - dragging; - - // Generate ng-style-appropriate style for positioning - function getStyle() { - // Adjust from grid to pixel coordinates - var x = elementHandle.x() * gridSize[0], - y = elementHandle.y() * gridSize[1]; - - // Convert to a CSS style centered on that point - return { - left: (x - DRAG_HANDLE_SIZE[0] / 2) + 'px', - top: (y - DRAG_HANDLE_SIZE[1] / 2) + 'px', - width: DRAG_HANDLE_SIZE[0] + 'px', - height: DRAG_HANDLE_SIZE[1] + 'px' - }; - } - - // Begin a drag gesture - function startDrag() { - // Cache initial x/y positions - dragging = { x: elementHandle.x(), y: elementHandle.y() }; - } - - // Reposition during drag - function continueDrag(delta) { - if (dragging) { - // Update x/y positions (snapping to grid) - elementHandle.x( - dragging.x + Math.round(delta[0] / gridSize[0]) - ); - elementHandle.y( - dragging.y + Math.round(delta[1] / gridSize[1]) - ); - // Invoke update callback - if (update) { - update(); - } - } - } - - // Conclude a drag gesture - function endDrag() { - // Clear cached state - dragging = undefined; - // Mark change as complete - if (commit) { - commit("Dragged handle."); - } - } - - return { - /** - * Get a CSS style to position this drag handle. - * @returns CSS style object (for `ng-style`) - * @memberof platform/features/layout.FixedDragHandle# - */ - style: getStyle, - /** - * Start a drag gesture. This should be called when a drag - * begins to track initial state. - * @memberof platform/features/layout.FixedDragHandle# - */ - startDrag: startDrag, - /** - * Continue a drag gesture; update x/y positions. - * @param {number[]} delta x/y pixel difference since drag - * started - * @memberof platform/features/layout.FixedDragHandle# - */ - continueDrag: continueDrag, - /** - * End a drag gesture. This should be callled when a drag - * concludes to trigger commit of changes. - * @memberof platform/features/layout.FixedDragHandle# - */ - endDrag: endDrag - }; + this.elementHandle = elementHandle; + this.gridSize = gridSize; + this.update = update; + this.commit = commit; } + /** + * Get a CSS style to position this drag handle. + * @returns CSS style object (for `ng-style`) + * @memberof platform/features/layout.FixedDragHandle# + */ + FixedDragHandle.prototype.style = function () { + // Adjust from grid to pixel coordinates + var x = this.elementHandle.x() * this.gridSize[0], + y = this.elementHandle.y() * this.gridSize[1]; + + // Convert to a CSS style centered on that point + return { + left: (x - DRAG_HANDLE_SIZE[0] / 2) + 'px', + top: (y - DRAG_HANDLE_SIZE[1] / 2) + 'px', + width: DRAG_HANDLE_SIZE[0] + 'px', + height: DRAG_HANDLE_SIZE[1] + 'px' + }; + }; + + /** + * Start a drag gesture. This should be called when a drag + * begins to track initial state. + */ + FixedDragHandle.prototype.startDrag = function startDrag() { + // Cache initial x/y positions + this.dragging = { + x: this.elementHandle.x(), + y: this.elementHandle.y() + }; + }; + + /** + * Continue a drag gesture; update x/y positions. + * @param {number[]} delta x/y pixel difference since drag + * started + */ + FixedDragHandle.prototype.continueDrag = function (delta) { + if (this.dragging) { + // Update x/y positions (snapping to grid) + this.elementHandle.x( + this.dragging.x + Math.round(delta[0] / this.gridSize[0]) + ); + this.elementHandle.y( + this.dragging.y + Math.round(delta[1] / this.gridSize[1]) + ); + // Invoke update callback + if (this.update) { + this.update(); + } + } + }; + + /** + * End a drag gesture. This should be callled when a drag + * concludes to trigger commit of changes. + */ + FixedDragHandle.prototype.endDrag = function () { + // Clear cached state + this.dragging = undefined; + // Mark change as complete + if (this.commit) { + this.commit("Dragged handle."); + } + }; + return FixedDragHandle; } ); diff --git a/platform/features/layout/src/FixedProxy.js b/platform/features/layout/src/FixedProxy.js index b84985f9d8..bb6c2f16c8 100644 --- a/platform/features/layout/src/FixedProxy.js +++ b/platform/features/layout/src/FixedProxy.js @@ -37,33 +37,41 @@ define( * when adding a new element will require user input */ function FixedProxy(addElementCallback, $q, dialogService) { - var factory = new ElementFactory(dialogService); - - return { - /** - * Add a new visual element to this view. - * @memberof platform/features/layout.FixedProxy# - */ - add: function (type) { - // Place a configured element into the view configuration - function addElement(element) { - // Configure common properties of the element - element.x = element.x || 0; - element.y = element.y || 0; - element.width = element.width || 1; - element.height = element.height || 1; - element.type = type; - - // Finally, add it to the view's configuration - addElementCallback(element); - } - - // Defer creation to the factory - $q.when(factory.createElement(type)).then(addElement); - } - }; + this.factory = new ElementFactory(dialogService); + this.$q = $q; + this.addElementCallback = addElementCallback; } + /** + * Add a new visual element to this view. Supported types are: + * + * * `fixed.image` + * * `fixed.box` + * * `fixed.text` + * * `fixed.line` + * + * @param {string} type the type of element to add + */ + FixedProxy.prototype.add = function (type) { + var addElementCallback = this.addElementCallback; + + // Place a configured element into the view configuration + function addElement(element) { + // Configure common properties of the element + element.x = element.x || 0; + element.y = element.y || 0; + element.width = element.width || 1; + element.height = element.height || 1; + element.type = type; + + // Finally, add it to the view's configuration + addElementCallback(element); + } + + // Defer creation to the factory + this.$q.when(this.factory.createElement(type)).then(addElement); + }; + return FixedProxy; } ); diff --git a/platform/features/layout/src/LayoutCompositionPolicy.js b/platform/features/layout/src/LayoutCompositionPolicy.js index 8f9b6ccf31..23d5a4f882 100644 --- a/platform/features/layout/src/LayoutCompositionPolicy.js +++ b/platform/features/layout/src/LayoutCompositionPolicy.js @@ -31,25 +31,20 @@ define( * They cannot contain folders. * @constructor * @memberof platform/features/layout + * @implements {Policy.} */ function LayoutCompositionPolicy() { - return { - /** - * Is the type identified by the candidate allowed to - * contain the type described by the context? - * @memberof platform/features/layout.LayoutCompositionPolicy# - */ - allow: function (candidate, context) { - var isFolderInLayout = - candidate && - context && - candidate.instanceOf('layout') && - context.instanceOf('folder'); - return !isFolderInLayout; - } - }; } + LayoutCompositionPolicy.prototype.allow = function (candidate, context) { + var isFolderInLayout = + candidate && + context && + candidate.instanceOf('layout') && + context.instanceOf('folder'); + return !isFolderInLayout; + }; + return LayoutCompositionPolicy; } ); diff --git a/platform/features/layout/src/LayoutController.js b/platform/features/layout/src/LayoutController.js index bf7c265de0..89364a1bb2 100644 --- a/platform/features/layout/src/LayoutController.js +++ b/platform/features/layout/src/LayoutController.js @@ -45,11 +45,7 @@ define( * @param {Scope} $scope the controller's Angular scope */ function LayoutController($scope) { - var gridSize = DEFAULT_GRID_SIZE, - activeDrag, - activeDragId, - rawPositions = {}, - positions = {}; + var self = this; // Utility function to copy raw positions from configuration, // without writing directly to configuration (to avoid triggering @@ -62,47 +58,6 @@ define( return copy; } - // Convert from { positions: ..., dimensions: ... } to an - // apropriate ng-style argument, to position frames. - function convertPosition(raw) { - // Multiply position/dimensions by grid size - return { - left: (gridSize[0] * raw.position[0]) + 'px', - top: (gridSize[1] * raw.position[1]) + 'px', - width: (gridSize[0] * raw.dimensions[0]) + 'px', - height: (gridSize[1] * raw.dimensions[1]) + 'px' - }; - } - - // Generate default positions for a new panel - function defaultDimensions() { - return MINIMUM_FRAME_SIZE.map(function (min, i) { - return Math.max( - Math.ceil(min / gridSize[i]), - DEFAULT_DIMENSIONS[i] - ); - }); - } - - // Generate a default position (in its raw format) for a frame. - // Use an index to ensure that default positions are unique. - function defaultPosition(index) { - return { - position: [index, index], - dimensions: defaultDimensions() - }; - } - - // Store a computed position for a contained frame by its - // domain object id. Called in a forEach loop, so arguments - // are as expected there. - function populatePosition(id, index) { - rawPositions[id] = - rawPositions[id] || defaultPosition(index || 0); - positions[id] = - convertPosition(rawPositions[id]); - } - // Compute panel positions based on the layout's object model function lookupPanels(ids) { var configuration = $scope.configuration || {}; @@ -112,27 +67,32 @@ define( ids = ids || []; // Pull panel positions from configuration - rawPositions = shallowCopy(configuration.panels || {}, ids); + self.rawPositions = + shallowCopy(configuration.panels || {}, ids); // Clear prior computed positions - positions = {}; + self.positions = {}; // Update width/height that we are tracking - gridSize = ($scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE; + self.gridSize = + ($scope.model || {}).layoutGrid || DEFAULT_GRID_SIZE; // Compute positions and add defaults where needed - ids.forEach(populatePosition); + ids.forEach(function (id, index) { + self.populatePosition(id, index); + }); } // Update grid size when it changed function updateGridSize(layoutGrid) { - var oldSize = gridSize; + var oldSize = self.gridSize; - gridSize = layoutGrid || DEFAULT_GRID_SIZE; + self.gridSize = layoutGrid || DEFAULT_GRID_SIZE; // Only update panel positions if this actually changed things - if (gridSize[0] !== oldSize[0] || gridSize[1] !== oldSize[1]) { - lookupPanels(Object.keys(positions)); + if (self.gridSize[0] !== oldSize[0] || + self.gridSize[1] !== oldSize[1]) { + lookupPanels(Object.keys(self.positions)); } } @@ -150,8 +110,8 @@ define( // Store the position of this panel. $scope.configuration.panels[id] = { position: [ - Math.floor(position.x / gridSize[0]), - Math.floor(position.y / gridSize[1]) + Math.floor(position.x / self.gridSize[0]), + Math.floor(position.y / self.gridSize[1]) ], dimensions: DEFAULT_DIMENSIONS }; @@ -160,13 +120,39 @@ define( $scope.commit("Dropped a frame."); } // Populate template-facing position for this id - populatePosition(id); + self.populatePosition(id); // Layout may contain embedded views which will // listen for drops, so call preventDefault() so // that they can recognize that this event is handled. e.preventDefault(); } + // End drag; we don't want to put $scope into this + // because it triggers "cpws" (copy window or scope) + // errors in Angular. + this.endDragInScope = function () { + // Write to configuration; this is watched and + // saved by the EditRepresenter. + $scope.configuration = + $scope.configuration || {}; + // Make sure there is a "panels" field in the + // view configuration. + $scope.configuration.panels = + $scope.configuration.panels || {}; + // Store the position of this panel. + $scope.configuration.panels[self.activeDragId] = + self.rawPositions[self.activeDragId]; + // Mark this object as dirty to encourage persistence + if ($scope.commit) { + $scope.commit("Moved frame."); + } + }; + + this.positions = {}; + this.rawPositions = {}; + this.gridSize = DEFAULT_GRID_SIZE; + this.$scope = $scope; + // Watch for changes to the grid size in the model $scope.$watch("model.layoutGrid", updateGridSize); @@ -175,92 +161,116 @@ define( // Position panes where they are dropped $scope.$on("mctDrop", handleDrop); - - return { - /** - * Get a style object for a frame with the specified domain - * object identifier, suitable for use in an `ng-style` - * directive to position a frame as configured for this layout. - * @param {string} id the object identifier - * @returns {Object.} an object with - * appropriate left, width, etc fields for positioning - * @memberof platform/features/layout.LayoutController# - */ - getFrameStyle: function (id) { - // Called in a loop, so just look up; the "positions" - // object is kept up to date by a watch. - return positions[id]; - }, - /** - * Start a drag gesture to move/resize a frame. - * - * The provided position and dimensions factors will determine - * whether this is a move or a resize, and what type it - * will be. For instance, a position factor of [1, 1] - * will move a frame along with the mouse as the drag - * proceeds, while a dimension factor of [0, 0] will leave - * dimensions unchanged. Combining these in different - * ways results in different handles; a position factor of - * [1, 0] and a dimensions factor of [-1, 0] will implement - * a left-edge resize, as the horizontal position will move - * with the mouse while the horizontal dimensions shrink in - * kind (and vertical properties remain unmodified.) - * - * @param {string} id the identifier of the domain object - * in the frame being manipulated - * @param {number[]} posFactor the position factor - * @param {number[]} dimFactor the dimensions factor - * @memberof platform/features/layout.LayoutController# - */ - startDrag: function (id, posFactor, dimFactor) { - activeDragId = id; - activeDrag = new LayoutDrag( - rawPositions[id], - posFactor, - dimFactor, - gridSize - ); - }, - /** - * Continue an active drag gesture. - * @param {number[]} delta the offset, in pixels, - * of the current pointer position, relative - * to its position when the drag started - * @memberof platform/features/layout.LayoutController# - */ - continueDrag: function (delta) { - if (activeDrag) { - rawPositions[activeDragId] = - activeDrag.getAdjustedPosition(delta); - populatePosition(activeDragId); - } - }, - /** - * End the active drag gesture. This will update the - * view configuration. - * @memberof platform/features/layout.LayoutController# - */ - endDrag: function () { - // Write to configuration; this is watched and - // saved by the EditRepresenter. - $scope.configuration = - $scope.configuration || {}; - // Make sure there is a "panels" field in the - // view configuration. - $scope.configuration.panels = - $scope.configuration.panels || {}; - // Store the position of this panel. - $scope.configuration.panels[activeDragId] = - rawPositions[activeDragId]; - // Mark this object as dirty to encourage persistence - if ($scope.commit) { - $scope.commit("Moved frame."); - } - } - }; - } + // Convert from { positions: ..., dimensions: ... } to an + // apropriate ng-style argument, to position frames. + LayoutController.prototype.convertPosition = function (raw) { + var gridSize = this.gridSize; + // Multiply position/dimensions by grid size + return { + left: (gridSize[0] * raw.position[0]) + 'px', + top: (gridSize[1] * raw.position[1]) + 'px', + width: (gridSize[0] * raw.dimensions[0]) + 'px', + height: (gridSize[1] * raw.dimensions[1]) + 'px' + }; + }; + + // Generate default positions for a new panel + LayoutController.prototype.defaultDimensions = function () { + var gridSize = this.gridSize; + return MINIMUM_FRAME_SIZE.map(function (min, i) { + return Math.max( + Math.ceil(min / gridSize[i]), + DEFAULT_DIMENSIONS[i] + ); + }); + }; + + // Generate a default position (in its raw format) for a frame. + // Use an index to ensure that default positions are unique. + LayoutController.prototype.defaultPosition = function (index) { + return { + position: [index, index], + dimensions: this.defaultDimensions() + }; + }; + + // Store a computed position for a contained frame by its + // domain object id. Called in a forEach loop, so arguments + // are as expected there. + LayoutController.prototype.populatePosition = function (id, index) { + this.rawPositions[id] = + this.rawPositions[id] || this.defaultPosition(index || 0); + this.positions[id] = + this.convertPosition(this.rawPositions[id]); + }; + + /** + * Get a style object for a frame with the specified domain + * object identifier, suitable for use in an `ng-style` + * directive to position a frame as configured for this layout. + * @param {string} id the object identifier + * @returns {Object.} an object with + * appropriate left, width, etc fields for positioning + */ + LayoutController.prototype.getFrameStyle = function (id) { + // Called in a loop, so just look up; the "positions" + // object is kept up to date by a watch. + return this.positions[id]; + }; + + /** + * Start a drag gesture to move/resize a frame. + * + * The provided position and dimensions factors will determine + * whether this is a move or a resize, and what type it + * will be. For instance, a position factor of [1, 1] + * will move a frame along with the mouse as the drag + * proceeds, while a dimension factor of [0, 0] will leave + * dimensions unchanged. Combining these in different + * ways results in different handles; a position factor of + * [1, 0] and a dimensions factor of [-1, 0] will implement + * a left-edge resize, as the horizontal position will move + * with the mouse while the horizontal dimensions shrink in + * kind (and vertical properties remain unmodified.) + * + * @param {string} id the identifier of the domain object + * in the frame being manipulated + * @param {number[]} posFactor the position factor + * @param {number[]} dimFactor the dimensions factor + */ + LayoutController.prototype.startDrag = function (id, posFactor, dimFactor) { + this.activeDragId = id; + this.activeDrag = new LayoutDrag( + this.rawPositions[id], + posFactor, + dimFactor, + this.gridSize + ); + }; + /** + * Continue an active drag gesture. + * @param {number[]} delta the offset, in pixels, + * of the current pointer position, relative + * to its position when the drag started + */ + LayoutController.prototype.continueDrag = function (delta) { + if (this.activeDrag) { + this.rawPositions[this.activeDragId] = + this.activeDrag.getAdjustedPosition(delta); + this.populatePosition(this.activeDragId); + } + }; + + /** + * End the active drag gesture. This will update the + * view configuration. + */ + LayoutController.prototype.endDrag = function () { + this.endDragInScope(); + }; + return LayoutController; } ); diff --git a/platform/features/layout/src/LayoutDrag.js b/platform/features/layout/src/LayoutDrag.js index 45f1ad9856..0c0ef6b1a7 100644 --- a/platform/features/layout/src/LayoutDrag.js +++ b/platform/features/layout/src/LayoutDrag.js @@ -54,63 +54,63 @@ define( * @memberof platform/features/layout */ function LayoutDrag(rawPosition, posFactor, dimFactor, gridSize) { - // Convert a delta from pixel coordinates to grid coordinates, - // rounding to whole-number grid coordinates. - function toGridDelta(pixelDelta) { - return pixelDelta.map(function (v, i) { - return Math.round(v / gridSize[i]); - }); - } - - // Utility function to perform element-by-element multiplication - function multiply(array, factors) { - return array.map(function (v, i) { - return v * factors[i]; - }); - } - - // Utility function to perform element-by-element addition - function add(array, other) { - return array.map(function (v, i) { - return v + other[i]; - }); - } - - // Utility function to perform element-by-element max-choosing - function max(array, other) { - return array.map(function (v, i) { - return Math.max(v, other[i]); - }); - } - - function getAdjustedPosition(pixelDelta) { - var gridDelta = toGridDelta(pixelDelta); - return { - position: max(add( - rawPosition.position, - multiply(gridDelta, posFactor) - ), [0, 0]), - dimensions: max(add( - rawPosition.dimensions, - multiply(gridDelta, dimFactor) - ), [1, 1]) - }; - - } - - return { - /** - * Get a new position object in grid coordinates, with - * position and dimensions both offset appropriately - * according to the factors supplied in the constructor. - * @param {number[]} pixelDelta the offset from the - * original position, in pixels - * @memberof platform/features/layout.LayoutDrag# - */ - getAdjustedPosition: getAdjustedPosition - }; + this.rawPosition = rawPosition; + this.posFactor = posFactor; + this.dimFactor = dimFactor; + this.gridSize = gridSize; } + // Convert a delta from pixel coordinates to grid coordinates, + // rounding to whole-number grid coordinates. + function toGridDelta(gridSize, pixelDelta) { + return pixelDelta.map(function (v, i) { + return Math.round(v / gridSize[i]); + }); + } + + // Utility function to perform element-by-element multiplication + function multiply(array, factors) { + return array.map(function (v, i) { + return v * factors[i]; + }); + } + + // Utility function to perform element-by-element addition + function add(array, other) { + return array.map(function (v, i) { + return v + other[i]; + }); + } + + // Utility function to perform element-by-element max-choosing + function max(array, other) { + return array.map(function (v, i) { + return Math.max(v, other[i]); + }); + } + + + /** + * Get a new position object in grid coordinates, with + * position and dimensions both offset appropriately + * according to the factors supplied in the constructor. + * @param {number[]} pixelDelta the offset from the + * original position, in pixels + */ + LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) { + var gridDelta = toGridDelta(this.gridSize, pixelDelta); + return { + position: max(add( + this.rawPosition.position, + multiply(gridDelta, this.posFactor) + ), [0, 0]), + dimensions: max(add( + this.rawPosition.dimensions, + multiply(gridDelta, this.dimFactor) + ), [1, 1]) + }; + }; + return LayoutDrag; } diff --git a/platform/features/layout/src/elements/BoxProxy.js b/platform/features/layout/src/elements/BoxProxy.js index 46ec351b1f..a4b6bc4c09 100644 --- a/platform/features/layout/src/elements/BoxProxy.js +++ b/platform/features/layout/src/elements/BoxProxy.js @@ -48,7 +48,6 @@ define( * Get/set this element's fill color. (Omitting the * argument makes this act as a getter.) * @method - * @memberof BoxProxy * @param {string} fill the new fill color * @returns {string} the fill color * @memberof platform/features/layout.BoxProxy# diff --git a/platform/features/layout/src/elements/ElementFactory.js b/platform/features/layout/src/elements/ElementFactory.js index 01cc4be729..63dbb82757 100644 --- a/platform/features/layout/src/elements/ElementFactory.js +++ b/platform/features/layout/src/elements/ElementFactory.js @@ -89,29 +89,28 @@ define( * @constructor */ function ElementFactory(dialogService) { - return { - /** - * Create a new element for the fixed position view. - * @param {string} type the type of element to create - * @returns {Promise|object} the created element, or a promise - * for that element - * @memberof platform/features/layout.ElementFactory# - */ - createElement: function (type) { - var initialState = INITIAL_STATES[type] || {}; - - // Clone that state - initialState = JSON.parse(JSON.stringify(initialState)); - - // Show a dialog to configure initial state, if appropriate - return DIALOGS[type] ? dialogService.getUserInput( - DIALOGS[type], - initialState - ) : initialState; - } - }; + this.dialogService = dialogService; } + /** + * Create a new element for the fixed position view. + * @param {string} type the type of element to create + * @returns {Promise|object} the created element, or a promise + * for that element + */ + ElementFactory.prototype.createElement = function (type) { + var initialState = INITIAL_STATES[type] || {}; + + // Clone that state + initialState = JSON.parse(JSON.stringify(initialState)); + + // Show a dialog to configure initial state, if appropriate + return DIALOGS[type] ? this.dialogService.getUserInput( + DIALOGS[type], + initialState + ) : initialState; + }; + return ElementFactory; } ); diff --git a/platform/features/layout/src/elements/ElementProxy.js b/platform/features/layout/src/elements/ElementProxy.js index 1261104a9e..5f3ef17bcb 100644 --- a/platform/features/layout/src/elements/ElementProxy.js +++ b/platform/features/layout/src/elements/ElementProxy.js @@ -56,96 +56,108 @@ define( * @param {Array} elements the full array of elements */ function ElementProxy(element, index, elements) { - var handles = [ new ResizeHandle(element, 1, 1) ]; + this.resizeHandles = [ new ResizeHandle(element, 1, 1) ]; - return { - /** - * The element as stored in the view configuration. - * @memberof platform/features/layout.ElementProxy# - */ - element: element, - /** - * Get and/or set the x position of this element. - * Units are in fixed position grid space. - * @param {number} [x] the new x position (if setting) - * @returns {number} the x position - * @memberof platform/features/layout.ElementProxy# - */ - x: new AccessorMutator(element, 'x', clamp), - /** - * Get and/or set the y position of this element. - * Units are in fixed position grid space. - * @param {number} [y] the new y position (if setting) - * @returns {number} the y position - * @memberof platform/features/layout.ElementProxy# - */ - y: new AccessorMutator(element, 'y', clamp), - /** - * Get and/or set the stroke color of this element. - * @param {string} [stroke] the new stroke color (if setting) - * @returns {string} the stroke color - * @memberof platform/features/layout.ElementProxy# - */ - stroke: new AccessorMutator(element, 'stroke'), - /** - * Get and/or set the width of this element. - * Units are in fixed position grid space. - * @param {number} [w] the new width (if setting) - * @returns {number} the width - * @memberof platform/features/layout.ElementProxy# - */ - width: new AccessorMutator(element, 'width'), - /** - * Get and/or set the height of this element. - * Units are in fixed position grid space. - * @param {number} [h] the new height (if setting) - * @returns {number} the height - * @memberof platform/features/layout.ElementProxy# - */ - height: new AccessorMutator(element, 'height'), - /** - * Change the display order of this element. - * @param {string} o where to move this element; - * one of "top", "up", "down", or "bottom" - * @memberof platform/features/layout.ElementProxy# - */ - order: function (o) { - var delta = ORDERS[o] || 0, - desired = Math.max( - Math.min(index + delta, elements.length - 1), - 0 - ); - // Move to the desired index, if this is a change - if ((desired !== index) && (elements[index] === element)) { - // Splice out the current element - elements.splice(index, 1); - // Splice it back in at the correct index - elements.splice(desired, 0, element); - // Track change in index (proxy should be recreated - // anyway, but be consistent) - index = desired; - } - }, - /** - * Remove this element from the fixed position view. - * @memberof platform/features/layout.ElementProxy# - */ - remove: function () { - if (elements[index] === element) { - elements.splice(index, 1); - } - }, - /** - * Get handles to control specific features of this element, - * e.g. corner size. - * @memberof platform/features/layout.ElementProxy# - */ - handles: function () { - return handles; - } - }; + /** + * The element as stored in the view configuration. + * @memberof platform/features/layout.ElementProxy# + */ + this.element = element; + + /** + * Get and/or set the x position of this element. + * Units are in fixed position grid space. + * @param {number} [x] the new x position (if setting) + * @returns {number} the x position + * @memberof platform/features/layout.ElementProxy# + */ + this.x = new AccessorMutator(element, 'x', clamp); + + /** + * Get and/or set the y position of this element. + * Units are in fixed position grid space. + * @param {number} [y] the new y position (if setting) + * @returns {number} the y position + * @memberof platform/features/layout.ElementProxy# + */ + this.y = new AccessorMutator(element, 'y', clamp); + + /** + * Get and/or set the stroke color of this element. + * @param {string} [stroke] the new stroke color (if setting) + * @returns {string} the stroke color + * @memberof platform/features/layout.ElementProxy# + */ + this.stroke = new AccessorMutator(element, 'stroke'); + + /** + * Get and/or set the width of this element. + * Units are in fixed position grid space. + * @param {number} [w] the new width (if setting) + * @returns {number} the width + * @memberof platform/features/layout.ElementProxy# + */ + this.width = new AccessorMutator(element, 'width'); + + /** + * Get and/or set the height of this element. + * Units are in fixed position grid space. + * @param {number} [h] the new height (if setting) + * @returns {number} the height + * @memberof platform/features/layout.ElementProxy# + */ + this.height = new AccessorMutator(element, 'height'); + + this.index = index; + this.elements = elements; } + /** + * Change the display order of this element. + * @param {string} o where to move this element; + * one of "top", "up", "down", or "bottom" + */ + ElementProxy.prototype.order = function (o) { + var index = this.index, + elements = this.elements, + element = this.element, + delta = ORDERS[o] || 0, + desired = Math.max( + Math.min(index + delta, elements.length - 1), + 0 + ); + // Move to the desired index, if this is a change + if ((desired !== index) && (elements[index] === element)) { + // Splice out the current element + elements.splice(index, 1); + // Splice it back in at the correct index + elements.splice(desired, 0, element); + // Track change in index (proxy should be recreated + // anyway, but be consistent) + this.index = desired; + } + }; + + /** + * Remove this element from the fixed position view. + */ + ElementProxy.prototype.remove = function () { + var index = this.index; + if (this.elements[index] === this.element) { + this.elements.splice(index, 1); + } + }; + + /** + * Get handles to control specific features of this element, + * e.g. corner size. + * @return {platform/features/layout.ElementHandle[]} handles + * for moving/resizing this element + */ + ElementProxy.prototype.handles = function () { + return this.resizeHandles; + }; + return ElementProxy; } ); diff --git a/platform/features/layout/src/elements/ImageProxy.js b/platform/features/layout/src/elements/ImageProxy.js index 28d84a3fa4..22ef3ef0c3 100644 --- a/platform/features/layout/src/elements/ImageProxy.js +++ b/platform/features/layout/src/elements/ImageProxy.js @@ -38,6 +38,7 @@ define( * configuration * @param index the element's index within its array * @param {Array} elements the full array of elements + * @augments {platform/features/layout.ElementProxy} */ function ImageProxy(element, index, elements) { var proxy = new ElementProxy(element, index, elements); diff --git a/platform/features/layout/src/elements/LineHandle.js b/platform/features/layout/src/elements/LineHandle.js index f4178f107b..c61d1f3802 100644 --- a/platform/features/layout/src/elements/LineHandle.js +++ b/platform/features/layout/src/elements/LineHandle.js @@ -37,48 +37,54 @@ define( * @param {string} yProperty field which stores x position * @param {string} xOther field which stores x of other end * @param {string} yOther field which stores y of other end + * @implements {platform/features/layout.ElementHandle} */ function LineHandle(element, xProperty, yProperty, xOther, yOther) { - return { - /** - * Get/set the x position of the lower-right corner - * of the handle-controlled element, changing size - * as necessary. - * @memberof platform/features/layout.LineHandle# - */ - x: function (value) { - if (arguments.length > 0) { - // Ensure we stay in view - value = Math.max(value, 0); - // Make sure end points will still be different - if (element[yOther] !== element[yProperty] || - element[xOther] !== value) { - element[xProperty] = value; - } - } - return element[xProperty]; - }, - /** - * Get/set the y position of the lower-right corner - * of the handle-controlled element, changing size - * as necessary. - * @memberof platform/features/layout.LineHandle# - */ - y: function (value) { - if (arguments.length > 0) { - // Ensure we stay in view - value = Math.max(value, 0); - // Make sure end points will still be different - if (element[xOther] !== element[xProperty] || - element[yOther] !== value) { - element[yProperty] = value; - } - } - return element[yProperty]; - } - }; + this.element = element; + this.xProperty = xProperty; + this.yProperty = yProperty; + this.xOther = xOther; + this.yOther = yOther; } + LineHandle.prototype.x = function (value) { + var element = this.element, + xProperty = this.xProperty, + yProperty = this.yProperty, + xOther = this.xOther, + yOther = this.yOther; + + if (arguments.length > 0) { + // Ensure we stay in view + value = Math.max(value, 0); + // Make sure end points will still be different + if (element[yOther] !== element[yProperty] || + element[xOther] !== value) { + element[xProperty] = value; + } + } + return element[xProperty]; + }; + + LineHandle.prototype.y = function (value) { + var element = this.element, + xProperty = this.xProperty, + yProperty = this.yProperty, + xOther = this.xOther, + yOther = this.yOther; + + if (arguments.length > 0) { + // Ensure we stay in view + value = Math.max(value, 0); + // Make sure end points will still be different + if (element[xOther] !== element[xProperty] || + element[yOther] !== value) { + element[yProperty] = value; + } + } + return element[yProperty]; + }; + return LineHandle; } diff --git a/platform/features/layout/src/elements/LineProxy.js b/platform/features/layout/src/elements/LineProxy.js index 0051b1d3c1..44cf282993 100644 --- a/platform/features/layout/src/elements/LineProxy.js +++ b/platform/features/layout/src/elements/LineProxy.js @@ -35,6 +35,7 @@ define( * configuration * @param index the element's index within its array * @param {Array} elements the full array of elements + * @augments {platform/features/layout.ElementProxy} */ function LineProxy(element, index, elements) { var proxy = new ElementProxy(element, index, elements), diff --git a/platform/features/layout/src/elements/ResizeHandle.js b/platform/features/layout/src/elements/ResizeHandle.js index c8fe59682c..757bb6218e 100644 --- a/platform/features/layout/src/elements/ResizeHandle.js +++ b/platform/features/layout/src/elements/ResizeHandle.js @@ -25,6 +25,11 @@ define( function () { 'use strict'; + /** + * @interface platform/features/layout.ElementHandle + * @private + */ + /** * Handle for changing width/height properties of an element. * This is used to support drag handles for different @@ -33,44 +38,35 @@ define( * @constructor */ function ResizeHandle(element, minWidth, minHeight) { - // Ensure reasonable defaults - minWidth = minWidth || 0; - minHeight = minHeight || 0; + this.element = element; - return { - /** - * Get/set the x position of the lower-right corner - * of the handle-controlled element, changing size - * as necessary. - * @memberof platform/features/layout.ResizeHandle# - */ - x: function (value) { - if (arguments.length > 0) { - element.width = Math.max( - minWidth, - value - element.x - ); - } - return element.x + element.width; - }, - /** - * Get/set the y position of the lower-right corner - * of the handle-controlled element, changing size - * as necessary. - * @memberof platform/features/layout.ResizeHandle# - */ - y: function (value) { - if (arguments.length > 0) { - element.height = Math.max( - minHeight, - value - element.y - ); - } - return element.y + element.height; - } - }; + // Ensure reasonable defaults + this.minWidth = minWidth || 0; + this.minHeight = minHeight || 0; } + ResizeHandle.prototype.x = function (value) { + var element = this.element; + if (arguments.length > 0) { + element.width = Math.max( + this.minWidth, + value - element.x + ); + } + return element.x + element.width; + }; + + ResizeHandle.prototype.y = function (value) { + var element = this.element; + if (arguments.length > 0) { + element.height = Math.max( + this.minHeight, + value - element.y + ); + } + return element.y + element.height; + }; + return ResizeHandle; } diff --git a/platform/features/layout/src/elements/TelemetryProxy.js b/platform/features/layout/src/elements/TelemetryProxy.js index 058048eca8..dbb7044c51 100644 --- a/platform/features/layout/src/elements/TelemetryProxy.js +++ b/platform/features/layout/src/elements/TelemetryProxy.js @@ -41,6 +41,7 @@ define( * configuration * @param index the element's index within its array * @param {Array} elements the full array of elements + * @augments {platform/features/layout.ElementProxy} */ function TelemetryProxy(element, index, elements) { var proxy = new TextProxy(element, index, elements); diff --git a/platform/features/layout/src/elements/TextProxy.js b/platform/features/layout/src/elements/TextProxy.js index d3ff832833..c5b5247c4c 100644 --- a/platform/features/layout/src/elements/TextProxy.js +++ b/platform/features/layout/src/elements/TextProxy.js @@ -38,6 +38,7 @@ define( * configuration * @param index the element's index within its array * @param {Array} elements the full array of elements + * @augments {platform/features/layout.ElementProxy} */ function TextProxy(element, index, elements) { var proxy = new BoxProxy(element, index, elements); From 3492cd394290439d3d319a249e59690c2408ae51 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 12 Aug 2015 13:57:17 -0700 Subject: [PATCH 53/84] [Code Style] Fix bug introduced by refactor Do some extra checking, since capabilities may have properties which are note methods. WTD-1482. --- .../edit/src/capabilities/EditableLookupCapability.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js b/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js index 727a569a15..c92495dc3f 100644 --- a/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js +++ b/platform/commonUI/edit/src/capabilities/EditableLookupCapability.js @@ -78,7 +78,7 @@ define( // Wrap a returned value (see above); if it's a promise, wrap // the resolved value. function wrapResult(result) { - return result.then ? // promise-like + return (result && result.then) ? // promise-like result.then(makeEditable) : makeEditable(result); } @@ -107,8 +107,10 @@ define( // Wrap a method of this capability function wrapMethod(fn) { - capability[fn] = - (idempotent ? oneTimeFunction : wrapFunction)(fn); + if (typeof capability[fn] === 'function') { + capability[fn] = + (idempotent ? oneTimeFunction : wrapFunction)(fn); + } } // Wrap all methods; return only editable domain objects. From 175490e1f76a382264bf3734908c29ac19770e4e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 12 Aug 2015 14:32:05 -0700 Subject: [PATCH 54/84] [Code Style] Use prototypes in Web Page bundle WTD-1482 --- .../pages/src/EmbeddedPageController.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/platform/features/pages/src/EmbeddedPageController.js b/platform/features/pages/src/EmbeddedPageController.js index f7720bc62c..0ebe5dfa23 100644 --- a/platform/features/pages/src/EmbeddedPageController.js +++ b/platform/features/pages/src/EmbeddedPageController.js @@ -38,17 +38,19 @@ define( * @memberof platform/features/pages */ function EmbeddedPageController($sce) { - return { - /** - * Alias of `$sce.trustAsResourceUrl`. - * @memberof platform/features/pages.EmbeddedPageController# - */ - trust: function (url) { - return $sce.trustAsResourceUrl(url); - } - }; + this.$sce = $sce; } + /** + * Alias of `$sce.trustAsResourceUrl`. + * @param {string} url the URL to trust + * @returns {string} the trusted URL + */ + EmbeddedPageController.prototype.trust = function (url) { + return this.$sce.trustAsResourceUrl(url); + }; + + return EmbeddedPageController; } From 18bc7d3637e8e1ca3c4532484666893991cffda4 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 12 Aug 2015 14:49:03 -0700 Subject: [PATCH 55/84] [Code Style] Begin using prototypes in Plot bundle WTD-1482 --- .../features/plot/src/elements/PlotAxis.js | 36 +- .../plot/src/elements/PlotLimitTracker.js | 50 +- .../features/plot/src/elements/PlotLine.js | 110 +++-- .../plot/src/elements/PlotLineBuffer.js | 455 +++++++++--------- .../plot/src/elements/PlotPanZoomStack.js | 208 ++++---- 5 files changed, 419 insertions(+), 440 deletions(-) diff --git a/platform/features/plot/src/elements/PlotAxis.js b/platform/features/plot/src/elements/PlotAxis.js index 2066b9c1bd..25795fd347 100644 --- a/platform/features/plot/src/elements/PlotAxis.js +++ b/platform/features/plot/src/elements/PlotAxis.js @@ -62,26 +62,22 @@ define( (metadatas || []).forEach(buildOptionsForMetadata); - // Plot axis will be used directly from the Angular - // template, so expose properties directly to facilitate - // two-way data binding (for drop-down menus) - return { - /** - * The set of options applicable for this axis; - * an array of objects, where each object contains a - * "key" field and a "name" field (for machine- and - * human-readable names respectively) - * @memberof platform/features/plot.PlotAxis# - */ - options: options, - /** - * The currently chosen option for this axis. An - * initial value is provided; this will be updated - * directly form the plot template. - * @memberof platform/features/plot.PlotAxis# - */ - active: options[0] || defaultValue - }; + /** + * The currently chosen option for this axis. An + * initial value is provided; this will be updated + * directly form the plot template. + * @memberof platform/features/plot.PlotAxis# + */ + this.active = options[0] || defaultValue; + + /** + * The set of options applicable for this axis; + * an array of objects, where each object contains a + * "key" field and a "name" field (for machine- and + * human-readable names respectively) + * @memberof platform/features/plot.PlotAxis# + */ + this.options = options; } return PlotAxis; diff --git a/platform/features/plot/src/elements/PlotLimitTracker.js b/platform/features/plot/src/elements/PlotLimitTracker.js index 9993ff2144..9309c50f32 100644 --- a/platform/features/plot/src/elements/PlotLimitTracker.js +++ b/platform/features/plot/src/elements/PlotLimitTracker.js @@ -21,26 +21,32 @@ *****************************************************************************/ /*global define,Float32Array*/ -/** - * Prepares data to be rendered in a GL Plot. Handles - * the conversion from data API to displayable buffers. - */ define( [], function () { 'use strict'; - var MAX_POINTS = 86400, - INITIAL_SIZE = 675; // 1/128 of MAX_POINTS - /** + * Tracks the limit state of telemetry objects being plotted. * @memberof platform/features/plot * @constructor - * @param {TelemetryHandle} handle the handle to telemetry access + * @param {platform/telemetry.TelemetryHandle} handle the handle + * to telemetry access * @param {string} range the key to use when looking up range values */ function PlotLimitTracker(handle, range) { - var legendClasses = {}; + this.handle = handle; + this.range = range; + this.legendClasses = {}; + } + + /** + * Update limit states to reflect the latest data. + */ + PlotLimitTracker.prototype.update = function () { + var legendClasses = {}, + range = this.range, + handle = this.handle; function updateLimit(telemetryObject) { var limit = telemetryObject.getCapability('limit'), @@ -52,17 +58,21 @@ define( } } - return { - update: function () { - legendClasses = {}; - handle.getTelemetryObjects().forEach(updateLimit); - }, - getLegendClass: function (domainObject) { - var id = domainObject && domainObject.getId(); - return id && legendClasses[id]; - } - }; - } + handle.getTelemetryObjects().forEach(updateLimit); + + this.legendClasses = legendClasses; + }; + + /** + * Get the CSS class associated with any limit violations for this + * telemetry object. + * @param {DomainObject} domainObject the telemetry object to check + * @returns {string} the CSS class name, if any + */ + PlotLimitTracker.prototype.getLegendClass = function (domainObject) { + var id = domainObject && domainObject.getId(); + return id && this.legendClasses[id]; + }; return PlotLimitTracker; diff --git a/platform/features/plot/src/elements/PlotLine.js b/platform/features/plot/src/elements/PlotLine.js index ae9b3b56b3..abb23c8770 100644 --- a/platform/features/plot/src/elements/PlotLine.js +++ b/platform/features/plot/src/elements/PlotLine.js @@ -33,6 +33,47 @@ define( * @constructor */ function PlotLine(buffer) { + this.buffer = buffer; + } + + /** + * Add a point to this plot line. + * @param {number} domainValue the domain value + * @param {number} rangeValue the range value + */ + PlotLine.prototype.addPoint = function (domainValue, rangeValue) { + var buffer = this.buffer, + index; + + // Make sure we got real/useful values here... + if (domainValue !== undefined && rangeValue !== undefined) { + index = buffer.findInsertionIndex(domainValue); + + // Already in the buffer? Skip insertion + if (index < 0) { + return; + } + + // Insert the point + if (!buffer.insertPoint(domainValue, rangeValue, index)) { + // If insertion failed, trim from the beginning... + buffer.trim(1); + // ...and try again. + buffer.insertPoint(domainValue, rangeValue, index); + } + } + }; + + /** + * Add a series of telemetry data to this plot line. + * @param {TelemetrySeries} series the data series + * @param {string} [domain] the key indicating which domain + * to use when looking up data from this series + * @param {string} [range] the key indicating which range + * to use when looking up data from this series + */ + PlotLine.prototype.addSeries = function (series, domain, range) { + var buffer = this.buffer; // Insert a time-windowed data series into the buffer function insertSeriesWindow(seriesWindow) { @@ -60,62 +101,19 @@ define( } } - function createWindow(series, domain, range) { - return new PlotSeriesWindow( - series, - domain, - range, - 0, - series.getPointCount() - ); - } - - return { - /** - * Add a point to this plot line. - * @param {number} domainValue the domain value - * @param {number} rangeValue the range value - * @memberof platform/features/plot.PlotLine - */ - addPoint: function (domainValue, rangeValue) { - var index; - // Make sure we got real/useful values here... - if (domainValue !== undefined && rangeValue !== undefined) { - index = buffer.findInsertionIndex(domainValue); - - // Already in the buffer? Skip insertion - if (index < 0) { - return; - } - - // Insert the point - if (!buffer.insertPoint(domainValue, rangeValue, index)) { - // If insertion failed, trim from the beginning... - buffer.trim(1); - // ...and try again. - buffer.insertPoint(domainValue, rangeValue, index); - } - } - }, - /** - * Add a series of telemetry data to this plot line. - * @param {TelemetrySeries} series the data series - * @param {string} [domain] the key indicating which domain - * to use when looking up data from this series - * @param {string} [range] the key indicating which range - * to use when looking up data from this series - * @memberof platform/features/plot.PlotLine - */ - addSeries: function (series, domain, range) { - // Should try to add via insertion if a - // clear insertion point is available; - // if not, should split and add each half. - // Insertion operation also needs to factor out - // redundant timestamps, for overlapping data - insertSeriesWindow(createWindow(series, domain, range)); - } - }; - } + // Should try to add via insertion if a + // clear insertion point is available; + // if not, should split and add each half. + // Insertion operation also needs to factor out + // redundant timestamps, for overlapping data + insertSeriesWindow(new PlotSeriesWindow( + series, + domain, + range, + 0, + series.getPointCount() + )); + }; return PlotLine; } diff --git a/platform/features/plot/src/elements/PlotLineBuffer.js b/platform/features/plot/src/elements/PlotLineBuffer.js index 5cf52ad49d..af0bbe553b 100644 --- a/platform/features/plot/src/elements/PlotLineBuffer.js +++ b/platform/features/plot/src/elements/PlotLineBuffer.js @@ -35,236 +35,235 @@ define( * @constructor */ function PlotLineBuffer(domainOffset, initialSize, maxSize) { - var buffer = new Float32Array(initialSize * 2), - rangeExtrema = [ Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ], - length = 0; - - // Binary search for an insertion index - function binSearch(value, min, max) { - var mid = Math.floor((min + max) / 2), - found = buffer[mid * 2]; - - // On collisions, insert at same index - if (found === value) { - return mid; - } - - // Otherwise, if we're down to a single index, - // we've found our insertion point - if (min >= max) { - // Compare the found timestamp with the search - // value to decide if we'll insert after or before. - return min + ((found < value) ? 1 : 0); - } - - // Finally, do the recursive step - if (found < value) { - return binSearch(value, mid + 1, max); - } else { - return binSearch(value, min, mid - 1); - } - } - - // Increase the size of the buffer - function doubleBufferSize() { - var sz = Math.min(maxSize * 2, buffer.length * 2), - canDouble = sz > buffer.length, - doubled = canDouble && new Float32Array(sz); - - if (canDouble) { - doubled.set(buffer); // Copy contents of original - buffer = doubled; - } - - return canDouble; - } - - // Decrease the size of the buffer - function halveBufferSize() { - var sz = Math.max(initialSize * 2, buffer.length / 2), - canHalve = sz < buffer.length; - - if (canHalve) { - buffer = new Float32Array(buffer.subarray(0, sz)); - } - - return canHalve; - } - - // Set a value in the buffer - function setValue(index, domainValue, rangeValue) { - buffer[index * 2] = domainValue - domainOffset; - buffer[index * 2 + 1] = rangeValue; - // Track min/max of range values (min/max for - // domain values can be read directly from buffer) - rangeExtrema[0] = Math.min(rangeExtrema[0], rangeValue); - rangeExtrema[1] = Math.max(rangeExtrema[1], rangeValue); - } - - return { - /** - * Get the WebGL-displayable buffer of points to plot. - * @returns {Float32Array} displayable buffer for this line - * @memberof platform/features/plot.PlotLineBuffer# - */ - getBuffer: function () { - return buffer; - }, - /** - * Get the number of points stored in this buffer. - * @returns {number} the number of points stored - * @memberof platform/features/plot.PlotLineBuffer# - */ - getLength: function () { - return length; - }, - /** - * Get the min/max range values that are currently in this - * buffer. Unlike range extrema, these will change as the - * buffer gets trimmed. - * @returns {number[]} min, max domain values - * @memberof platform/features/plot.PlotLineBuffer# - */ - getDomainExtrema: function () { - // Since these are ordered in the buffer, assume - // these are the values at the first and last index - return [ - buffer[0] + domainOffset, - buffer[length * 2 - 2] + domainOffset - ]; - }, - /** - * Get the min/max range values that have been observed for this - * buffer. Note that these values may have been trimmed out at - * some point. - * @returns {number[]} min, max range values - * @memberof platform/features/plot.PlotLineBuffer# - */ - getRangeExtrema: function () { - return rangeExtrema; - }, - /** - * Remove values from this buffer. - * Normally, values are removed from the start - * of the buffer; a truthy value in the second argument - * will cause values to be removed from the end. - * @param {number} count number of values to remove - * @param {boolean} [fromEnd] true if the most recent - * values should be removed - * @memberof platform/features/plot.PlotLineBuffer# - */ - trim: function (count, fromEnd) { - // If we're removing values from the start... - if (!fromEnd) { - // ...do so by shifting buffer contents over - buffer.set(buffer.subarray(2 * count)); - } - // Reduce used buffer size accordingly - length -= count; - // Finally, if less than half of the buffer is being - // used, free up some memory. - if (length < buffer.length / 4) { - halveBufferSize(); - } - }, - /** - * Insert data from the provided series at the specified - * index. If this would exceed the buffer's maximum capacity, - * this operation fails and the buffer is unchanged. - * @param {TelemetrySeries} series the series to insert - * @param {number} index the index at which to insert this - * series - * @returns {boolean} true if insertion succeeded; otherwise - * false - * @memberof platform/features/plot.PlotLineBuffer# - */ - insert: function (series, index) { - var sz = series.getPointCount(), - i; - - // Don't allow append after the end; that doesn't make sense - index = Math.min(index, length); - - // Resize if necessary - while (sz > ((buffer.length / 2) - length)) { - if (!doubleBufferSize()) { - // Can't make room for this, insertion fails - return false; - } - } - - // Shift data over if necessary - if (index < length) { - buffer.set( - buffer.subarray(index * 2, length * 2), - (index + sz) * 2 - ); - } - - // Insert data into the set - for (i = 0; i < sz; i += 1) { - setValue( - i + index, - series.getDomainValue(i), - series.getRangeValue(i) - ); - } - - // Increase the length - length += sz; - - // Indicate that insertion was successful - return true; - }, - /** - * Append a single data point. - * @memberof platform/features/plot.PlotLineBuffer# - */ - insertPoint: function (domainValue, rangeValue, index) { - // Don't allow - index = Math.min(length, index); - - // Ensure there is space for this point - if (length >= (buffer.length / 2)) { - if (!doubleBufferSize()) { - return false; - } - } - - // Put the data in the buffer - setValue(length, domainValue, rangeValue); - - // Update length - length += 1; - - // Indicate that this was successful - return true; - }, - /** - * Find an index for inserting data with this - * timestamp. The second argument indicates whether - * we are searching for insert-before or insert-after - * positions. - * Timestamps are meant to be unique, so if a collision - * occurs, this will return -1. - * @param {number} timestamp timestamp to insert - * @returns {number} the index for insertion (or -1) - * @memberof platform/features/plot.PlotLineBuffer# - */ - findInsertionIndex: function (timestamp) { - var value = timestamp - domainOffset; - - // Handle empty buffer case and check for an - // append opportunity (which is most common case for - // real-time data so is optimized-for) before falling - // back to a binary search for the insertion point. - return (length < 1) ? 0 : - (value > buffer[length * 2 - 2]) ? length : - binSearch(value, 0, length - 1); - } - }; + this.buffer = new Float32Array(initialSize * 2); + this.rangeExtrema = + [ Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY ]; + this.length = 0; + this.domainOffset = domainOffset; + this.initialSize = initialSize; + this.maxSize = maxSize; } + // Binary search for an insertion index + PlotLineBuffer.prototype.binSearch = function (value, min, max) { + var mid = Math.floor((min + max) / 2), + found = this.buffer[mid * 2]; + + // On collisions, insert at same index + if (found === value) { + return mid; + } + + // Otherwise, if we're down to a single index, + // we've found our insertion point + if (min >= max) { + // Compare the found timestamp with the search + // value to decide if we'll insert after or before. + return min + ((found < value) ? 1 : 0); + } + + // Finally, do the recursive step + if (found < value) { + return this.binSearch(value, mid + 1, max); + } else { + return this.binSearch(value, min, mid - 1); + } + }; + + // Increase the size of the buffer + PlotLineBuffer.prototype.doubleBufferSize = function () { + var sz = Math.min(this.maxSize * 2, this.buffer.length * 2), + canDouble = sz > this.buffer.length, + doubled = canDouble && new Float32Array(sz); + + if (canDouble) { + doubled.set(this.buffer); // Copy contents of original + this.buffer = doubled; + } + + return canDouble; + }; + + // Decrease the size of the buffer + PlotLineBuffer.prototype.halveBufferSize = function () { + var sz = Math.max(this.initialSize * 2, this.buffer.length / 2), + canHalve = sz < this.buffer.length; + + if (canHalve) { + this.buffer = new Float32Array(this.buffer.subarray(0, sz)); + } + + return canHalve; + }; + + // Set a value in the buffer + PlotLineBuffer.prototype.setValue = function (index, domainValue, rangeValue) { + this.buffer[index * 2] = domainValue - this.domainOffset; + this.buffer[index * 2 + 1] = rangeValue; + // Track min/max of range values (min/max for + // domain values can be read directly from buffer) + this.rangeExtrema[0] = Math.min(this.rangeExtrema[0], rangeValue); + this.rangeExtrema[1] = Math.max(this.rangeExtrema[1], rangeValue); + }; + + /** + * Get the WebGL-displayable buffer of points to plot. + * @returns {Float32Array} displayable buffer for this line + */ + PlotLineBuffer.prototype.getBuffer = function () { + return this.buffer; + }; + + /** + * Get the number of points stored in this buffer. + * @returns {number} the number of points stored + */ + PlotLineBuffer.prototype.getLength = function () { + return this.length; + }; + + /** + * Get the min/max range values that are currently in this + * buffer. Unlike range extrema, these will change as the + * buffer gets trimmed. + * @returns {number[]} min, max domain values + */ + PlotLineBuffer.prototype.getDomainExtrema = function () { + // Since these are ordered in the buffer, assume + // these are the values at the first and last index + return [ + this.buffer[0] + this.domainOffset, + this.buffer[this.length * 2 - 2] + this.domainOffset + ]; + }; + + /** + * Get the min/max range values that have been observed for this + * buffer. Note that these values may have been trimmed out at + * some point. + * @returns {number[]} min, max range values + */ + PlotLineBuffer.prototype.getRangeExtrema = function () { + return this.rangeExtrema; + }; + + /** + * Remove values from this buffer. + * Normally, values are removed from the start + * of the buffer; a truthy value in the second argument + * will cause values to be removed from the end. + * @param {number} count number of values to remove + * @param {boolean} [fromEnd] true if the most recent + * values should be removed + */ + PlotLineBuffer.prototype.trim = function (count, fromEnd) { + // If we're removing values from the start... + if (!fromEnd) { + // ...do so by shifting buffer contents over + this.buffer.set(this.buffer.subarray(2 * count)); + } + // Reduce used buffer size accordingly + this.length -= count; + // Finally, if less than half of the buffer is being + // used, free up some memory. + if (this.length < this.buffer.length / 4) { + this.halveBufferSize(); + } + }; + + /** + * Insert data from the provided series at the specified + * index. If this would exceed the buffer's maximum capacity, + * this operation fails and the buffer is unchanged. + * @param {TelemetrySeries} series the series to insert + * @param {number} index the index at which to insert this + * series + * @returns {boolean} true if insertion succeeded; otherwise + * false + */ + PlotLineBuffer.prototype.insert = function (series, index) { + var sz = series.getPointCount(), + i; + + // Don't allow append after the end; that doesn't make sense + index = Math.min(index, this.length); + + // Resize if necessary + while (sz > ((this.buffer.length / 2) - this.length)) { + if (!this.doubleBufferSize()) { + // Can't make room for this, insertion fails + return false; + } + } + + // Shift data over if necessary + if (index < this.length) { + this.buffer.set( + this.buffer.subarray(index * 2, this.length * 2), + (index + sz) * 2 + ); + } + + // Insert data into the set + for (i = 0; i < sz; i += 1) { + this.setValue( + i + index, + series.getDomainValue(i), + series.getRangeValue(i) + ); + } + + // Increase the length + this.length += sz; + + // Indicate that insertion was successful + return true; + }; + + /** + * Append a single data point. + * @memberof platform/features/plot.PlotLineBuffer# + */ + PlotLineBuffer.prototype.insertPoint = function (domainValue, rangeValue) { + // Ensure there is space for this point + if (this.length >= (this.buffer.length / 2)) { + if (!this.doubleBufferSize()) { + return false; + } + } + + // Put the data in the buffer + this.setValue(this.length, domainValue, rangeValue); + + // Update length + this.length += 1; + + // Indicate that this was successful + return true; + }; + + /** + * Find an index for inserting data with this + * timestamp. The second argument indicates whether + * we are searching for insert-before or insert-after + * positions. + * Timestamps are meant to be unique, so if a collision + * occurs, this will return -1. + * @param {number} timestamp timestamp to insert + * @returns {number} the index for insertion (or -1) + */ + PlotLineBuffer.prototype.findInsertionIndex = function (timestamp) { + var value = timestamp - this.domainOffset; + + // Handle empty buffer case and check for an + // append opportunity (which is most common case for + // real-time data so is optimized-for) before falling + // back to a binary search for the insertion point. + return (this.length < 1) ? 0 : + (value > this.buffer[this.length * 2 - 2]) ? this.length : + this.binSearch(value, 0, this.length - 1); + }; + return PlotLineBuffer; } ); diff --git a/platform/features/plot/src/elements/PlotPanZoomStack.js b/platform/features/plot/src/elements/PlotPanZoomStack.js index 66e3593488..d31d53c128 100644 --- a/platform/features/plot/src/elements/PlotPanZoomStack.js +++ b/platform/features/plot/src/elements/PlotPanZoomStack.js @@ -44,124 +44,100 @@ define( */ function PlotPanZoomStack(origin, dimensions) { // Use constructor parameters as the stack's initial state - var stack = [{ origin: origin, dimensions: dimensions }]; - - // Various functions which follow are simply wrappers for - // normal stack-like array methods, with the exception that - // they prevent undesired modification and enforce that this - // stack must remain non-empty. - // See JSDoc for specific methods below for more detail. - function getDepth() { - return stack.length; - } - - function pushPanZoom(origin, dimensions) { - stack.push({ origin: origin, dimensions: dimensions }); - } - - function popPanZoom() { - if (stack.length > 1) { - stack.pop(); - } - } - - function clearPanZoom() { - stack = [stack[0]]; - } - - function setBasePanZoom(origin, dimensions) { - stack[0] = { origin: origin, dimensions: dimensions }; - } - - function getPanZoom() { - return stack[stack.length - 1]; - } - - function getOrigin() { - return getPanZoom().origin; - } - - function getDimensions() { - return getPanZoom().dimensions; - } - - return { - /** - * Get the current stack depth; that is, the number - * of items on the stack. A depth of one means that no - * panning or zooming relative to the base value has - * been applied. - * @returns {number} the depth of the stack - * @memberof platform/features/plot.PlotPanZoomStack# - */ - getDepth: getDepth, - - /** - * Push a new pan-zoom state onto the stack; this will - * become the active pan-zoom state. - * @param {number[]} origin the new origin - * @param {number[]} dimensions the new dimensions - * @memberof platform/features/plot.PlotPanZoomStack# - */ - pushPanZoom: pushPanZoom, - - /** - * Pop a pan-zoom state from the stack. Whatever pan-zoom - * state was previously present will become current. - * If called when there is only one pan-zoom state on the - * stack, this acts as a no-op (that is, the lowest - * pan-zoom state on the stack cannot be popped, to ensure - * that some pan-zoom state is always available.) - * @memberof platform/features/plot.PlotPanZoomStack# - */ - popPanZoom: popPanZoom, - - /** - * Set the base pan-zoom state; that is, the state at the - * bottom of the stack. This allows the "unzoomed" state of - * a plot to be updated (e.g. as new data comes in) without - * interfering with the user's chosen zoom level. - * @param {number[]} origin the base origin - * @param {number[]} dimensions the base dimensions - * @memberof platform/features/plot.PlotPanZoomStack# - */ - setBasePanZoom: setBasePanZoom, - - /** - * Clear the pan-zoom stack down to its bottom element; - * in effect, pop all elements but the last, e.g. to remove - * any temporary user modifications to pan-zoom state. - * @memberof platform/features/plot.PlotPanZoomStack# - */ - clearPanZoom: clearPanZoom, - - /** - * Get the current pan-zoom state (the state at the top - * of the stack), expressed as an object with "origin" and - * "dimensions" fields. - * @returns {object} the current pan-zoom state - * @memberof platform/features/plot.PlotPanZoomStack# - */ - getPanZoom: getPanZoom, - - /** - * Get the current origin, as represented on the top of the - * stack. - * @returns {number[]} the current plot origin - * @memberof platform/features/plot.PlotPanZoomStack# - */ - getOrigin: getOrigin, - - /** - * Get the current dimensions, as represented on the top of - * the stack. - * @returns {number[]} the current plot dimensions - * @memberof platform/features/plot.PlotPanZoomStack# - */ - getDimensions: getDimensions - }; + this.stack = [{ origin: origin, dimensions: dimensions }]; } + // Various functions which follow are simply wrappers for + // normal stack-like array methods, with the exception that + // they prevent undesired modification and enforce that this + // stack must remain non-empty. + // See JSDoc for specific methods below for more detail. + + /** + * Get the current stack depth; that is, the number + * of items on the stack. A depth of one means that no + * panning or zooming relative to the base value has + * been applied. + * @returns {number} the depth of the stack + */ + PlotPanZoomStack.prototype.getDepth = function getDepth() { + return this.stack.length; + }; + + /** + * Push a new pan-zoom state onto the stack; this will + * become the active pan-zoom state. + * @param {number[]} origin the new origin + * @param {number[]} dimensions the new dimensions + */ + PlotPanZoomStack.prototype.pushPanZoom = function (origin, dimensions) { + this.stack.push({ origin: origin, dimensions: dimensions }); + }; + + /** + * Pop a pan-zoom state from the stack. Whatever pan-zoom + * state was previously present will become current. + * If called when there is only one pan-zoom state on the + * stack, this acts as a no-op (that is, the lowest + * pan-zoom state on the stack cannot be popped, to ensure + * that some pan-zoom state is always available.) + */ + PlotPanZoomStack.prototype.popPanZoom = function popPanZoom() { + if (stack.length > 1) { + this.stack.pop(); + } + }; + + /** + * Set the base pan-zoom state; that is, the state at the + * bottom of the stack. This allows the "unzoomed" state of + * a plot to be updated (e.g. as new data comes in) without + * interfering with the user's chosen zoom level. + * @param {number[]} origin the base origin + * @param {number[]} dimensions the base dimensions + * @memberof platform/features/plot.PlotPanZoomStack# + */ + PlotPanZoomStack.prototype.setBasePanZoom = function (origin, dimensions) { + this.stack[0] = { origin: origin, dimensions: dimensions }; + }; + + /** + * Clear the pan-zoom stack down to its bottom element; + * in effect, pop all elements but the last, e.g. to remove + * any temporary user modifications to pan-zoom state. + */ + PlotPanZoomStack.prototype.clearPanZoom = function clearPanZoom() { + this.stack = [this.stack[0]]; + }; + + /** + * Get the current pan-zoom state (the state at the top + * of the stack), expressed as an object with "origin" and + * "dimensions" fields. + * @returns {object} the current pan-zoom state + */ + PlotPanZoomStack.prototype.getPanZoom = function getPanZoom() { + return this.stack[this.stack.length - 1]; + }; + + /** + * Get the current origin, as represented on the top of the + * stack. + * @returns {number[]} the current plot origin + */ + PlotPanZoomStack.prototype.getOrigin = function getOrigin() { + return this.getPanZoom().origin; + }; + + /** + * Get the current dimensions, as represented on the top of + * the stack. + * @returns {number[]} the current plot dimensions + */ + PlotPanZoomStack.prototype.getDimensions = function getDimensions() { + return this.getPanZoom().dimensions; + }; + return PlotPanZoomStack; } ); From aefad6fdd35a9e32077157a0f7c3bf6607195e48 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Wed, 12 Aug 2015 16:12:44 -0700 Subject: [PATCH 56/84] [Code Style] Continue refactor of Plot bundle Continue refactoring Plot bundle to use prototypes, WTD-1482 --- .../plot/src/elements/PlotPanZoomStack.js | 2 +- .../src/elements/PlotPanZoomStackGroup.js | 185 +++--- .../plot/src/elements/PlotPosition.js | 64 +- .../plot/src/elements/PlotPreparer.js | 119 ++-- .../plot/src/elements/PlotSeriesWindow.js | 74 ++- .../plot/src/elements/PlotTickGenerator.js | 92 ++- .../features/plot/src/elements/PlotUpdater.js | 552 +++++++++--------- 7 files changed, 531 insertions(+), 557 deletions(-) diff --git a/platform/features/plot/src/elements/PlotPanZoomStack.js b/platform/features/plot/src/elements/PlotPanZoomStack.js index d31d53c128..1afb903056 100644 --- a/platform/features/plot/src/elements/PlotPanZoomStack.js +++ b/platform/features/plot/src/elements/PlotPanZoomStack.js @@ -83,7 +83,7 @@ define( * that some pan-zoom state is always available.) */ PlotPanZoomStack.prototype.popPanZoom = function popPanZoom() { - if (stack.length > 1) { + if (this.stack.length > 1) { this.stack.pop(); } }; diff --git a/platform/features/plot/src/elements/PlotPanZoomStackGroup.js b/platform/features/plot/src/elements/PlotPanZoomStackGroup.js index ccb3ae3579..3746958ecb 100644 --- a/platform/features/plot/src/elements/PlotPanZoomStackGroup.js +++ b/platform/features/plot/src/elements/PlotPanZoomStackGroup.js @@ -38,15 +38,13 @@ define( * group */ function PlotPanZoomStackGroup(count) { - var stacks = [], - decoratedStacks = [], - i; + var self = this; // Push a pan-zoom state; the index argument identifies // which stack originated the request (all other stacks // will ignore the range part of the change.) function pushPanZoom(origin, dimensions, index) { - stacks.forEach(function (stack, i) { + self.stacks.forEach(function (stack, i) { if (i === index) { // Do a normal push for the specified stack stack.pushPanZoom(origin, dimensions); @@ -61,26 +59,6 @@ define( }); } - // Pop one pan-zoom state from all stacks - function popPanZoom() { - stacks.forEach(function (stack) { - stack.popPanZoom(); - }); - } - - // Set the base pan-zoom state for all stacks - function setBasePanZoom(origin, dimensions) { - stacks.forEach(function (stack) { - stack.setBasePanZoom(origin, dimensions); - }); - } - - // Clear the pan-zoom state of all stacks - function clearPanZoom() { - stacks.forEach(function (stack) { - stack.clearPanZoom(); - }); - } // Decorate a pan-zoom stack; returns an object with // the same interface, but whose stack-mutation methods @@ -92,88 +70,101 @@ define( result.pushPanZoom = function (origin, dimensions) { pushPanZoom(origin, dimensions, index); }; - result.setBasePanZoom = setBasePanZoom; - result.popPanZoom = popPanZoom; - result.clearPanZoom = clearPanZoom; + result.setBasePanZoom = function () { + self.setBasePanZoom.apply(self, arguments); + }; + result.popPanZoom = function () { + self.popPanZoom.apply(self, arguments); + }; + result.clearPanZoom = function () { + self.clearPanZoom.apply(self, arguments); + }; return result; } // Create the stacks in this group ... - while (stacks.length < count) { - stacks.push(new PlotPanZoomStack([], [])); + this.stacks = []; + while (this.stacks.length < count) { + this.stacks.push(new PlotPanZoomStack([], [])); } // ... and their decorated-to-synchronize versions. - decoratedStacks = stacks.map(decorateStack); - - return { - /** - * Pop a pan-zoom state from all stacks in the group. - * If called when there is only one pan-zoom state on each - * stack, this acts as a no-op (that is, the lowest - * pan-zoom state on the stack cannot be popped, to ensure - * that some pan-zoom state is always available.) - * @memberof platform/features/plot.PlotPanZoomStackGroup# - */ - popPanZoom: popPanZoom, - - /** - * Set the base pan-zoom state for all stacks in this group. - * This changes the state at the bottom of each stack. - * This allows the "unzoomed" state of plots to be updated - * (e.g. as new data comes in) without - * interfering with the user's chosen pan/zoom states. - * @param {number[]} origin the base origin - * @param {number[]} dimensions the base dimensions - * @memberof platform/features/plot.PlotPanZoomStackGroup# - */ - setBasePanZoom: setBasePanZoom, - - /** - * Clear all pan-zoom stacks in this group down to - * their bottom element; in effect, pop all elements - * but the last, e.g. to remove any temporary user - * modifications to pan-zoom state. - * @memberof platform/features/plot.PlotPanZoomStackGroup# - */ - clearPanZoom: clearPanZoom, - /** - * Get the current stack depth; that is, the number - * of items on each stack in the group. - * A depth of one means that no - * panning or zooming relative to the base value has - * been applied. - * @returns {number} the depth of the stacks in this group - * @memberof platform/features/plot.PlotPanZoomStackGroup# - */ - getDepth: function () { - // All stacks are kept in sync, so look up depth - // from the first one. - return stacks.length > 0 ? - stacks[0].getDepth() : 0; - }, - /** - * Get a specific pan-zoom stack in this group. - * Stacks are specified by index; this index must be less - * than the count provided at construction time, and must - * not be less than zero. - * The stack returned by this function will be synchronized - * to other stacks in this group; that is, mutating that - * stack directly will result in other stacks in this group - * undergoing similar updates to ensure that domain bounds - * remain the same. - * @param {number} index the index of the stack to get - * @returns {PlotPanZoomStack} the pan-zoom stack in the - * group identified by that index - * @memberof platform/features/plot.PlotPanZoomStackGroup# - */ - getPanZoomStack: function (index) { - return decoratedStacks[index]; - } - }; - + this.decoratedStacks = this.stacks.map(decorateStack); } + /** + * Pop a pan-zoom state from all stacks in the group. + * If called when there is only one pan-zoom state on each + * stack, this acts as a no-op (that is, the lowest + * pan-zoom state on the stack cannot be popped, to ensure + * that some pan-zoom state is always available.) + */ + PlotPanZoomStackGroup.prototype.popPanZoom = function () { + this.stacks.forEach(function (stack) { + stack.popPanZoom(); + }); + }; + + /** + * Set the base pan-zoom state for all stacks in this group. + * This changes the state at the bottom of each stack. + * This allows the "unzoomed" state of plots to be updated + * (e.g. as new data comes in) without + * interfering with the user's chosen pan/zoom states. + * @param {number[]} origin the base origin + * @param {number[]} dimensions the base dimensions + */ + PlotPanZoomStackGroup.prototype.setBasePanZoom = function (origin, dimensions) { + this.stacks.forEach(function (stack) { + stack.setBasePanZoom(origin, dimensions); + }); + }; + + /** + * Clear all pan-zoom stacks in this group down to + * their bottom element; in effect, pop all elements + * but the last, e.g. to remove any temporary user + * modifications to pan-zoom state. + */ + PlotPanZoomStackGroup.prototype.clearPanZoom = function () { + this.stacks.forEach(function (stack) { + stack.clearPanZoom(); + }); + }; + + /** + * Get the current stack depth; that is, the number + * of items on each stack in the group. + * A depth of one means that no + * panning or zooming relative to the base value has + * been applied. + * @returns {number} the depth of the stacks in this group + */ + PlotPanZoomStackGroup.prototype.getDepth = function () { + // All stacks are kept in sync, so look up depth + // from the first one. + return this.stacks.length > 0 ? + this.stacks[0].getDepth() : 0; + }; + + /** + * Get a specific pan-zoom stack in this group. + * Stacks are specified by index; this index must be less + * than the count provided at construction time, and must + * not be less than zero. + * The stack returned by this function will be synchronized + * to other stacks in this group; that is, mutating that + * stack directly will result in other stacks in this group + * undergoing similar updates to ensure that domain bounds + * remain the same. + * @param {number} index the index of the stack to get + * @returns {PlotPanZoomStack} the pan-zoom stack in the + * group identified by that index + */ + PlotPanZoomStackGroup.prototype.getPanZoomStack = function (index) { + return this.decoratedStacks[index]; + }; + return PlotPanZoomStackGroup; } ); diff --git a/platform/features/plot/src/elements/PlotPosition.js b/platform/features/plot/src/elements/PlotPosition.js index 30220f56f6..15444e68d5 100644 --- a/platform/features/plot/src/elements/PlotPosition.js +++ b/platform/features/plot/src/elements/PlotPosition.js @@ -48,8 +48,7 @@ define( function PlotPosition(x, y, width, height, panZoomStack) { var panZoom = panZoomStack.getPanZoom(), origin = panZoom.origin, - dimensions = panZoom.dimensions, - position; + dimensions = panZoom.dimensions; function convert(v, i) { return v * dimensions[i] + origin[i]; @@ -57,45 +56,42 @@ define( if (!dimensions || !origin) { // We need both dimensions and origin to compute a position - position = []; + this.position = []; } else { // Convert from pixel to domain-range space. // Note that range is reversed from the y-axis in pixel space //(positive range points up, positive pixel-y points down) - position = [ x / width, (height - y) / height ].map(convert); + this.position = + [ x / width, (height - y) / height ].map(convert); } - - return { - /** - * Get the domain value corresponding to this pixel position. - * @returns {number} the domain value - * @memberof platform/features/plot.PlotPosition# - */ - getDomain: function () { - return position[0]; - }, - /** - * Get the range value corresponding to this pixel position. - * @returns {number} the range value - * @memberof platform/features/plot.PlotPosition# - */ - getRange: function () { - return position[1]; - }, - /** - * Get the domain and values corresponding to this - * pixel position. - * @returns {number[]} an array containing the domain and - * the range value, in that order - * @memberof platform/features/plot.PlotPosition# - */ - getPosition: function () { - return position; - } - }; - } + /** + * Get the domain value corresponding to this pixel position. + * @returns {number} the domain value + */ + PlotPosition.prototype.getDomain = function () { + return this.position[0]; + }; + + /** + * Get the range value corresponding to this pixel position. + * @returns {number} the range value + */ + PlotPosition.prototype.getRange =function () { + return this.position[1]; + }; + + /** + * Get the domain and values corresponding to this + * pixel position. + * @returns {number[]} an array containing the domain and + * the range value, in that order + */ + PlotPosition.prototype.getPosition = function () { + return this.position; + }; + return PlotPosition; } ); diff --git a/platform/features/plot/src/elements/PlotPreparer.js b/platform/features/plot/src/elements/PlotPreparer.js index 87049c9198..a1ca0cc5b5 100644 --- a/platform/features/plot/src/elements/PlotPreparer.js +++ b/platform/features/plot/src/elements/PlotPreparer.js @@ -49,8 +49,7 @@ define( min = [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY], x, y, - domainOffset = Number.POSITIVE_INFINITY, - buffers; + domainOffset = Number.POSITIVE_INFINITY; // Remove any undefined data sets datas = (datas || []).filter(identity); @@ -85,65 +84,69 @@ define( } // Convert to Float32Array - buffers = vertices.map(function (v) { return new Float32Array(v); }); + this.buffers = vertices.map(function (v) { + return new Float32Array(v); + }); - return { - /** - * Get the dimensions which bound all data in the provided - * data sets. This is given as a two-element array where the - * first element is domain, and second is range. - * @returns {number[]} the dimensions which bound this data set - * @memberof platform/features/plot.PlotPreparer# - */ - getDimensions: function () { - return [max[0] - min[0], max[1] - min[1]]; - }, - /** - * Get the origin of this data set's boundary. - * This is given as a two-element array where the - * first element is domain, and second is range. - * The domain value here is not adjusted by the domain offset. - * @returns {number[]} the origin of this data set's boundary - * @memberof platform/features/plot.PlotPreparer# - */ - getOrigin: function () { - return min; - }, - /** - * Get the domain offset; this offset will have been subtracted - * from all domain values in all buffers returned by this - * preparer, in order to minimize loss-of-precision due to - * conversion to the 32-bit float format needed by WebGL. - * @returns {number} the domain offset - * @memberof platform/features/plot.PlotPreparer# - */ - getDomainOffset: function () { - return domainOffset; - }, - /** - * Get all renderable buffers for this data set. This will - * be returned as an array which can be correlated back to - * the provided telemetry data objects (from the constructor - * call) by index. - * - * Internally, these are flattened; each buffer contains a - * sequence of alternating domain and range values. - * - * All domain values in all buffers will have been adjusted - * from their original values by subtraction of the domain - * offset; this minimizes loss-of-precision resulting from - * the conversion to 32-bit floats, which may otherwise - * cause aliasing artifacts (particularly for timestamps) - * - * @returns {Float32Array[]} the buffers for these traces - * @memberof platform/features/plot.PlotPreparer# - */ - getBuffers: function () { - return buffers; - } - }; + this.min = min; + this.max = max; + this.domainOffset = domainOffset; } + /** + * Get the dimensions which bound all data in the provided + * data sets. This is given as a two-element array where the + * first element is domain, and second is range. + * @returns {number[]} the dimensions which bound this data set + */ + PlotPreparer.prototype.getDimensions = function () { + var max = this.max, min = this.min; + return [max[0] - min[0], max[1] - min[1]]; + }; + + /** + * Get the origin of this data set's boundary. + * This is given as a two-element array where the + * first element is domain, and second is range. + * The domain value here is not adjusted by the domain offset. + * @returns {number[]} the origin of this data set's boundary + */ + PlotPreparer.prototype.getOrigin = function () { + return this.min; + }; + + /** + * Get the domain offset; this offset will have been subtracted + * from all domain values in all buffers returned by this + * preparer, in order to minimize loss-of-precision due to + * conversion to the 32-bit float format needed by WebGL. + * @returns {number} the domain offset + */ + PlotPreparer.prototype.getDomainOffset = function () { + return this.domainOffset; + }; + + /** + * Get all renderable buffers for this data set. This will + * be returned as an array which can be correlated back to + * the provided telemetry data objects (from the constructor + * call) by index. + * + * Internally, these are flattened; each buffer contains a + * sequence of alternating domain and range values. + * + * All domain values in all buffers will have been adjusted + * from their original values by subtraction of the domain + * offset; this minimizes loss-of-precision resulting from + * the conversion to 32-bit floats, which may otherwise + * cause aliasing artifacts (particularly for timestamps) + * + * @returns {Float32Array[]} the buffers for these traces + */ + PlotPreparer.prototype.getBuffers = function () { + return this.buffers; + }; + return PlotPreparer; } diff --git a/platform/features/plot/src/elements/PlotSeriesWindow.js b/platform/features/plot/src/elements/PlotSeriesWindow.js index bff0710b34..4bf880a239 100644 --- a/platform/features/plot/src/elements/PlotSeriesWindow.js +++ b/platform/features/plot/src/elements/PlotSeriesWindow.js @@ -30,41 +30,53 @@ define( * insertion into a plot line. * @constructor * @memberof platform/features/plot + * @implements {TelemetrySeries} */ function PlotSeriesWindow(series, domain, range, start, end) { - return { - getPointCount: function () { - return end - start; - }, - getDomainValue: function (index) { - return series.getDomainValue(index + start, domain); - }, - getRangeValue: function (index) { - return series.getRangeValue(index + start, range); - }, - split: function () { - var mid = Math.floor((end + start) / 2); - return ((end - start) > 1) ? - [ - new PlotSeriesWindow( - series, - domain, - range, - start, - mid - ), - new PlotSeriesWindow( - series, - domain, - range, - mid, - end - ) - ] : []; - } - }; + this.series = series; + this.domain = domain; + this.range = range; + this.start = start; + this.end = end; } + PlotSeriesWindow.prototype.getPointCount = function () { + return this.end - this.start; + }; + + PlotSeriesWindow.prototype.getDomainValue = function (index) { + return this.series.getDomainValue(index + this.start, this.domain); + }; + + PlotSeriesWindow.prototype.getRangeValue = function (index) { + return this.series.getRangeValue(index + this.start, this.range); + }; + + /** + * Split this series into two series of equal (or nearly-equal) size. + * @returns {PlotSeriesWindow[]} two series + */ + PlotSeriesWindow.prototype.split = function () { + var mid = Math.floor((this.end + this.start) / 2); + return ((this.end - this.start) > 1) ? + [ + new PlotSeriesWindow( + this.series, + this.domain, + this.range, + this.start, + mid + ), + new PlotSeriesWindow( + this.series, + this.domain, + this.range, + mid, + this.end + ) + ] : []; + }; + return PlotSeriesWindow; } ); diff --git a/platform/features/plot/src/elements/PlotTickGenerator.js b/platform/features/plot/src/elements/PlotTickGenerator.js index 024338eb4d..af18050955 100644 --- a/platform/features/plot/src/elements/PlotTickGenerator.js +++ b/platform/features/plot/src/elements/PlotTickGenerator.js @@ -39,60 +39,56 @@ define( * domain and range values. */ function PlotTickGenerator(panZoomStack, formatter) { + this.panZoomStack = panZoomStack; + this.formatter = formatter; + } - // Generate ticks; interpolate from start up to - // start + span in count steps, using the provided - // formatter to represent each value. - function generateTicks(start, span, count, format) { - var step = span / (count - 1), - result = [], - i; + // Generate ticks; interpolate from start up to + // start + span in count steps, using the provided + // formatter to represent each value. + PlotTickGenerator.prototype.generateTicks = function (start, span, count, format) { + var step = span / (count - 1), + result = [], + i; - for (i = 0; i < count; i += 1) { - result.push({ - label: format(i * step + start) - }); - } - - return result; + for (i = 0; i < count; i += 1) { + result.push({ + label: format(i * step + start) + }); } + return result; + }; - return { - /** - * Generate tick marks for the domain axis. - * @param {number} count the number of ticks - * @returns {string[]} labels for those ticks - * @memberof platform/features/plot.PlotTickGenerator# - */ - generateDomainTicks: function (count) { - var panZoom = panZoomStack.getPanZoom(); - return generateTicks( - panZoom.origin[0], - panZoom.dimensions[0], - count, - formatter.formatDomainValue - ); - }, + /** + * Generate tick marks for the domain axis. + * @param {number} count the number of ticks + * @returns {string[]} labels for those ticks + */ + PlotTickGenerator.prototype.generateDomainTicks = function (count) { + var panZoom = this.panZoomStack.getPanZoom(); + return this.generateTicks( + panZoom.origin[0], + panZoom.dimensions[0], + count, + this.formatter.formatDomainValue + ); + }; - /** - * Generate tick marks for the range axis. - * @param {number} count the number of ticks - * @returns {string[]} labels for those ticks - * @memberof platform/features/plot.PlotTickGenerator# - */ - generateRangeTicks: function (count) { - var panZoom = panZoomStack.getPanZoom(); - return generateTicks( - panZoom.origin[1], - panZoom.dimensions[1], - count, - formatter.formatRangeValue - ); - } - }; - - } + /** + * Generate tick marks for the range axis. + * @param {number} count the number of ticks + * @returns {string[]} labels for those ticks + */ + PlotTickGenerator.prototype.generateRangeTicks = function (count) { + var panZoom = this.panZoomStack.getPanZoom(); + return this.generateTicks( + panZoom.origin[1], + panZoom.dimensions[1], + count, + this.formatter.formatRangeValue + ); + }; return PlotTickGenerator; } diff --git a/platform/features/plot/src/elements/PlotUpdater.js b/platform/features/plot/src/elements/PlotUpdater.js index d37112c243..851fa56096 100644 --- a/platform/features/plot/src/elements/PlotUpdater.js +++ b/platform/features/plot/src/elements/PlotUpdater.js @@ -21,10 +21,6 @@ *****************************************************************************/ /*global define,Float32Array*/ -/** - * Prepares data to be rendered in a GL Plot. Handles - * the conversion from data API to displayable buffers. - */ define( ['./PlotLine', './PlotLineBuffer'], function (PlotLine, PlotLineBuffer) { @@ -44,302 +40,282 @@ define( * @param {TelemetryHandle} handle the handle to telemetry access * @param {string} domain the key to use when looking up domain values * @param {string} range the key to use when looking up range values - * @param {number} maxDuration maximum plot duration to display + * @param {number} fixedDuration maximum plot duration to display * @param {number} maxPoints maximum number of points to display */ function PlotUpdater(handle, domain, range, fixedDuration, maxPoints) { - var ids = [], - lines = {}, - dimensions = [0, 0], - origin = [0, 0], - domainExtrema, - rangeExtrema, - buffers = {}, - bufferArray = [], - domainOffset; + this.handle = handle; + this.domain = domain; + this.range = range; + this.fixedDuration = fixedDuration; + this.maxPoints = maxPoints; - // Look up a domain object's id (for mapping, below) - function getId(domainObject) { - return domainObject.getId(); - } - - // Check if this set of ids matches the current set of ids - // (used to detect if line preparation can be skipped) - function idsMatch(nextIds) { - return ids.length === nextIds.length && - nextIds.every(function (id, index) { - return ids[index] === id; - }); - } - - // Prepare plot lines for this group of telemetry objects - function prepareLines(telemetryObjects) { - var nextIds = telemetryObjects.map(getId), - next = {}; - - // Detect if we already have everything we need prepared - if (idsMatch(nextIds)) { - // Nothing to prepare, move on - return; - } - - // Built up a set of ids. Note that we can only - // create plot lines after our domain offset has - // been determined. - if (domainOffset !== undefined) { - // Update list of ids in use - ids = nextIds; - - // Create buffers for these objects - bufferArray = ids.map(function (id) { - buffers[id] = buffers[id] || new PlotLineBuffer( - domainOffset, - INITIAL_SIZE, - maxPoints - ); - next[id] = lines[id] || new PlotLine(buffers[id]); - return buffers[id]; - }); - } - - // If there are no more lines, clear the domain offset - if (Object.keys(next).length < 1) { - domainOffset = undefined; - } - - // Update to the current set of lines - lines = next; - } - - - // Initialize the domain offset, based on these observed values - function initializeDomainOffset(values) { - domainOffset = - ((domainOffset === undefined) && (values.length > 0)) ? - (values.reduce(function (a, b) { - return (a || 0) + (b || 0); - }, 0) / values.length) : - domainOffset; - } - - // Used in the reduce step of updateExtrema - function reduceExtrema(a, b) { - return [ Math.min(a[0], b[0]), Math.max(a[1], b[1]) ]; - } - - // Convert a domain/range extrema to plot dimensions - function dimensionsOf(extrema) { - return extrema[1] - extrema[0]; - } - - // Convert a domain/range extrema to a plot origin - function originOf(extrema) { - return extrema[0]; - } - - // Expand range slightly so points near edges are visible - function expandRange() { - var padding = PADDING_RATIO * dimensions[1], - top; - padding = Math.max(padding, 1.0); - top = Math.ceil(origin[1] + dimensions[1] + padding / 2); - origin[1] = Math.floor(origin[1] - padding / 2); - dimensions[1] = top - origin[1]; - } - - // Update dimensions and origin based on extrema of plots - function updateBounds() { - if (bufferArray.length > 0) { - domainExtrema = bufferArray.map(function (lineBuffer) { - return lineBuffer.getDomainExtrema(); - }).reduce(reduceExtrema); - - rangeExtrema = bufferArray.map(function (lineBuffer) { - return lineBuffer.getRangeExtrema(); - }).reduce(reduceExtrema); - - // Calculate best-fit dimensions - dimensions = - [dimensionsOf(domainExtrema), dimensionsOf(rangeExtrema)]; - origin = [originOf(domainExtrema), originOf(rangeExtrema)]; - - // Enforce some minimum visible area - expandRange(); - - // ...then enforce a fixed duration if needed - if (fixedDuration !== undefined) { - origin[0] = origin[0] + dimensions[0] - fixedDuration; - dimensions[0] = fixedDuration; - } - } - } - - // Enforce maximum duration on all plot lines; not that - // domain extrema must be up-to-date for this to behave correctly. - function enforceDuration() { - var cutoff; - - function enforceDurationForBuffer(plotLineBuffer) { - var index = plotLineBuffer.findInsertionIndex(cutoff); - if (index > 0) { - // Leave one point untrimmed, such that line will - // continue off left edge of visible plot area. - plotLineBuffer.trim(index - 1); - } - } - - if (fixedDuration !== undefined && - domainExtrema !== undefined && - (domainExtrema[1] - domainExtrema[0] > fixedDuration)) { - cutoff = domainExtrema[1] - fixedDuration; - bufferArray.forEach(enforceDurationForBuffer); - updateBounds(); // Extrema may have changed now - } - } - - // Add latest data for this domain object - function addPointFor(domainObject) { - var line = lines[domainObject.getId()]; - if (line) { - line.addPoint( - handle.getDomainValue(domainObject, domain), - handle.getRangeValue(domainObject, range) - ); - } - } - - // Handle new telemetry data - function update() { - var objects = handle.getTelemetryObjects(); - - // Initialize domain offset if necessary - if (domainOffset === undefined) { - initializeDomainOffset(objects.map(function (obj) { - return handle.getDomainValue(obj, domain); - }).filter(function (value) { - return typeof value === 'number'; - })); - } - - // Make sure lines are available - prepareLines(objects); - - // Add new data - objects.forEach(addPointFor); - - // Then, update extrema - updateBounds(); - } - - // Add historical data for this domain object - function setHistorical(domainObject, series) { - var count = series ? series.getPointCount() : 0, - line; - - // Nothing to do if it's an empty series - if (count < 1) { - return; - } - - // Initialize domain offset if necessary - if (domainOffset === undefined) { - initializeDomainOffset([ - series.getDomainValue(0, domain), - series.getDomainValue(count - 1, domain) - ]); - } - - // Make sure lines are available - prepareLines(handle.getTelemetryObjects()); - - // Look up the line for this domain object - line = lines[domainObject.getId()]; - - // ...and put the data into it. - if (line) { - line.addSeries(series, domain, range); - } - - // Update extrema - updateBounds(); - } + this.ids = []; + this.lines = {}; + this.buffers = {}; + this.bufferArray = []; // Use a default MAX_POINTS if none is provided - maxPoints = maxPoints !== undefined ? maxPoints : MAX_POINTS; + this.maxPoints = maxPoints !== undefined ? maxPoints : MAX_POINTS; + this.dimensions = [0, 0]; + this.origin = [0, 0]; // Initially prepare state for these objects. // Note that this may be an empty array at this time, // so we also need to check during update cycles. - update(); - - return { - /** - * Get the dimensions which bound all data in the provided - * data sets. This is given as a two-element array where the - * first element is domain, and second is range. - * @returns {number[]} the dimensions which bound this data set - * @memberof platform/features/plot.PlotUpdater# - */ - getDimensions: function () { - return dimensions; - }, - /** - * Get the origin of this data set's boundary. - * This is given as a two-element array where the - * first element is domain, and second is range. - * The domain value here is not adjusted by the domain offset. - * @returns {number[]} the origin of this data set's boundary - * @memberof platform/features/plot.PlotUpdater# - */ - getOrigin: function () { - // Pad range if necessary - return origin; - }, - /** - * Get the domain offset; this offset will have been subtracted - * from all domain values in all buffers returned by this - * preparer, in order to minimize loss-of-precision due to - * conversion to the 32-bit float format needed by WebGL. - * @returns {number} the domain offset - * @memberof platform/features/plot.PlotUpdater# - */ - getDomainOffset: function () { - return domainOffset; - }, - /** - * Get all renderable buffers for this data set. This will - * be returned as an array which can be correlated back to - * the provided telemetry data objects (from the constructor - * call) by index. - * - * Internally, these are flattened; each buffer contains a - * sequence of alternating domain and range values. - * - * All domain values in all buffers will have been adjusted - * from their original values by subtraction of the domain - * offset; this minimizes loss-of-precision resulting from - * the conversion to 32-bit floats, which may otherwise - * cause aliasing artifacts (particularly for timestamps) - * - * @returns {Float32Array[]} the buffers for these traces - * @memberof platform/features/plot.PlotUpdater# - */ - getLineBuffers: function () { - return bufferArray; - }, - /** - * Update with latest data. - * @memberof platform/features/plot.PlotUpdater# - */ - update: update, - /** - * Fill in historical data. - * @memberof platform/features/plot.PlotUpdater# - */ - addHistorical: setHistorical - }; + this.update(); } + // Look up a domain object's id (for mapping, below) + function getId(domainObject) { + return domainObject.getId(); + } + + // Used in the reduce step of updateExtrema + function reduceExtrema(a, b) { + return [ Math.min(a[0], b[0]), Math.max(a[1], b[1]) ]; + } + + // Convert a domain/range extrema to plot dimensions + function dimensionsOf(extrema) { + return extrema[1] - extrema[0]; + } + + // Convert a domain/range extrema to a plot origin + function originOf(extrema) { + return extrema[0]; + } + + // Check if this set of ids matches the current set of ids + // (used to detect if line preparation can be skipped) + PlotUpdater.prototype.idsMatch = function (nextIds) { + var ids = this.ids; + return ids.length === nextIds.length && + nextIds.every(function (id, index) { + return ids[index] === id; + }); + }; + + // Prepare plot lines for this group of telemetry objects + PlotUpdater.prototype.prepareLines = function (telemetryObjects) { + var nextIds = telemetryObjects.map(getId), + next = {}, + self = this; + + // Detect if we already have everything we need prepared + if (this.idsMatch(nextIds)) { + // Nothing to prepare, move on + return; + } + + // Built up a set of ids. Note that we can only + // create plot lines after our domain offset has + // been determined. + if (this.domainOffset !== undefined) { + // Update list of ids in use + this.ids = nextIds; + + // Create buffers for these objects + this.bufferArray = this.ids.map(function (id) { + self.buffers[id] = self.buffers[id] || new PlotLineBuffer( + self.domainOffset, + INITIAL_SIZE, + self.maxPoints + ); + next[id] = + self.lines[id] || new PlotLine(self.buffers[id]); + return self.buffers[id]; + }); + } + + // If there are no more lines, clear the domain offset + if (Object.keys(next).length < 1) { + this.domainOffset = undefined; + } + + // Update to the current set of lines + this.lines = next; + }; + + // Initialize the domain offset, based on these observed values + PlotUpdater.prototype.initializeDomainOffset = function (values) { + this.domainOffset = + ((this.domainOffset === undefined) && (values.length > 0)) ? + (values.reduce(function (a, b) { + return (a || 0) + (b || 0); + }, 0) / values.length) : + this.domainOffset; + }; + + // Expand range slightly so points near edges are visible + PlotUpdater.prototype.expandRange = function () { + var padding = PADDING_RATIO * this.dimensions[1], + top; + padding = Math.max(padding, 1.0); + top = Math.ceil(this.origin[1] + this.dimensions[1] + padding / 2); + this.origin[1] = Math.floor(this.origin[1] - padding / 2); + this.dimensions[1] = top - this.origin[1]; + }; + + // Update dimensions and origin based on extrema of plots + PlotUpdater.prototype.updateBounds = function () { + var bufferArray = this.bufferArray; + if (bufferArray.length > 0) { + this.domainExtrema = bufferArray.map(function (lineBuffer) { + return lineBuffer.getDomainExtrema(); + }).reduce(reduceExtrema); + + this.rangeExtrema = bufferArray.map(function (lineBuffer) { + return lineBuffer.getRangeExtrema(); + }).reduce(reduceExtrema); + + // Calculate best-fit dimensions + this.dimensions = [ this.domainExtrema, this.rangeExtrema ] + .map(dimensionsOf); + this.origin = [ this.domainExtrema, this.rangeExtrema ] + .map(originOf); + + // Enforce some minimum visible area + this.expandRange(); + + // ...then enforce a fixed duration if needed + if (this.fixedDuration !== undefined) { + this.origin[0] = this.origin[0] + this.dimensions[0] - + this.fixedDuration; + this.dimensions[0] = this.fixedDuration; + } + } + }; + + // Add latest data for this domain object + PlotUpdater.prototype.addPointFor = function (domainObject) { + var line = this.lines[domainObject.getId()]; + if (line) { + line.addPoint( + this.handle.getDomainValue(domainObject, this.domain), + this.handle.getRangeValue(domainObject, this.range) + ); + } + }; + + /** + * Update with latest data. + */ + PlotUpdater.prototype.update = function update() { + var objects = this.handle.getTelemetryObjects(), + self = this; + + // Initialize domain offset if necessary + if (this.domainOffset === undefined) { + this.initializeDomainOffset(objects.map(function (obj) { + return self.handle.getDomainValue(obj, self.domain); + }).filter(function (value) { + return typeof value === 'number'; + })); + } + + // Make sure lines are available + this.prepareLines(objects); + + // Add new data + objects.forEach(function (domainObject, index) { + self.addPointFor(domainObject, index); + }); + + // Then, update extrema + this.updateBounds(); + }; + + /** + * Get the dimensions which bound all data in the provided + * data sets. This is given as a two-element array where the + * first element is domain, and second is range. + * @returns {number[]} the dimensions which bound this data set + */ + PlotUpdater.prototype.getDimensions = function () { + return this.dimensions; + }; + + /** + * Get the origin of this data set's boundary. + * This is given as a two-element array where the + * first element is domain, and second is range. + * The domain value here is not adjusted by the domain offset. + * @returns {number[]} the origin of this data set's boundary + */ + PlotUpdater.prototype.getOrigin = function () { + return this.origin; + }; + + /** + * Get the domain offset; this offset will have been subtracted + * from all domain values in all buffers returned by this + * preparer, in order to minimize loss-of-precision due to + * conversion to the 32-bit float format needed by WebGL. + * @returns {number} the domain offset + * @memberof platform/features/plot.PlotUpdater# + */ + PlotUpdater.prototype.getDomainOffset = function () { + return this.domainOffset; + }; + + /** + * Get all renderable buffers for this data set. This will + * be returned as an array which can be correlated back to + * the provided telemetry data objects (from the constructor + * call) by index. + * + * Internally, these are flattened; each buffer contains a + * sequence of alternating domain and range values. + * + * All domain values in all buffers will have been adjusted + * from their original values by subtraction of the domain + * offset; this minimizes loss-of-precision resulting from + * the conversion to 32-bit floats, which may otherwise + * cause aliasing artifacts (particularly for timestamps) + * + * @returns {Float32Array[]} the buffers for these traces + * @memberof platform/features/plot.PlotUpdater# + */ + PlotUpdater.prototype.getLineBuffers = function () { + return this.bufferArray; + }; + + /** + * Fill in historical data. + */ + PlotUpdater.prototype.addHistorical = function (domainObject, series) { + var count = series ? series.getPointCount() : 0, + line; + + // Nothing to do if it's an empty series + if (count < 1) { + return; + } + + // Initialize domain offset if necessary + if (this.domainOffset === undefined) { + this.initializeDomainOffset([ + series.getDomainValue(0, this.domain), + series.getDomainValue(count - 1, this.domain) + ]); + } + + // Make sure lines are available + this.prepareLines(this.handle.getTelemetryObjects()); + + // Look up the line for this domain object + line = this.lines[domainObject.getId()]; + + // ...and put the data into it. + if (line) { + line.addSeries(series, this.domain, this.range); + } + + // Update extrema + this.updateBounds(); + }; + return PlotUpdater; } From 820c15d74cd796dbc89cc9351b7d4e41ffd5ad74 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 13 Aug 2015 12:12:15 -0700 Subject: [PATCH 57/84] [Code Style] Use prototypes in Plot bundle WTD-1482. --- platform/features/plot/src/Canvas2DChart.js | 175 +++-- platform/features/plot/src/GLChart.js | 130 ++-- platform/features/plot/src/MCTChart.js | 39 ++ platform/features/plot/src/PlotController.js | 238 ++++--- platform/features/plot/src/SubPlot.js | 605 +++++++++--------- platform/features/plot/src/SubPlotFactory.js | 38 +- .../plot/src/modes/PlotModeOptions.js | 167 +++-- .../plot/src/modes/PlotOverlayMode.js | 102 ++- .../features/plot/src/modes/PlotStackMode.js | 145 ++--- .../plot/src/policies/PlotViewPolicy.js | 43 +- .../features/plot/test/PlotControllerSpec.js | 14 +- 11 files changed, 844 insertions(+), 852 deletions(-) diff --git a/platform/features/plot/src/Canvas2DChart.js b/platform/features/plot/src/Canvas2DChart.js index 9fcee46123..5917207920 100644 --- a/platform/features/plot/src/Canvas2DChart.js +++ b/platform/features/plot/src/Canvas2DChart.js @@ -31,116 +31,89 @@ define( * * @memberof platform/features/plot * @constructor + * @implements {platform/features/plot.Chart} * @param {CanvasElement} canvas the canvas object to render upon * @throws {Error} an error is thrown if Canvas's 2D API is unavailable. */ function Canvas2DChart(canvas) { - var c2d = canvas.getContext('2d'), - width = canvas.width, - height = canvas.height, - dimensions = [ width, height ], - origin = [ 0, 0 ]; + this.canvas = canvas; + this.c2d = canvas.getContext('2d'); + this.width = canvas.width; + this.height = canvas.height; + this.dimensions = [ this.width, this.height ]; + this.origin = [ 0, 0 ]; - // Convert from logical to physical x coordinates - function x(v) { - return ((v - origin[0]) / dimensions[0]) * width; - } - - // Convert from logical to physical y coordinates - function y(v) { - return height - ((v - origin[1]) / dimensions[1]) * height; - } - - // Set the color to be used for drawing operations - function setColor(color) { - var mappedColor = color.map(function (c, i) { - return i < 3 ? Math.floor(c * 255) : (c); - }).join(','); - c2d.strokeStyle = "rgba(" + mappedColor + ")"; - c2d.fillStyle = "rgba(" + mappedColor + ")"; - } - - if (!c2d) { + if (!this.c2d) { throw new Error("Canvas 2d API unavailable."); } - - return { - /** - * Clear the chart. - * @memberof platform/features/plot.Canvas2DChart# - */ - clear: function () { - width = canvas.width; - height = canvas.height; - c2d.clearRect(0, 0, width, height); - }, - /** - * Set the logical boundaries of the chart. - * @param {number[]} dimensions the horizontal and - * vertical dimensions of the chart - * @param {number[]} origin the horizontal/vertical - * origin of the chart - * @memberof platform/features/plot.Canvas2DChart# - */ - setDimensions: function (newDimensions, newOrigin) { - dimensions = newDimensions; - origin = newOrigin; - }, - /** - * Draw the supplied buffer as a line strip (a sequence - * of line segments), in the chosen color. - * @param {Float32Array} buf the line strip to draw, - * in alternating x/y positions - * @param {number[]} color the color to use when drawing - * the line, as an RGBA color where each element - * is in the range of 0.0-1.0 - * @param {number} points the number of points to draw - * @memberof platform/features/plot.Canvas2DChart# - */ - drawLine: function (buf, color, points) { - var i; - - setColor(color); - - // Configure context to draw two-pixel-thick lines - c2d.lineWidth = 2; - - // Start a new path... - if (buf.length > 1) { - c2d.beginPath(); - c2d.moveTo(x(buf[0]), y(buf[1])); - } - - // ...and add points to it... - for (i = 2; i < points * 2; i = i + 2) { - c2d.lineTo(x(buf[i]), y(buf[i + 1])); - } - - // ...before finally drawing it. - c2d.stroke(); - }, - /** - * Draw a rectangle extending from one corner to another, - * in the chosen color. - * @param {number[]} min the first corner of the rectangle - * @param {number[]} max the opposite corner - * @param {number[]} color the color to use when drawing - * the rectangle, as an RGBA color where each element - * is in the range of 0.0-1.0 - * @memberof platform/features/plot.Canvas2DChart# - */ - drawSquare: function (min, max, color) { - var x1 = x(min[0]), - y1 = y(min[1]), - w = x(max[0]) - x1, - h = y(max[1]) - y1; - - setColor(color); - c2d.fillRect(x1, y1, w, h); - } - }; } + // Convert from logical to physical x coordinates + Canvas2DChart.prototype.x = function (v) { + return ((v - this.origin[0]) / this.dimensions[0]) * this.width; + }; + + // Convert from logical to physical y coordinates + Canvas2DChart.prototype.y = function (v) { + return this.height - + ((v - this.origin[1]) / this.dimensions[1]) * this.height; + }; + + // Set the color to be used for drawing operations + Canvas2DChart.prototype.setColor = function (color) { + var mappedColor = color.map(function (c, i) { + return i < 3 ? Math.floor(c * 255) : (c); + }).join(','); + this.c2d.strokeStyle = "rgba(" + mappedColor + ")"; + this.c2d.fillStyle = "rgba(" + mappedColor + ")"; + }; + + + Canvas2DChart.prototype.clear = function () { + var canvas = this.canvas; + this.width = canvas.width; + this.height = canvas.height; + this.c2d.clearRect(0, 0, this.width, this.height); + }; + + Canvas2DChart.prototype.setDimensions = function (newDimensions, newOrigin) { + this.dimensions = newDimensions; + this.origin = newOrigin; + }; + + Canvas2DChart.prototype.drawLine = function (buf, color, points) { + var i; + + this.setColor(color); + + // Configure context to draw two-pixel-thick lines + this.c2d.lineWidth = 2; + + // Start a new path... + if (buf.length > 1) { + this.c2d.beginPath(); + this.c2d.moveTo(this.x(buf[0]), this.y(buf[1])); + } + + // ...and add points to it... + for (i = 2; i < points * 2; i = i + 2) { + this.c2d.lineTo(this.x(buf[i]), this.y(buf[i + 1])); + } + + // ...before finally drawing it. + this.c2d.stroke(); + }; + + Canvas2DChart.prototype.drawSquare = function (min, max, color) { + var x1 = this.x(min[0]), + y1 = this.y(min[1]), + w = this.x(max[0]) - x1, + h = this.y(max[1]) - y1; + + this.setColor(color); + this.c2d.fillRect(x1, y1, w, h); + }; + return Canvas2DChart; } ); diff --git a/platform/features/plot/src/GLChart.js b/platform/features/plot/src/GLChart.js index a390cf1153..6dc7934fa5 100644 --- a/platform/features/plot/src/GLChart.js +++ b/platform/features/plot/src/GLChart.js @@ -51,6 +51,7 @@ define( * * @memberof platform/features/plot * @constructor + * @implements {platform/features/plot.Chart} * @param {CanvasElement} canvas the canvas object to render upon * @throws {Error} an error is thrown if WebGL is unavailable. */ @@ -62,8 +63,7 @@ define( aVertexPosition, uColor, uDimensions, - uOrigin, - buffer; + uOrigin; // Ensure a context was actually available before proceeding if (!gl) { @@ -94,7 +94,7 @@ define( gl.enableVertexAttribArray(aVertexPosition); // Create a buffer to holds points which will be drawn - buffer = gl.createBuffer(); + this.buffer = gl.createBuffer(); // Use a line width of 2.0 for legibility gl.lineWidth(2.0); @@ -103,79 +103,59 @@ define( gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); - // Utility function to handle drawing of a buffer; - // drawType will determine whether this is a box, line, etc. - function doDraw(drawType, buf, color, points) { - gl.bindBuffer(gl.ARRAY_BUFFER, buffer); - gl.bufferData(gl.ARRAY_BUFFER, buf, gl.DYNAMIC_DRAW); - gl.vertexAttribPointer(aVertexPosition, 2, gl.FLOAT, false, 0, 0); - gl.uniform4fv(uColor, color); - gl.drawArrays(drawType, 0, points); - } - - return { - /** - * Clear the chart. - * @memberof platform/features/plot.GLChart# - */ - clear: function () { - // Set the viewport size; note that we use the width/height - // that our WebGL context reports, which may be lower - // resolution than the canvas we requested. - gl.viewport( - 0, - 0, - gl.drawingBufferWidth, - gl.drawingBufferHeight - ); - gl.clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT); - }, - /** - * Set the logical boundaries of the chart. - * @param {number[]} dimensions the horizontal and - * vertical dimensions of the chart - * @param {number[]} origin the horizontal/vertical - * origin of the chart - * @memberof platform/features/plot.GLChart# - */ - setDimensions: function (dimensions, origin) { - if (dimensions && dimensions.length > 0 && - origin && origin.length > 0) { - gl.uniform2fv(uDimensions, dimensions); - gl.uniform2fv(uOrigin, origin); - } - }, - /** - * Draw the supplied buffer as a line strip (a sequence - * of line segments), in the chosen color. - * @param {Float32Array} buf the line strip to draw, - * in alternating x/y positions - * @param {number[]} color the color to use when drawing - * the line, as an RGBA color where each element - * is in the range of 0.0-1.0 - * @param {number} points the number of points to draw - * @memberof platform/features/plot.GLChart# - */ - drawLine: function (buf, color, points) { - doDraw(gl.LINE_STRIP, buf, color, points); - }, - /** - * Draw a rectangle extending from one corner to another, - * in the chosen color. - * @param {number[]} min the first corner of the rectangle - * @param {number[]} max the opposite corner - * @param {number[]} color the color to use when drawing - * the rectangle, as an RGBA color where each element - * is in the range of 0.0-1.0 - * @memberof platform/features/plot.GLChart# - */ - drawSquare: function (min, max, color) { - doDraw(gl.TRIANGLE_FAN, new Float32Array( - min.concat([min[0], max[1]]).concat(max).concat([max[0], min[1]]) - ), color, 4); - } - }; + this.gl = gl; + this.aVertexPosition = aVertexPosition; + this.uColor = uColor; + this.uDimensions = uDimensions; + this.uOrigin = uOrigin; } + + // Utility function to handle drawing of a buffer; + // drawType will determine whether this is a box, line, etc. + GLChart.prototype.doDraw = function (drawType, buf, color, points) { + var gl = this.gl; + gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer); + gl.bufferData(gl.ARRAY_BUFFER, buf, gl.DYNAMIC_DRAW); + gl.vertexAttribPointer(this.aVertexPosition, 2, gl.FLOAT, false, 0, 0); + gl.uniform4fv(this.uColor, color); + gl.drawArrays(drawType, 0, points); + }; + + GLChart.prototype.clear = function () { + var gl = this.gl; + + // Set the viewport size; note that we use the width/height + // that our WebGL context reports, which may be lower + // resolution than the canvas we requested. + gl.viewport( + 0, + 0, + gl.drawingBufferWidth, + gl.drawingBufferHeight + ); + gl.clear(gl.COLOR_BUFFER_BIT + gl.DEPTH_BUFFER_BIT); + }; + + + GLChart.prototype.setDimensions = function (dimensions, origin) { + var gl = this.gl; + if (dimensions && dimensions.length > 0 && + origin && origin.length > 0) { + gl.uniform2fv(this.uDimensions, dimensions); + gl.uniform2fv(this.uOrigin, origin); + } + }; + + GLChart.prototype.drawLine = function (buf, color, points) { + this.doDraw(this.gl.LINE_STRIP, buf, color, points); + }; + + GLChart.prototype.drawSquare = function (min, max, color) { + this.doDraw(this.gl.TRIANGLE_FAN, new Float32Array( + min.concat([min[0], max[1]]).concat(max).concat([max[0], min[1]]) + ), color, 4); + }; + return GLChart; } ); diff --git a/platform/features/plot/src/MCTChart.js b/platform/features/plot/src/MCTChart.js index 951ca3532b..e8c9db74e4 100644 --- a/platform/features/plot/src/MCTChart.js +++ b/platform/features/plot/src/MCTChart.js @@ -206,6 +206,45 @@ define( }; } + /** + * @interface platform/features/plot.Chart + * @private + */ + + /** + * Clear the chart. + * @method platform/features/plot.Chart#clear + */ + /** + * Set the logical boundaries of the chart. + * @param {number[]} dimensions the horizontal and + * vertical dimensions of the chart + * @param {number[]} origin the horizontal/vertical + * origin of the chart + * @memberof platform/features/plot.Chart#setDimensions + */ + /** + * Draw the supplied buffer as a line strip (a sequence + * of line segments), in the chosen color. + * @param {Float32Array} buf the line strip to draw, + * in alternating x/y positions + * @param {number[]} color the color to use when drawing + * the line, as an RGBA color where each element + * is in the range of 0.0-1.0 + * @param {number} points the number of points to draw + * @memberof platform/features/plot.Chart#drawLine + */ + /** + * Draw a rectangle extending from one corner to another, + * in the chosen color. + * @param {number[]} min the first corner of the rectangle + * @param {number[]} max the opposite corner + * @param {number[]} color the color to use when drawing + * the rectangle, as an RGBA color where each element + * is in the range of 0.0-1.0 + * @memberof platform/features/plot.Chart#drawSquare + */ + return MCTChart; } ); diff --git a/platform/features/plot/src/PlotController.js b/platform/features/plot/src/PlotController.js index da8dcfb168..a54fff83dd 100644 --- a/platform/features/plot/src/PlotController.js +++ b/platform/features/plot/src/PlotController.js @@ -61,15 +61,11 @@ define( throttle, PLOT_FIXED_DURATION ) { - var subPlotFactory = new SubPlotFactory(telemetryFormatter), - modeOptions = new PlotModeOptions([], subPlotFactory), - subplots = [], + var self = this, + subPlotFactory = new SubPlotFactory(telemetryFormatter), cachedObjects = [], - limitTracker, updater, - handle, - scheduleUpdate, - domainOffset; + handle; // Populate the scope with axis information (specifically, options // available for each axis.) @@ -91,18 +87,13 @@ define( function setupModes(telemetryObjects) { if (cachedObjects !== telemetryObjects) { cachedObjects = telemetryObjects; - modeOptions = new PlotModeOptions( + self.modeOptions = new PlotModeOptions( telemetryObjects || [], subPlotFactory ); } } - // Update all sub-plots - function update() { - scheduleUpdate(); - } - // Reinstantiate the plot updater (e.g. because we have a // new subscription.) This will clear the plot. function recreateUpdater() { @@ -112,7 +103,7 @@ define( ($scope.axes[1].active || {}).key, PLOT_FIXED_DURATION ); - limitTracker = new PlotLimitTracker( + self.limitTracker = new PlotLimitTracker( handle, ($scope.axes[1].active || {}).key ); @@ -125,19 +116,19 @@ define( } if (updater) { updater.update(); - modeOptions.getModeHandler().plotTelemetry(updater); + self.modeOptions.getModeHandler().plotTelemetry(updater); } - if (limitTracker) { - limitTracker.update(); + if (self.limitTracker) { + self.limitTracker.update(); } - update(); + self.update(); } // Display new historical data as it becomes available function addHistoricalData(domainObject, series) { updater.addHistorical(domainObject, series); - modeOptions.getModeHandler().plotTelemetry(updater); - update(); + self.modeOptions.getModeHandler().plotTelemetry(updater); + self.update(); } // Issue a new request for historical telemetry @@ -174,116 +165,119 @@ define( } } + this.modeOptions = new PlotModeOptions([], subPlotFactory); + this.updateValues = updateValues; + + // Create a throttled update function + this.scheduleUpdate = throttle(function () { + self.modeOptions.getModeHandler().getSubPlots() + .forEach(updateSubplot); + }); + // Subscribe to telemetry when a domain object becomes available $scope.$watch('domainObject', subscribe); // Unsubscribe when the plot is destroyed $scope.$on("$destroy", releaseSubscription); - // Create a throttled update function - scheduleUpdate = throttle(function () { - modeOptions.getModeHandler().getSubPlots() - .forEach(updateSubplot); - }); - - return { - /** - * Get the color (as a style-friendly string) to use - * for plotting the trace at the specified index. - * @param {number} index the index of the trace - * @returns {string} the color, in #RRGGBB form - * @memberof platform/features/plot.PlotController# - */ - getColor: function (index) { - return PlotPalette.getStringColor(index); - }, - /** - * Check if the plot is zoomed or panned out - * of its default state (to determine whether back/unzoom - * controls should be shown) - * @returns {boolean} true if not in default state - * @memberof platform/features/plot.PlotController# - */ - isZoomed: function () { - return modeOptions.getModeHandler().isZoomed(); - }, - /** - * Undo the most recent pan/zoom change and restore - * the prior state. - * @memberof platform/features/plot.PlotController# - */ - stepBackPanZoom: function () { - return modeOptions.getModeHandler().stepBackPanZoom(); - }, - /** - * Undo all pan/zoom changes and restore the initial state. - * @memberof platform/features/plot.PlotController# - */ - unzoom: function () { - return modeOptions.getModeHandler().unzoom(); - }, - /** - * Get the mode options (Stacked/Overlaid) that are applicable - * for this plot. - * @memberof platform/features/plot.PlotController# - */ - getModeOptions: function () { - return modeOptions.getModeOptions(); - }, - /** - * Get the current mode that is applicable to this plot. This - * will include key, name, and glyph fields. - * @memberof platform/features/plot.PlotController# - */ - getMode: function () { - return modeOptions.getMode(); - }, - /** - * Set the mode which should be active in this plot. - * @param mode one of the mode options returned from - * getModeOptions() - * @memberof platform/features/plot.PlotController# - */ - setMode: function (mode) { - modeOptions.setMode(mode); - updateValues(); - }, - /** - * Get all individual plots contained within this Plot view. - * (Multiple may be contained when in Stacked mode). - * @returns {SubPlot[]} all subplots in this Plot view - * @memberof platform/features/plot.PlotController# - */ - getSubPlots: function () { - return modeOptions.getModeHandler().getSubPlots(); - }, - /** - * Get the CSS class to apply to the legend for this domain - * object; this will reflect limit state. - * @returns {string} the CSS class - * @memberof platform/features/plot.PlotController# - */ - getLegendClass: function (telemetryObject) { - return limitTracker && - limitTracker.getLegendClass(telemetryObject); - }, - /** - * Explicitly update all plots. - * @memberof platform/features/plot.PlotController# - */ - update: update, - /** - * Check if a request is pending (to show the wait spinner) - * @memberof platform/features/plot.PlotController# - */ - isRequestPending: function () { - // Placeholder; this should reflect request state - // when requesting historical telemetry - return false; - } - }; } + /** + * Get the color (as a style-friendly string) to use + * for plotting the trace at the specified index. + * @param {number} index the index of the trace + * @returns {string} the color, in #RRGGBB form + */ + PlotController.prototype.getColor = function (index) { + return PlotPalette.getStringColor(index); + }; + + /** + * Check if the plot is zoomed or panned out + * of its default state (to determine whether back/unzoom + * controls should be shown) + * @returns {boolean} true if not in default state + */ + PlotController.prototype.isZoomed = function () { + return this.modeOptions.getModeHandler().isZoomed(); + }; + + /** + * Undo the most recent pan/zoom change and restore + * the prior state. + */ + PlotController.prototype.stepBackPanZoom = function () { + return this.modeOptions.getModeHandler().stepBackPanZoom(); + }; + + /** + * Undo all pan/zoom changes and restore the initial state. + */ + PlotController.prototype.unzoom = function () { + return this.modeOptions.getModeHandler().unzoom(); + }; + + /** + * Get the mode options (Stacked/Overlaid) that are applicable + * for this plot. + */ + PlotController.prototype.getModeOptions = function () { + return this.modeOptions.getModeOptions(); + }; + + /** + * Get the current mode that is applicable to this plot. This + * will include key, name, and glyph fields. + */ + PlotController.prototype.getMode = function () { + return this.modeOptions.getMode(); + }; + + /** + * Set the mode which should be active in this plot. + * @param mode one of the mode options returned from + * getModeOptions() + */ + PlotController.prototype.setMode = function (mode) { + this.modeOptions.setMode(mode); + this.updateValues(); + }; + + /** + * Get all individual plots contained within this Plot view. + * (Multiple may be contained when in Stacked mode). + * @returns {SubPlot[]} all subplots in this Plot view + */ + PlotController.prototype.getSubPlots = function () { + return this.modeOptions.getModeHandler().getSubPlots(); + }; + + /** + * Get the CSS class to apply to the legend for this domain + * object; this will reflect limit state. + * @returns {string} the CSS class + */ + PlotController.prototype.getLegendClass = function (telemetryObject) { + return this.limitTracker && + this.limitTracker.getLegendClass(telemetryObject); + }; + + /** + * Explicitly update all plots. + */ + PlotController.prototype.update = function () { + this.scheduleUpdate(); + }; + + /** + * Check if a request is pending (to show the wait spinner) + */ + PlotController.prototype.isRequestPending = function () { + // Placeholder; this should reflect request state + // when requesting historical telemetry + return false; + }; + return PlotController; } ); diff --git a/platform/features/plot/src/SubPlot.js b/platform/features/plot/src/SubPlot.js index 9cd8b829cf..06b7f7bb0f 100644 --- a/platform/features/plot/src/SubPlot.js +++ b/platform/features/plot/src/SubPlot.js @@ -50,141 +50,278 @@ define( // We are used from a template often, so maintain // state in local variables to allow for fast look-up, // as is normal for controllers. - var draw = {}, - rangeTicks = [], - domainTicks = [], - formatter = telemetryFormatter, - domainOffset, - mousePosition, - marqueeStart, - panStart, - panStartBounds, - subPlotBounds, - hoverCoordinates, - isHovering = false; + this.telemetryObjects = telemetryObjects; + this.domainTicks = []; + this.rangeTicks = []; + this.formatter = telemetryFormatter; + this.draw = {}; + this.hovering = false; + this.panZoomStack = panZoomStack; + + // Start with the right initial drawing bounds, + // tick marks + this.updateDrawingBounds(); + this.updateTicks(); + } + + // Utility function for filtering out empty strings. + function isNonEmpty(v) { + return typeof v === 'string' && v !== ""; + } + + // Converts from pixel coordinates to domain-range, + // to interpret mouse gestures. + SubPlot.prototype.mousePositionToDomainRange = function (mousePosition) { + return new PlotPosition( + mousePosition.x, + mousePosition.y, + mousePosition.width, + mousePosition.height, + this.panZoomStack + ).getPosition(); + }; + + // Utility function to get the mouse position (in x,y + // pixel coordinates in the canvas area) from a mouse + // event object. + SubPlot.prototype.toMousePosition = function ($event) { + var bounds = this.subPlotBounds; + + return { + x: $event.clientX - bounds.left, + y: $event.clientY - bounds.top, + width: bounds.width, + height: bounds.height + }; + }; + + // Convert a domain-range position to a displayable + // position. This will subtract the domain offset, which + // is used to bias domain values to minimize loss-of-precision + // associated with conversion to a 32-bit floating point + // format (which is needed in the chart area itself, by WebGL.) + SubPlot.prototype.toDisplayable = function (position) { + return [ position[0] - this.domainOffset, position[1] ]; + }; + + // Update the current hover coordinates + SubPlot.prototype.updateHoverCoordinates = function () { + var formatter = this.formatter; // Utility, for map/forEach loops. Index 0 is domain, // index 1 is range. function formatValue(v, i) { return (i ? - formatter.formatRangeValue : - formatter.formatDomainValue)(v); + formatter.formatRangeValue : + formatter.formatDomainValue)(v); } - // Utility function for filtering out empty strings. - function isNonEmpty(v) { - return typeof v === 'string' && v !== ""; + this.hoverCoordinates = this.mousePosition && + this.mousePositionToDomainRange(this.mousePosition) + .map(formatValue) + .filter(isNonEmpty) + .join(", "); + }; + + // Update the drawable marquee area to reflect current + // mouse position (or don't show it at all, if no marquee + // zoom is in progress) + SubPlot.prototype.updateMarqueeBox = function () { + // Express this as a box in the draw object, which + // is passed to an mct-chart in the template for rendering. + this.draw.boxes = this.marqueeStart ? + [{ + start: this.toDisplayable( + this.mousePositionToDomainRange(this.marqueeStart) + ), + end: this.toDisplayable( + this.mousePositionToDomainRange(this.mousePosition) + ), + color: [1, 1, 1, 0.5 ] + }] : undefined; + }; + + // Update the bounds (origin and dimensions) of the drawing area. + SubPlot.prototype.updateDrawingBounds = function () { + var panZoom = this.panZoomStack.getPanZoom(); + + // Communicate pan-zoom state from stack to the draw object + // which is passed to mct-chart in the template. + this.draw.dimensions = panZoom.dimensions; + this.draw.origin = [ + panZoom.origin[0] - this.domainOffset, + panZoom.origin[1] + ]; + }; + + // Update tick marks in scope. + SubPlot.prototype.updateTicks = function () { + var tickGenerator = + new PlotTickGenerator(this.panZoomStack, this.formatter); + + this.domainTicks = + tickGenerator.generateDomainTicks(DOMAIN_TICKS); + this.rangeTicks = + tickGenerator.generateRangeTicks(RANGE_TICKS); + }; + + SubPlot.prototype.updatePan = function () { + var start, current, delta, nextOrigin; + + // Clear the previous panning pan-zoom state + this.panZoomStack.popPanZoom(); + + // Calculate what the new resulting pan-zoom should be + start = this.mousePositionToDomainRange( + this.panStart, + this.panZoomStack + ); + current = this.mousePositionToDomainRange( + this.mousePosition, + this.panZoomStack + ); + + delta = [ current[0] - start[0], current[1] - start[1] ]; + nextOrigin = [ + this.panStartBounds.origin[0] - delta[0], + this.panStartBounds.origin[1] - delta[1] + ]; + + // ...and push a new one at the current mouse position + this.panZoomStack + .pushPanZoom(nextOrigin, this.panStartBounds.dimensions); + }; + + /** + * Get the set of domain objects which are being + * represented in this sub-plot. + * @returns {DomainObject[]} the domain objects which + * will have data plotted in this sub-plot + */ + SubPlot.prototype.getTelemetryObjects = function () { + return this.telemetryObjects; + }; + + /** + * Get ticks mark information appropriate for using in the + * template for this sub-plot's domain axis, as prepared + * by the PlotTickGenerator. + * @returns {Array} tick marks for the domain axis + */ + SubPlot.prototype.getDomainTicks = function () { + return this.domainTicks; + }; + + /** + * Get ticks mark information appropriate for using in the + * template for this sub-plot's range axis, as prepared + * by the PlotTickGenerator. + * @returns {Array} tick marks for the range axis + */ + SubPlot.prototype.getRangeTicks = function () { + return this.rangeTicks; + }; + + /** + * Get the drawing object associated with this sub-plot; + * this object will be passed to the mct-chart in which + * this sub-plot's lines will be plotted, as its "draw" + * attribute, and should have the same internal format + * expected by that directive. + * @return {object} the drawing object + */ + SubPlot.prototype.getDrawingObject = function () { + return this.draw; + }; + + /** + * Get the coordinates (as displayable text) for the + * current mouse position. + * @returns {string[]} the displayable domain and range + * coordinates over which the mouse is hovered + */ + SubPlot.prototype.getHoverCoordinates = function () { + return this.hoverCoordinates; + }; + + /** + * Handle mouse movement over the chart area. + * @param $event the mouse event + * @memberof platform/features/plot.SubPlot# + */ + SubPlot.prototype.hover = function ($event) { + this.hovering = true; + this.subPlotBounds = $event.target.getBoundingClientRect(); + this.mousePosition = this.toMousePosition($event); + this.updateHoverCoordinates(); + if (this.marqueeStart) { + this.updateMarqueeBox(); } - - // Converts from pixel coordinates to domain-range, - // to interpret mouse gestures. - function mousePositionToDomainRange(mousePosition) { - return new PlotPosition( - mousePosition.x, - mousePosition.y, - mousePosition.width, - mousePosition.height, - panZoomStack - ).getPosition(); + if (this.panStart) { + this.updatePan(); + this.updateDrawingBounds(); + this.updateTicks(); } + }; - // Utility function to get the mouse position (in x,y - // pixel coordinates in the canvas area) from a mouse - // event object. - function toMousePosition($event) { - var bounds = subPlotBounds; - - return { - x: $event.clientX - bounds.left, - y: $event.clientY - bounds.top, - width: bounds.width, - height: bounds.height - }; + /** + * Continue a previously-start pan or zoom gesture. + * @param $event the mouse event + * @memberof platform/features/plot.SubPlot# + */ + SubPlot.prototype.continueDrag = function ($event) { + this.mousePosition = this.toMousePosition($event); + if (this.marqueeStart) { + this.updateMarqueeBox(); } - - // Convert a domain-range position to a displayable - // position. This will subtract the domain offset, which - // is used to bias domain values to minimize loss-of-precision - // associated with conversion to a 32-bit floating point - // format (which is needed in the chart area itself, by WebGL.) - function toDisplayable(position) { - return [ position[0] - domainOffset, position[1] ]; + if (this.panStart) { + this.updatePan(); + this.updateDrawingBounds(); + this.updateTicks(); } + }; - - // Update the currnet hover coordinates - function updateHoverCoordinates() { - hoverCoordinates = mousePosition && - mousePositionToDomainRange(mousePosition) - .map(formatValue) - .filter(isNonEmpty) - .join(", "); - } - - // Update the drawable marquee area to reflect current - // mouse position (or don't show it at all, if no marquee - // zoom is in progress) - function updateMarqueeBox() { - // Express this as a box in the draw object, which - // is passed to an mct-chart in the template for rendering. - draw.boxes = marqueeStart ? - [{ - start: toDisplayable(mousePositionToDomainRange(marqueeStart)), - end: toDisplayable(mousePositionToDomainRange(mousePosition)), - color: [1, 1, 1, 0.5 ] - }] : undefined; - } - - // Update the bounds (origin and dimensions) of the drawing area. - function updateDrawingBounds() { - var panZoom = panZoomStack.getPanZoom(); - - // Communicate pan-zoom state from stack to the draw object - // which is passed to mct-chart in the template. - draw.dimensions = panZoom.dimensions; - draw.origin = [ - panZoom.origin[0] - domainOffset, - panZoom.origin[1] - ]; - } - - // Update tick marks in scope. - function updateTicks() { - var tickGenerator = new PlotTickGenerator(panZoomStack, formatter); - - domainTicks = - tickGenerator.generateDomainTicks(DOMAIN_TICKS); - rangeTicks = - tickGenerator.generateRangeTicks(RANGE_TICKS); - } - - function updatePan() { - var start, current, delta, nextOrigin; - - // Clear the previous panning pan-zoom state - panZoomStack.popPanZoom(); - - // Calculate what the new resulting pan-zoom should be - start = mousePositionToDomainRange(panStart); - current = mousePositionToDomainRange(mousePosition); - delta = [ current[0] - start[0], current[1] - start[1] ]; - nextOrigin = [ - panStartBounds.origin[0] - delta[0], - panStartBounds.origin[1] - delta[1] - ]; - - // ...and push a new one at the current mouse position - panZoomStack.pushPanZoom(nextOrigin, panStartBounds.dimensions); + /** + * Initiate a marquee zoom action. + * @param $event the mouse event + */ + SubPlot.prototype.startDrag = function ($event) { + this.subPlotBounds = $event.target.getBoundingClientRect(); + this.mousePosition = this.toMousePosition($event); + // Treat any modifier key as a pan + if ($event.altKey || $event.shiftKey || $event.ctrlKey) { + // Start panning + this.panStart = this.mousePosition; + this.panStartBounds = this.panZoomStack.getPanZoom(); + // We're starting a pan, so add this back as a + // state on the stack; it will get replaced + // during the pan. + this.panZoomStack.pushPanZoom( + this.panStartBounds.origin, + this.panStartBounds.dimensions + ); + $event.preventDefault(); + } else { + // Start marquee zooming + this.marqueeStart = this.mousePosition; + this.updateMarqueeBox(); } + }; + /** + * Complete a marquee zoom action. + * @param $event the mouse event + */ + SubPlot.prototype.endDrag = function ($event) { + var self = this; // Perform a marquee zoom. function marqueeZoom(start, end) { // Determine what boundary is described by the marquee, // in domain-range values. Use the minima for origin, so that // it doesn't matter what direction the user marqueed in. - var a = mousePositionToDomainRange(start), - b = mousePositionToDomainRange(end), + var a = self.mousePositionToDomainRange(start), + b = self.mousePositionToDomainRange(end), origin = [ Math.min(a[0], b[0]), Math.min(a[1], b[1]) @@ -197,196 +334,68 @@ define( // Proceed with zoom if zoom dimensions are non zeros if (!(dimensions[0] === 0 && dimensions[1] === 0)) { // Push the new state onto the pan-zoom stack - panZoomStack.pushPanZoom(origin, dimensions); + self.panZoomStack.pushPanZoom(origin, dimensions); // Make sure tick marks reflect new bounds - updateTicks(); + self.updateTicks(); } } - // Start with the right initial drawing bounds, - // tick marks - updateDrawingBounds(); - updateTicks(); + this.mousePosition = this.toMousePosition($event); + this.subPlotBounds = undefined; + if (this.marqueeStart) { + marqueeZoom(this.marqueeStart, this.mousePosition); + this.marqueeStart = undefined; + this.updateMarqueeBox(); + this.updateDrawingBounds(); + this.updateTicks(); + } + if (this.panStart) { + // End panning + this.panStart = undefined; + this.panStartBounds = undefined; + } + }; - return { - /** - * Get the set of domain objects which are being - * represented in this sub-plot. - * @returns {DomainObject[]} the domain objects which - * will have data plotted in this sub-plot - * @memberof platform/features/plot.SubPlot# - */ - getTelemetryObjects: function () { - return telemetryObjects; - }, - /** - * Get ticks mark information appropriate for using in the - * template for this sub-plot's domain axis, as prepared - * by the PlotTickGenerator. - * @returns {Array} tick marks for the domain axis - * @memberof platform/features/plot.SubPlot# - */ - getDomainTicks: function () { - return domainTicks; - }, - /** - * Get ticks mark information appropriate for using in the - * template for this sub-plot's range axis, as prepared - * by the PlotTickGenerator. - * @returns {Array} tick marks for the range axis - * @memberof platform/features/plot.SubPlot# - */ - getRangeTicks: function () { - return rangeTicks; - }, - /** - * Get the drawing object associated with this sub-plot; - * this object will be passed to the mct-chart in which - * this sub-plot's lines will be plotted, as its "draw" - * attribute, and should have the same internal format - * expected by that directive. - * @return {object} the drawing object - * @memberof platform/features/plot.SubPlot# - */ - getDrawingObject: function () { - return draw; - }, - /** - * Get the coordinates (as displayable text) for the - * current mouse position. - * @returns {string[]} the displayable domain and range - * coordinates over which the mouse is hovered - * @memberof platform/features/plot.SubPlot# - */ - getHoverCoordinates: function () { - return hoverCoordinates; - }, - /** - * Handle mouse movement over the chart area. - * @param $event the mouse event - * @memberof platform/features/plot.SubPlot# - */ - hover: function ($event) { - isHovering = true; - subPlotBounds = $event.target.getBoundingClientRect(); - mousePosition = toMousePosition($event); - updateHoverCoordinates(); - if (marqueeStart) { - updateMarqueeBox(); - } - if (panStart) { - updatePan(); - updateDrawingBounds(); - updateTicks(); - } - }, - /** - * Continue a previously-start pan or zoom gesture. - * @param $event the mouse event - * @memberof platform/features/plot.SubPlot# - */ - continueDrag: function ($event) { - mousePosition = toMousePosition($event); - if (marqueeStart) { - updateMarqueeBox(); - } - if (panStart) { - updatePan(); - updateDrawingBounds(); - updateTicks(); - } - }, - /** - * Initiate a marquee zoom action. - * @param $event the mouse event - * @memberof platform/features/plot.SubPlot# - */ - startDrag: function ($event) { - subPlotBounds = $event.target.getBoundingClientRect(); - mousePosition = toMousePosition($event); - // Treat any modifier key as a pan - if ($event.altKey || $event.shiftKey || $event.ctrlKey) { - // Start panning - panStart = mousePosition; - panStartBounds = panZoomStack.getPanZoom(); - // We're starting a pan, so add this back as a - // state on the stack; it will get replaced - // during the pan. - panZoomStack.pushPanZoom( - panStartBounds.origin, - panStartBounds.dimensions - ); - $event.preventDefault(); - } else { - // Start marquee zooming - marqueeStart = mousePosition; - updateMarqueeBox(); - } - }, - /** - * Complete a marquee zoom action. - * @param $event the mouse event - * @memberof platform/features/plot.SubPlot# - */ - endDrag: function ($event) { - mousePosition = toMousePosition($event); - subPlotBounds = undefined; - if (marqueeStart) { - marqueeZoom(marqueeStart, mousePosition); - marqueeStart = undefined; - updateMarqueeBox(); - updateDrawingBounds(); - updateTicks(); - } - if (panStart) { - // End panning - panStart = undefined; - panStartBounds = undefined; - } - }, - /** - * Update the drawing bounds, marquee box, and - * tick marks for this subplot. - * @memberof platform/features/plot.SubPlot# - */ - update: function () { - updateDrawingBounds(); - updateMarqueeBox(); - updateTicks(); - }, - /** - * Set the domain offset associated with this sub-plot. - * A domain offset is subtracted from all domain - * before lines are drawn to avoid artifacts associated - * with the use of 32-bit floats when domain values - * are often timestamps (due to insufficient precision.) - * A SubPlot will be drawing boxes (for marquee zoom) in - * the same offset coordinate space, so it needs to know - * the value of this to position that marquee box - * correctly. - * @param {number} value the domain offset - * @memberof platform/features/plot.SubPlot# - */ - setDomainOffset: function (value) { - domainOffset = value; - }, - /** - * When used with no argument, check whether or not the user - * is currently hovering over this subplot. When used with - * an argument, set that state. - * @param {boolean} [state] the new hovering state - * @returns {boolean} the hovering state - * @memberof platform/features/plot.SubPlot# - */ - isHovering: function (state) { - if (state !== undefined) { - isHovering = state; - } - return isHovering; - } - }; - } + /** + * Update the drawing bounds, marquee box, and + * tick marks for this subplot. + */ + SubPlot.prototype.update = function () { + this.updateDrawingBounds(); + this.updateMarqueeBox(); + this.updateTicks(); + }; + + /** + * Set the domain offset associated with this sub-plot. + * A domain offset is subtracted from all domain + * before lines are drawn to avoid artifacts associated + * with the use of 32-bit floats when domain values + * are often timestamps (due to insufficient precision.) + * A SubPlot will be drawing boxes (for marquee zoom) in + * the same offset coordinate space, so it needs to know + * the value of this to position that marquee box + * correctly. + * @param {number} value the domain offset + */ + SubPlot.prototype.setDomainOffset = function (value) { + this.domainOffset = value; + }; + + /** + * When used with no argument, check whether or not the user + * is currently hovering over this subplot. When used with + * an argument, set that state. + * @param {boolean} [state] the new hovering state + * @returns {boolean} the hovering state + */ + SubPlot.prototype.isHovering = function (state) { + if (state !== undefined) { + this.hovering = state; + } + return this.hovering; + }; return SubPlot; diff --git a/platform/features/plot/src/SubPlotFactory.js b/platform/features/plot/src/SubPlotFactory.js index 33eb8fff65..6de318f106 100644 --- a/platform/features/plot/src/SubPlotFactory.js +++ b/platform/features/plot/src/SubPlotFactory.js @@ -35,28 +35,26 @@ define( * @constructor */ function SubPlotFactory(telemetryFormatter) { - return { - /** - * Instantiate a new sub-plot. - * @param {DomainObject[]} telemetryObjects the domain objects - * which will be plotted in this sub-plot - * @param {PlotPanZoomStack} panZoomStack the stack of pan-zoom - * states which is applicable to this sub-plot - * @returns {SubPlot} the instantiated sub-plot - * @method - * @memberof SubPlotFactory - * @memberof platform/features/plot.SubPlotFactory# - */ - createSubPlot: function (telemetryObjects, panZoomStack) { - return new SubPlot( - telemetryObjects, - panZoomStack, - telemetryFormatter - ); - } - }; + this.telemetryFormatter = telemetryFormatter; } + /** + * Instantiate a new sub-plot. + * @param {DomainObject[]} telemetryObjects the domain objects + * which will be plotted in this sub-plot + * @param {PlotPanZoomStack} panZoomStack the stack of pan-zoom + * states which is applicable to this sub-plot + * @returns {SubPlot} the instantiated sub-plot + * @method + */ + SubPlotFactory.prototype.createSubPlot = function (telemetryObjects, panZoomStack) { + return new SubPlot( + telemetryObjects, + panZoomStack, + this.telemetryFormatter + ); + }; + return SubPlotFactory; } diff --git a/platform/features/plot/src/modes/PlotModeOptions.js b/platform/features/plot/src/modes/PlotModeOptions.js index efeea30fb5..bd03129698 100644 --- a/platform/features/plot/src/modes/PlotModeOptions.js +++ b/platform/features/plot/src/modes/PlotModeOptions.js @@ -30,15 +30,53 @@ define( key: "stacked", name: "Stacked", glyph: "m", - factory: PlotStackMode + Constructor: PlotStackMode }, OVERLAID = { key: "overlaid", name: "Overlaid", glyph: "6", - factory: PlotOverlayMode + Constructor: PlotOverlayMode }; + /** + * Handles distinct behavior associated with different + * plot modes. + * + * @interface platform/features/plot.PlotModeHandler + * @private + */ + + /** + * Plot telemetry to the sub-plot(s) managed by this mode. + * @param {platform/features/plot.PlotUpdater} updater a source + * of data that is ready to plot + * @method platform/features/plot.PlotModeHandler#plotTelemetry + */ + /** + * Get all sub-plots to be displayed in this mode; used + * to populate the plot template. + * @return {platform/features/plot.SubPlot[]} all sub-plots to + * display in this mode + * @method platform/features/plot.PlotModeHandler#getSubPlots + */ + /** + * Check if we are not in our base pan-zoom state (that is, + * there are some temporary user modifications to the + * current pan-zoom state.) + * @returns {boolean} true if not in the base pan-zoom state + * @method platform/features/plot.PlotModeHandler#isZoomed + */ + /** + * Undo the most recent pan/zoom change and restore + * the prior state. + * @method platform/features/plot.PlotModeHandler#stepBackPanZoom + */ + /** + * Undo all pan/zoom change and restore the base state. + * @method platform/features/plot.PlotModeHandler#unzoom + */ + /** * Determines which plotting modes (stacked/overlaid) * are applicable in a given plot view, maintains current @@ -46,73 +84,74 @@ define( * different behaviors associated with these modes. * @memberof platform/features/plot * @constructor - * @param {DomainObject[]} the telemetry objects being + * @param {DomainObject[]} telemetryObjects the telemetry objects being * represented in this plot view + * @param {platform/features/plot.SubPlotFactory} subPlotFactory a + * factory for creating sub-plots */ function PlotModeOptions(telemetryObjects, subPlotFactory) { - var options = telemetryObjects.length > 1 ? - [ OVERLAID, STACKED ] : [ OVERLAID ], - mode = options[0], // Initial selection (overlaid) - modeHandler; - - return { - /** - * Get a handler for the current mode. This will handle - * plotting telemetry, providing subplots for the template, - * and view-level interactions with pan-zoom state. - * @returns {PlotOverlayMode|PlotStackMode} a handler - * for the current mode - * @memberof platform/features/plot.PlotModeOptions# - */ - getModeHandler: function () { - // Lazily initialize - if (!modeHandler) { - modeHandler = mode.factory( - telemetryObjects, - subPlotFactory - ); - } - return modeHandler; - }, - /** - * Get all mode options available for each plot. Each - * mode contains a `name` and `glyph` field suitable - * for display in a template. - * @return {Array} the available modes - * @memberof platform/features/plot.PlotModeOptions# - */ - getModeOptions: function () { - return options; - }, - /** - * Get the plotting mode option currently in use. - * This will be one of the elements returned from - * `getModeOptions`. - * @return {object} the current mode - * @memberof platform/features/plot.PlotModeOptions# - */ - getMode: function () { - return mode; - }, - /** - * Set the plotting mode option to use. - * The passed argument must be one of the options - * returned by `getModeOptions`. - * @param {object} option one of the plot mode options - * from `getModeOptions` - * @memberof platform/features/plot.PlotModeOptions# - */ - setMode: function (option) { - if (mode !== option) { - mode = option; - // Clear the existing mode handler, so it - // can be instantiated next time it's needed. - modeHandler = undefined; - } - } - }; + this.options = telemetryObjects.length > 1 ? + [ OVERLAID, STACKED ] : [ OVERLAID ]; + this.mode = this.options[0]; // Initial selection (overlaid) + this.telemetryObjects = telemetryObjects; + this.subPlotFactory = subPlotFactory; } + /** + * Get a handler for the current mode. This will handle + * plotting telemetry, providing subplots for the template, + * and view-level interactions with pan-zoom state. + * @returns {PlotOverlayMode|PlotStackMode} a handler + * for the current mode + */ + PlotModeOptions.prototype.getModeHandler = function () { + // Lazily initialize + if (!this.modeHandler) { + this.modeHandler = new this.mode.Constructor( + this.telemetryObjects, + this.subPlotFactory + ); + } + return this.modeHandler; + }; + + /** + * Get all mode options available for each plot. Each + * mode contains a `name` and `glyph` field suitable + * for display in a template. + * @return {Array} the available modes + */ + PlotModeOptions.prototype.getModeOptions = function () { + return this.options; + }; + + /** + * Get the plotting mode option currently in use. + * This will be one of the elements returned from + * `getModeOptions`. + * @return {*} the current mode + */ + PlotModeOptions.prototype.getMode = function () { + return this.mode; + }; + + /** + * Set the plotting mode option to use. + * The passed argument must be one of the options + * returned by `getModeOptions`. + * @param {object} option one of the plot mode options + * from `getModeOptions` + */ + PlotModeOptions.prototype.setMode = function (option) { + if (this.mode !== option) { + this.mode = option; + // Clear the existing mode handler, so it + // can be instantiated next time it's needed. + this.modeHandler = undefined; + } + }; + + return PlotModeOptions; } ); diff --git a/platform/features/plot/src/modes/PlotOverlayMode.js b/platform/features/plot/src/modes/PlotOverlayMode.js index 6baad8a546..809d800ef2 100644 --- a/platform/features/plot/src/modes/PlotOverlayMode.js +++ b/platform/features/plot/src/modes/PlotOverlayMode.js @@ -31,81 +31,59 @@ define( * is one sub-plot which contains all plotted objects. * @memberof platform/features/plot * @constructor + * @implements {platform/features/plot.PlotModeHandler} * @param {DomainObject[]} the domain objects to be plotted */ function PlotOverlayMode(telemetryObjects, subPlotFactory) { - var domainOffset, - panZoomStack = new PlotPanZoomStack([], []), - subplot = subPlotFactory.createSubPlot( - telemetryObjects, - panZoomStack - ), - subplots = [ subplot ]; + this.panZoomStack = new PlotPanZoomStack([], []); + this.subplot = subPlotFactory.createSubPlot( + telemetryObjects, + this.panZoomStack + ); + this.subplots = [ this.subplot ]; + } - function plotTelemetry(prepared) { - // Fit to the boundaries of the data, but don't - // override any user-initiated pan-zoom changes. - panZoomStack.setBasePanZoom( - prepared.getOrigin(), - prepared.getDimensions() - ); + PlotOverlayMode.prototype.plotTelemetry = function (updater) { + // Fit to the boundaries of the data, but don't + // override any user-initiated pan-zoom changes. + this.panZoomStack.setBasePanZoom( + updater.getOrigin(), + updater.getDimensions() + ); - // Track the domain offset, used to bias domain values - // to minimize loss of precision when converted to 32-bit - // floating point values for display. - subplot.setDomainOffset(prepared.getDomainOffset()); + // Track the domain offset, used to bias domain values + // to minimize loss of precision when converted to 32-bit + // floating point values for display. + this.subplot.setDomainOffset(updater.getDomainOffset()); - // Draw the buffers. Select color by index. - subplot.getDrawingObject().lines = prepared.getLineBuffers().map(function (buf, i) { + // Draw the buffers. Select color by index. + this.subplot.getDrawingObject().lines = + updater.getLineBuffers().map(function (buf, i) { return { buffer: buf.getBuffer(), color: PlotPalette.getFloatColor(i), points: buf.getLength() }; }); - } + }; - return { - /** - * Plot telemetry to the sub-plot(s) managed by this mode. - * @param {PlotPreparer} prepared the prepared data to plot - * @memberof platform/features/plot.PlotOverlayMode# - */ - plotTelemetry: plotTelemetry, - /** - * Get all sub-plots to be displayed in this mode; used - * to populate the plot template. - * @return {SubPlot[]} all sub-plots to display in this mode - * @memberof platform/features/plot.PlotOverlayMode# - */ - getSubPlots: function () { - return subplots; - }, - /** - * Check if we are not in our base pan-zoom state (that is, - * there are some temporary user modifications to the - * current pan-zoom state.) - * @returns {boolean} true if not in the base pan-zoom state - * @memberof platform/features/plot.PlotOverlayMode# - */ - isZoomed: function () { - return panZoomStack.getDepth() > 1; - }, - /** - * Undo the most recent pan/zoom change and restore - * the prior state. - * @memberof platform/features/plot.PlotOverlayMode# - */ - stepBackPanZoom: function () { - panZoomStack.popPanZoom(); - subplot.update(); - }, - unzoom: function () { - panZoomStack.clearPanZoom(); - subplot.update(); - } - }; - } + PlotOverlayMode.prototype.getSubPlots = function () { + return this.subplots; + }; + + PlotOverlayMode.prototype.isZoomed = function () { + return this.panZoomStack.getDepth() > 1; + }; + + PlotOverlayMode.prototype.stepBackPanZoom = function () { + this.panZoomStack.popPanZoom(); + this.subplot.update(); + }; + + PlotOverlayMode.prototype.unzoom = function () { + this.panZoomStack.clearPanZoom(); + this.subplot.update(); + }; return PlotOverlayMode; } diff --git a/platform/features/plot/src/modes/PlotStackMode.js b/platform/features/plot/src/modes/PlotStackMode.js index c64f3fe286..b20e9b9e32 100644 --- a/platform/features/plot/src/modes/PlotStackMode.js +++ b/platform/features/plot/src/modes/PlotStackMode.js @@ -31,99 +31,76 @@ define( * is one sub-plot for each plotted object. * @memberof platform/features/plot * @constructor + * @implements {platform/features/plot.PlotModeHandler} * @param {DomainObject[]} the domain objects to be plotted */ function PlotStackMode(telemetryObjects, subPlotFactory) { - var domainOffset, - panZoomStackGroup = - new PlotPanZoomStackGroup(telemetryObjects.length), - subplots = telemetryObjects.map(function (telemetryObject, i) { + var self = this; + + this.panZoomStackGroup = + new PlotPanZoomStackGroup(telemetryObjects.length); + + this.subplots = telemetryObjects.map(function (telemetryObject, i) { return subPlotFactory.createSubPlot( [telemetryObject], - panZoomStackGroup.getPanZoomStack(i) + self.panZoomStackGroup.getPanZoomStack(i) ); }); - - function plotTelemetryTo(subplot, prepared, index) { - var buffer = prepared.getLineBuffers()[index]; - - // Track the domain offset, used to bias domain values - // to minimize loss of precision when converted to 32-bit - // floating point values for display. - subplot.setDomainOffset(prepared.getDomainOffset()); - - // Draw the buffers. Always use the 0th color, because there - // is one line per plot. - subplot.getDrawingObject().lines = [{ - buffer: buffer.getBuffer(), - color: PlotPalette.getFloatColor(0), - points: buffer.getLength() - }]; - } - - function plotTelemetry(prepared) { - // Fit to the boundaries of the data, but don't - // override any user-initiated pan-zoom changes. - panZoomStackGroup.setBasePanZoom( - prepared.getOrigin(), - prepared.getDimensions() - ); - - subplots.forEach(function (subplot, index) { - plotTelemetryTo(subplot, prepared, index); - }); - } - - return { - /** - * Plot telemetry to the sub-plot(s) managed by this mode. - * @param {PlotPreparer} prepared the prepared data to plot - * @memberof platform/features/plot.PlotStackMode# - */ - plotTelemetry: plotTelemetry, - /** - * Get all sub-plots to be displayed in this mode; used - * to populate the plot template. - * @return {SubPlot[]} all sub-plots to display in this mode - * @memberof platform/features/plot.PlotStackMode# - */ - getSubPlots: function () { - return subplots; - }, - /** - * Check if we are not in our base pan-zoom state (that is, - * there are some temporary user modifications to the - * current pan-zoom state.) - * @returns {boolean} true if not in the base pan-zoom state - * @memberof platform/features/plot.PlotStackMode# - */ - isZoomed: function () { - return panZoomStackGroup.getDepth() > 1; - }, - /** - * Undo the most recent pan/zoom change and restore - * the prior state. - * @memberof platform/features/plot.PlotStackMode# - */ - stepBackPanZoom: function () { - panZoomStackGroup.popPanZoom(); - subplots.forEach(function (subplot) { - subplot.update(); - }); - }, - /** - * Undo all pan/zoom changes and restore the initial state. - * @memberof platform/features/plot.PlotStackMode# - */ - unzoom: function () { - panZoomStackGroup.clearPanZoom(); - subplots.forEach(function (subplot) { - subplot.update(); - }); - } - }; } + PlotStackMode.prototype.plotTelemetryTo = function (subplot, prepared, index) { + var buffer = prepared.getLineBuffers()[index]; + + // Track the domain offset, used to bias domain values + // to minimize loss of precision when converted to 32-bit + // floating point values for display. + subplot.setDomainOffset(prepared.getDomainOffset()); + + // Draw the buffers. Always use the 0th color, because there + // is one line per plot. + subplot.getDrawingObject().lines = [{ + buffer: buffer.getBuffer(), + color: PlotPalette.getFloatColor(0), + points: buffer.getLength() + }]; + }; + + PlotStackMode.prototype.plotTelemetry = function (prepared) { + var self = this; + // Fit to the boundaries of the data, but don't + // override any user-initiated pan-zoom changes. + this.panZoomStackGroup.setBasePanZoom( + prepared.getOrigin(), + prepared.getDimensions() + ); + + this.subplots.forEach(function (subplot, index) { + self.plotTelemetryTo(subplot, prepared, index); + }); + }; + + PlotStackMode.prototype.getSubPlots = function () { + return this.subplots; + }; + + PlotStackMode.prototype.isZoomed = function () { + return this.panZoomStackGroup.getDepth() > 1; + }; + + PlotStackMode.prototype.stepBackPanZoom = function () { + this.panZoomStackGroup.popPanZoom(); + this.subplots.forEach(function (subplot) { + subplot.update(); + }); + }; + + PlotStackMode.prototype.unzoom = function () { + this.panZoomStackGroup.clearPanZoom(); + this.subplots.forEach(function (subplot) { + subplot.update(); + }); + }; + return PlotStackMode; } ); diff --git a/platform/features/plot/src/policies/PlotViewPolicy.js b/platform/features/plot/src/policies/PlotViewPolicy.js index 26a64c0101..1a2793aaa7 100644 --- a/platform/features/plot/src/policies/PlotViewPolicy.js +++ b/platform/features/plot/src/policies/PlotViewPolicy.js @@ -28,39 +28,38 @@ define( /** * Policy preventing the Plot view from being made available for * domain objects which have non-numeric telemetry. - * @implements {Policy} + * @implements {Policy.} * @constructor * @memberof platform/features/plot */ function PlotViewPolicy() { - function hasImageTelemetry(domainObject) { - var telemetry = domainObject && - domainObject.getCapability('telemetry'), - metadata = telemetry ? telemetry.getMetadata() : {}, - ranges = metadata.ranges || []; + } - // Generally, we want to allow Plot for telemetry-providing - // objects (most telemetry is plottable.) We only want to - // suppress this for telemetry which only has explicitly - // non-numeric values. - return ranges.length === 0 || ranges.some(function (range) { + function hasNumericTelemetry(domainObject) { + var telemetry = domainObject && + domainObject.getCapability('telemetry'), + metadata = telemetry ? telemetry.getMetadata() : {}, + ranges = metadata.ranges || []; + + // Generally, we want to allow Plot for telemetry-providing + // objects (most telemetry is plottable.) We only want to + // suppress this for telemetry which only has explicitly + // non-numeric values. + return ranges.length === 0 || ranges.some(function (range) { // Assume format is numeric if it is undefined // (numeric telemetry is the common case) return range.format === undefined || - range.format === 'number'; + range.format === 'number'; }); + } + + PlotViewPolicy.prototype.allow = function (view, domainObject) { + if (view.key === 'plot') { + return hasNumericTelemetry(domainObject); } - return { - allow: function (view, domainObject) { - if (view.key === 'plot') { - return hasImageTelemetry(domainObject); - } - - return true; - } - }; - } + return true; + }; return PlotViewPolicy; } diff --git a/platform/features/plot/test/PlotControllerSpec.js b/platform/features/plot/test/PlotControllerSpec.js index 32529b0f3d..e6c79b4e54 100644 --- a/platform/features/plot/test/PlotControllerSpec.js +++ b/platform/features/plot/test/PlotControllerSpec.js @@ -39,6 +39,12 @@ define( mockSeries, controller; + function bind(method, thisObj) { + return function () { + return method.apply(thisObj, arguments); + }; + } + beforeEach(function () { mockScope = jasmine.createSpyObj( @@ -196,13 +202,13 @@ define( }); it("allows plots to be updated", function () { - expect(controller.update).not.toThrow(); + expect(bind(controller.update, controller)).not.toThrow(); }); it("allows changing pan-zoom state", function () { - expect(controller.isZoomed).not.toThrow(); - expect(controller.stepBackPanZoom).not.toThrow(); - expect(controller.unzoom).not.toThrow(); + expect(bind(controller.isZoomed, controller)).not.toThrow(); + expect(bind(controller.stepBackPanZoom, controller)).not.toThrow(); + expect(bind(controller.unzoom, controller)).not.toThrow(); }); it("indicates if a request is pending", function () { From 6302eee17ee6cc36881249f17342dbfafe65f99a Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 13 Aug 2015 12:35:48 -0700 Subject: [PATCH 58/84] [Code Style] Use prototypes in Scrolling List bundle WTD-1482. --- .../features/scrolling/src/DomainColumn.js | 38 ++- platform/features/scrolling/src/NameColumn.js | 32 +-- .../features/scrolling/src/RangeColumn.js | 46 ++-- .../scrolling/src/ScrollingListController.js | 27 +- .../scrolling/src/ScrollingListPopulator.js | 237 +++++++++--------- 5 files changed, 189 insertions(+), 191 deletions(-) diff --git a/platform/features/scrolling/src/DomainColumn.js b/platform/features/scrolling/src/DomainColumn.js index 96df96f822..a55b4001d5 100644 --- a/platform/features/scrolling/src/DomainColumn.js +++ b/platform/features/scrolling/src/DomainColumn.js @@ -34,6 +34,7 @@ define( * (typically, timestamps.) Used by the ScrollingListController. * * @memberof platform/features/scrolling + * @implements {platform/features/scrolling.ScrollingColumn} * @constructor * @param domainMetadata an object with the machine- and human- * readable names for this domain (in `key` and `name` @@ -42,31 +43,22 @@ define( * formatting service, for making values human-readable. */ function DomainColumn(domainMetadata, telemetryFormatter) { - return { - /** - * Get the title to display in this column's header. - * @returns {string} the title to display - * @memberof platform/features/scrolling.DomainColumn# - */ - getTitle: function () { - return domainMetadata.name; - }, - /** - * Get the text to display inside a row under this - * column. - * @returns {string} the text to display - * @memberof platform/features/scrolling.DomainColumn# - */ - getValue: function (domainObject, datum) { - return { - text: telemetryFormatter.formatDomainValue( - datum[domainMetadata.key] - ) - }; - } - }; + this.domainMetadata = domainMetadata; + this.telemetryFormatter = telemetryFormatter; } + DomainColumn.prototype.getTitle = function () { + return this.domainMetadata.name; + }; + + DomainColumn.prototype.getValue = function (domainObject, datum) { + return { + text: this.telemetryFormatter.formatDomainValue( + datum[this.domainMetadata.key] + ) + }; + }; + return DomainColumn; } ); diff --git a/platform/features/scrolling/src/NameColumn.js b/platform/features/scrolling/src/NameColumn.js index e177f0ceca..8947b279f0 100644 --- a/platform/features/scrolling/src/NameColumn.js +++ b/platform/features/scrolling/src/NameColumn.js @@ -34,32 +34,22 @@ define( * which exposed specific telemetry values. * * @memberof platform/features/scrolling + * @implements {platform/features/scrolling.ScrollingColumn} * @constructor */ function NameColumn() { - return { - /** - * Get the title to display in this column's header. - * @returns {string} the title to display - * @memberof platform/features/scrolling.NameColumn# - */ - getTitle: function () { - return "Name"; - }, - /** - * Get the text to display inside a row under this - * column. This returns the domain object's name. - * @returns {string} the text to display - * @memberof platform/features/scrolling.NameColumn# - */ - getValue: function (domainObject) { - return { - text: domainObject.getModel().name - }; - } - }; } + NameColumn.prototype.getTitle = function () { + return "Name"; + }; + + NameColumn.prototype.getValue = function (domainObject) { + return { + text: domainObject.getModel().name + }; + }; + return NameColumn; } ); diff --git a/platform/features/scrolling/src/RangeColumn.js b/platform/features/scrolling/src/RangeColumn.js index 980ed5da39..637a68517d 100644 --- a/platform/features/scrolling/src/RangeColumn.js +++ b/platform/features/scrolling/src/RangeColumn.js @@ -34,6 +34,7 @@ define( * (typically, measurements.) Used by the ScrollingListController. * * @memberof platform/features/scrolling + * @implements {platform/features/scrolling.ScrollingColumn} * @constructor * @param rangeMetadata an object with the machine- and human- * readable names for this range (in `key` and `name` @@ -42,35 +43,26 @@ define( * formatting service, for making values human-readable. */ function RangeColumn(rangeMetadata, telemetryFormatter) { - return { - /** - * Get the title to display in this column's header. - * @returns {string} the title to display - * @memberof platform/features/scrolling.RangeColumn# - */ - getTitle: function () { - return rangeMetadata.name; - }, - /** - * Get the text to display inside a row under this - * column. - * @returns {string} the text to display - * @memberof platform/features/scrolling.RangeColumn# - */ - getValue: function (domainObject, datum) { - var range = rangeMetadata.key, - limit = domainObject.getCapability('limit'), - value = datum[range], - alarm = limit.evaluate(datum, range); - - return { - cssClass: alarm && alarm.cssClass, - text: telemetryFormatter.formatRangeValue(value) - }; - } - }; + this.rangeMetadata = rangeMetadata; + this.telemetryFormatter = telemetryFormatter; } + RangeColumn.prototype.getTitle = function () { + return this.rangeMetadata.name; + }; + + RangeColumn.prototype.getValue = function (domainObject, datum) { + var range = this.rangeMetadata.key, + limit = domainObject.getCapability('limit'), + value = datum[range], + alarm = limit.evaluate(datum, range); + + return { + cssClass: alarm && alarm.cssClass, + text: this.telemetryFormatter.formatRangeValue(value) + }; + }; + return RangeColumn; } ); diff --git a/platform/features/scrolling/src/ScrollingListController.js b/platform/features/scrolling/src/ScrollingListController.js index 0a179f6102..c6a9f48fd9 100644 --- a/platform/features/scrolling/src/ScrollingListController.js +++ b/platform/features/scrolling/src/ScrollingListController.js @@ -39,8 +39,6 @@ define( * @constructor */ function ScrollingListController($scope, formatter) { - var populator; - // Get a set of populated, ready-to-display rows for the // latest data values. @@ -129,6 +127,31 @@ define( $scope.$watch("telemetry.getMetadata()", setupColumns); } + /** + * A description of how to display a certain column of data in a + * Scrolling List view. + * @interface platform/features/scrolling.ScrollingColumn + * @private + */ + /** + * Get the title to display in this column's header. + * @returns {string} the title to display + * @method platform/features/scrolling.ScrollingColumn#getTitle + */ + /** + * Get the text to display inside a row under this + * column. + * @param {DomainObject} domainObject the domain object associated + * with this row + * @param {TelemetrySeries} series the telemetry data associated + * with this row + * @param {number} index the index of the telemetry datum associated + * with this row + * @returns {string} the text to display + * @method platform/features/scrolling.ScrollingColumn#getValue + */ + + return ScrollingListController; } ); diff --git a/platform/features/scrolling/src/ScrollingListPopulator.js b/platform/features/scrolling/src/ScrollingListPopulator.js index 058829bab0..b5995d65ba 100644 --- a/platform/features/scrolling/src/ScrollingListPopulator.js +++ b/platform/features/scrolling/src/ScrollingListPopulator.js @@ -35,84 +35,114 @@ define( * @param {Column[]} columns the columns to be populated */ function ScrollingListPopulator(columns) { - /** - * Look up the most recent values from a set of data objects. - * Returns an array of objects in the order in which data - * should be displayed; each element is an object with - * two properties: - * - * * objectIndex: The index of the domain object associated - * with the data point to be displayed in that - * row. - * * pointIndex: The index of the data point itself, within - * its data set. - * - * @param {Array} datas an array of the most recent - * data objects; expected to be in the same order - * as the domain objects provided at constructor - * @param {number} count the number of rows to provide - * @memberof platform/features/scrolling.ScrollingListPopulator# - */ - function getLatestDataValues(datas, count) { - var latest = [], - candidate, - candidateTime, - used = datas.map(function () { return 0; }); + this.columns = columns; + } - // This algorithm is O(nk) for n rows and k telemetry elements; - // one O(k) linear search for a max is made for each of n rows. - // This could be done in O(n lg k + k lg k), using a priority - // queue (where priority is max-finding) containing k initial - // values. For n rows, pop the max from the queue and replenish - // the queue with a value from the data at the same - // objectIndex, if available. - // But k is small, so this might not give an observable - // improvement in performance. + /** + * Look up the most recent values from a set of data objects. + * Returns an array of objects in the order in which data + * should be displayed; each element is an object with + * two properties: + * + * * objectIndex: The index of the domain object associated + * with the data point to be displayed in that + * row. + * * pointIndex: The index of the data point itself, within + * its data set. + * + * @param {Array} datas an array of the most recent + * data objects; expected to be in the same order + * as the domain objects provided at constructor + * @param {number} count the number of rows to provide + * @returns {Array} latest data values in display order + * @private + */ + function getLatestDataValues(datas, count) { + var latest = [], + candidate, + candidateTime, + used = datas.map(function () { return 0; }); - // Find the most recent unused data point (this will be used - // in a loop to find and the N most recent data points) - function findCandidate(data, i) { - var nextTime, - pointCount = data.getPointCount(), - pointIndex = pointCount - used[i] - 1; - if (data && pointIndex >= 0) { - nextTime = data.getDomainValue(pointIndex); - if (nextTime > candidateTime) { - candidateTime = nextTime; - candidate = { - objectIndex: i, - pointIndex: pointIndex - }; - } + // This algorithm is O(nk) for n rows and k telemetry elements; + // one O(k) linear search for a max is made for each of n rows. + // This could be done in O(n lg k + k lg k), using a priority + // queue (where priority is max-finding) containing k initial + // values. For n rows, pop the max from the queue and replenish + // the queue with a value from the data at the same + // objectIndex, if available. + // But k is small, so this might not give an observable + // improvement in performance. + + // Find the most recent unused data point (this will be used + // in a loop to find and the N most recent data points) + function findCandidate(data, i) { + var nextTime, + pointCount = data.getPointCount(), + pointIndex = pointCount - used[i] - 1; + if (data && pointIndex >= 0) { + nextTime = data.getDomainValue(pointIndex); + if (nextTime > candidateTime) { + candidateTime = nextTime; + candidate = { + objectIndex: i, + pointIndex: pointIndex + }; } } - - // Assemble a list of the most recent data points - while (latest.length < count) { - // Reset variables pre-search - candidateTime = Number.NEGATIVE_INFINITY; - candidate = undefined; - - // Linear search for most recent - datas.forEach(findCandidate); - - if (candidate) { - // Record this data point - it is the most recent - latest.push(candidate); - - // Track the data points used so we can look farther back - // in the data set on the next iteration - used[candidate.objectIndex] = used[candidate.objectIndex] + 1; - } else { - // Ran out of candidates; not enough data points - // available to fill all rows. - break; - } - } - - return latest; } + // Assemble a list of the most recent data points + while (latest.length < count) { + // Reset variables pre-search + candidateTime = Number.NEGATIVE_INFINITY; + candidate = undefined; + + // Linear search for most recent + datas.forEach(findCandidate); + + if (candidate) { + // Record this data point - it is the most recent + latest.push(candidate); + + // Track the data points used so we can look farther back + // in the data set on the next iteration + used[candidate.objectIndex] = used[candidate.objectIndex] + 1; + } else { + // Ran out of candidates; not enough data points + // available to fill all rows. + break; + } + } + + return latest; + } + + /** + * Get the text which should appear in headers for the + * provided columns. + * @returns {string[]} column headers + */ + ScrollingListPopulator.prototype.getHeaders = function () { + return this.columns.map(function (column) { + return column.getTitle(); + }); + }; + + /** + * Get the contents of rows for the scrolling list view. + * @param {TelemetrySeries[]} datas the data sets + * @param {DomainObject[]} objects the domain objects which + * provided the data sets; these should match + * index-to-index with the `datas` argument + * @param {number} count the number of rows to populate + * @returns {string[][]} an array of rows, each of which + * is an array of values which should appear + * in that row + */ + ScrollingListPopulator.prototype.getRows = function (datas, objects, count) { + var values = getLatestDataValues(datas, count), + self = this; + // From a telemetry series, retrieve a single data point // containing all fields for domains/ranges function makeDatum(domainObject, series, index) { @@ -133,53 +163,24 @@ define( return result; } - return { - /** - * Get the text which should appear in headers for the - * provided columns. - * @returns {string[]} column headers - * @memberof platform/features/scrolling.ScrollingListPopulator# - */ - getHeaders: function () { - return columns.map(function (column) { - return column.getTitle(); - }); - }, - /** - * Get the contents of rows for the scrolling list view. - * @param {TelemetrySeries[]} datas the data sets - * @param {DomainObject[]} objects the domain objects which - * provided the data sets; these should match - * index-to-index with the `datas` argument - * @param {number} count the number of rows to populate - * @returns {string[][]} an array of rows, each of which - * is an array of values which should appear - * in that row - * @memberof platform/features/scrolling.ScrollingListPopulator# - */ - getRows: function (datas, objects, count) { - var values = getLatestDataValues(datas, count); + // Each value will become a row, which will contain + // some value in each column (rendering by the + // column object itself) + return values.map(function (value) { + var datum = makeDatum( + objects[value.objectIndex], + datas[value.objectIndex], + value.pointIndex + ); - // Each value will become a row, which will contain - // some value in each column (rendering by the - // column object itself) - return values.map(function (value) { - var datum = makeDatum( - objects[value.objectIndex], - datas[value.objectIndex], - value.pointIndex - ); - - return columns.map(function (column) { - return column.getValue( - objects[value.objectIndex], - datum - ); - }); - }); - } - }; - } + return self.columns.map(function (column) { + return column.getValue( + objects[value.objectIndex], + datum + ); + }); + }); + }; return ScrollingListPopulator; From 1c187c3914e9b64edcfa6526e7563953e3cc7c3f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 13 Aug 2015 14:44:27 -0700 Subject: [PATCH 59/84] [Code Style] Begin refactoring forms bundle WTD-1482 --- platform/forms/src/controllers/ColorController.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/platform/forms/src/controllers/ColorController.js b/platform/forms/src/controllers/ColorController.js index 6c1db4fed1..e85fbe97d2 100644 --- a/platform/forms/src/controllers/ColorController.js +++ b/platform/forms/src/controllers/ColorController.js @@ -83,20 +83,16 @@ define( GROUPS.push(group); } - - function ColorController() { if (GROUPS.length === 0) { initializeGroups(); } - - return { - groups: function () { - return GROUPS; - } - }; } + ColorController.prototype.groups = function () { + return GROUPS; + }; + return ColorController; } ); From 7fe866060be7abe6ca3fa14714fd1796ca9f44d0 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 14 Aug 2015 13:40:33 -0700 Subject: [PATCH 60/84] [Code Style] Use prototypes in forms bundle WTD-1482. --- .../scrolling/src/ScrollingListController.js | 1 + .../forms/src/controllers/ColorController.js | 7 ++++ .../src/controllers/CompositeController.js | 41 ++++++++----------- .../src/controllers/DialogButtonController.js | 38 ++++++++--------- 4 files changed, 42 insertions(+), 45 deletions(-) diff --git a/platform/features/scrolling/src/ScrollingListController.js b/platform/features/scrolling/src/ScrollingListController.js index c6a9f48fd9..7ca6312369 100644 --- a/platform/features/scrolling/src/ScrollingListController.js +++ b/platform/features/scrolling/src/ScrollingListController.js @@ -39,6 +39,7 @@ define( * @constructor */ function ScrollingListController($scope, formatter) { + var populator = new ScrollingListPopulator([]); // Get a set of populated, ready-to-display rows for the // latest data values. diff --git a/platform/forms/src/controllers/ColorController.js b/platform/forms/src/controllers/ColorController.js index e85fbe97d2..62640364df 100644 --- a/platform/forms/src/controllers/ColorController.js +++ b/platform/forms/src/controllers/ColorController.js @@ -89,6 +89,13 @@ define( } } + /** + * Get groups of colors to display in a color picker. These are + * given as #-prefixed color strings, in a two-dimensional array. + * Each element of the array is a group of related colors (e.g. + * grayscale colors, web colors, gradients...) + * @returns {string[][]} groups of colors + */ ColorController.prototype.groups = function () { return GROUPS; }; diff --git a/platform/forms/src/controllers/CompositeController.js b/platform/forms/src/controllers/CompositeController.js index e3a0559d09..506fbb6f4e 100644 --- a/platform/forms/src/controllers/CompositeController.js +++ b/platform/forms/src/controllers/CompositeController.js @@ -39,32 +39,25 @@ define( * @constructor */ function CompositeController() { - // Check if an element is defined; the map step of isNonEmpty - function isDefined(element) { - return typeof element !== 'undefined'; - } - - // Boolean or; the reduce step of isNonEmpty - function or(a, b) { - return a || b; - } - - return { - /** - * Check if an array contains anything other than - * undefined elements. - * @param {Array} value the array to check - * @returns {boolean} true if any non-undefined - * element is in the array - * @memberof platform/forms.CompositeController# - */ - isNonEmpty: function (value) { - return Array.isArray(value) && - value.map(isDefined).reduce(or, false); - } - }; } + // Check if an element is defined; the map step of isNonEmpty + function isDefined(element) { + return typeof element !== 'undefined'; + } + + /** + * Check if an array contains anything other than + * undefined elements. + * @param {Array} value the array to check + * @returns {boolean} true if any non-undefined + * element is in the array + * @memberof platform/forms.CompositeController# + */ + CompositeController.prototype.isNonEmpty = function (value) { + return Array.isArray(value) && value.some(isDefined); + }; + return CompositeController; } diff --git a/platform/forms/src/controllers/DialogButtonController.js b/platform/forms/src/controllers/DialogButtonController.js index afb0e54391..2c440dead1 100644 --- a/platform/forms/src/controllers/DialogButtonController.js +++ b/platform/forms/src/controllers/DialogButtonController.js @@ -36,9 +36,8 @@ define( * for user input */ function DialogButtonController($scope, dialogService) { - var buttonStructure, - buttonForm, - field; + var self = this, + buttonForm; // Store the result of user input to the model function storeResult(result) { @@ -65,11 +64,11 @@ define( row.key = $scope.field; // Prepare the structure for the button itself - buttonStructure = {}; - buttonStructure.glyph = structure.glyph; - buttonStructure.name = structure.name; - buttonStructure.description = structure.description; - buttonStructure.click = showDialog; + self.buttonStructure = {}; + self.buttonStructure.glyph = structure.glyph; + self.buttonStructure.name = structure.name; + self.buttonStructure.description = structure.description; + self.buttonStructure.click = showDialog; // Prepare the form; a single row buttonForm = { @@ -79,21 +78,18 @@ define( } $scope.$watch('structure', refreshStructure); - - return { - /** - * Get the structure for an `mct-control` of type - * `button`; a dialog will be launched when this button - * is clicked. - * @returns dialog structure - * @memberof platform/forms.DialogButtonController# - */ - getButtonStructure: function () { - return buttonStructure; - } - }; } + /** + * Get the structure for an `mct-control` of type + * `button`; a dialog will be launched when this button + * is clicked. + * @returns dialog structure + */ + DialogButtonController.prototype.getButtonStructure = function () { + return this.buttonStructure; + }; + return DialogButtonController; } ); From edca2a9f031c7421c4b155a74261bd3845a72b53 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 14 Aug 2015 14:42:25 -0700 Subject: [PATCH 61/84] [Code Style] Use prototypes in framework layer WTD-1482 --- .../framework/src/FrameworkInitializer.js | 36 ++- platform/framework/src/LogLevel.js | 62 ++-- .../src/bootstrap/ApplicationBootstrapper.js | 36 ++- platform/framework/src/load/Bundle.js | 265 ++++++++------- platform/framework/src/load/BundleLoader.js | 51 ++- platform/framework/src/load/Extension.js | 171 +++++----- .../src/register/CustomRegistrars.js | 302 +++++++++++------- .../src/register/ExtensionRegistrar.js | 107 ++++--- .../framework/src/register/ExtensionSorter.js | 34 +- .../src/register/ServiceCompositor.js | 60 ++-- .../framework/src/resolve/BundleResolver.js | 48 +-- .../src/resolve/ExtensionResolver.js | 70 ++-- .../src/resolve/ImplementationLoader.js | 42 ++- .../src/resolve/RequireConfigurator.js | 142 ++++---- 14 files changed, 750 insertions(+), 676 deletions(-) diff --git a/platform/framework/src/FrameworkInitializer.js b/platform/framework/src/FrameworkInitializer.js index a0db162f01..add6846e9f 100644 --- a/platform/framework/src/FrameworkInitializer.js +++ b/platform/framework/src/FrameworkInitializer.js @@ -40,24 +40,36 @@ define( * * @memberof platform/framework * @constructor - * @param {BundleLoader} loader - * @param {BundleResolver} resolver - * @param {ExtensionRegistrar} registrar - * @param {ApplicationBootstrapper} bootstrapper + * @param {platform/framework.BundleLoader} loader + * @param {platform/framework.BundleResolver} resolver + * @param {platform/framework.ExtensionRegistrar} registrar + * @param {platform/framework.ApplicationBootstrapper} bootstrapper */ function FrameworkInitializer(loader, resolver, registrar, bootstrapper) { + this.loader = loader; + this.resolver = resolver; + this.registrar = registrar; + this.bootstrapper = bootstrapper; + } - return { - runApplication: function (bundleList) { - return loader.loadBundles(bundleList) - .then(resolver.resolveBundles) - .then(registrar.registerExtensions) - .then(bootstrapper.bootstrap); - } - + function bind(method, thisArg) { + return function () { + return method.apply(thisArg, arguments); }; } + /** + * Run the application defined by this set of bundles. + * @param bundleList + * @returns {*} + */ + FrameworkInitializer.prototype.runApplication = function (bundleList) { + return this.loader.loadBundles(bundleList) + .then(bind(this.resolver.resolveBundles, this.resolver)) + .then(bind(this.registrar.registerExtensions, this.registrar)) + .then(bind(this.bootstrapper.bootstrap, this.bootstrapper)); + }; + return FrameworkInitializer; } ); diff --git a/platform/framework/src/LogLevel.js b/platform/framework/src/LogLevel.js index 1c54659ff6..973811ca07 100644 --- a/platform/framework/src/LogLevel.js +++ b/platform/framework/src/LogLevel.js @@ -53,7 +53,29 @@ define( */ function LogLevel(level) { // Find the numeric level associated with the string - var index = LOG_LEVELS.indexOf(level); + this.index = LOG_LEVELS.indexOf(level); + + // Default to 'warn' level if unspecified + if (this.index < 0) { + this.index = 1; + } + } + + /** + * Configure logging to suppress log output if it is + * not of an appropriate level. Both the Angular app + * being initialized and a reference to `$log` should be + * passed; the former is used to configure application + * logging, while the latter is needed to apply the + * same configuration during framework initialization + * (since the framework also logs.) + * + * @param app the Angular app to configure + * @param $log Angular's $log (also configured) + * @memberof platform/framework.LogLevel# + */ + LogLevel.prototype.configure = function (app, $log) { + var index = this.index; // Replace logging methods with no-ops, if they are // not of an appropriate level. @@ -67,36 +89,14 @@ define( }); } - // Default to 'warn' level if unspecified - if (index < 0) { - index = 1; - } - - return { - /** - * Configure logging to suppress log output if it is - * not of an appropriate level. Both the Angular app - * being initialized and a reference to `$log` should be - * passed; the former is used to configure application - * logging, while the latter is needed to apply the - * same configuration during framework initialization - * (since the framework also logs.) - * - * @param app the Angular app to configure - * @param $log Angular's $log (also configured) - * @memberof platform/framework.LogLevel# - */ - configure: function (app, $log) { - decorate($log); - app.config(function ($provide) { - $provide.decorator('$log', function ($delegate) { - decorate($delegate); - return $delegate; - }); - }); - } - }; - } + decorate($log); + app.config(function ($provide) { + $provide.decorator('$log', function ($delegate) { + decorate($delegate); + return $delegate; + }); + }); + }; return LogLevel; } diff --git a/platform/framework/src/bootstrap/ApplicationBootstrapper.js b/platform/framework/src/bootstrap/ApplicationBootstrapper.js index 82b1714e31..f191bbbdaa 100644 --- a/platform/framework/src/bootstrap/ApplicationBootstrapper.js +++ b/platform/framework/src/bootstrap/ApplicationBootstrapper.js @@ -42,25 +42,27 @@ define( * @constructor */ function ApplicationBootstrapper(angular, document, $log) { - return { - /** - * Bootstrap the application. - * - * @method - * @memberof ApplicationBootstrapper# - * @param {angular.Module} app the Angular application to - * bootstrap - * @memberof platform/framework.ApplicationBootstrapper# - */ - bootstrap: function (app) { - $log.info("Bootstrapping application " + (app || {}).name); - angular.element(document).ready(function () { - angular.bootstrap(document, [app.name]); - }); - } - }; + this.angular = angular; + this.document = document; + this.$log = $log; } + /** + * Bootstrap the application. + * + * @param {angular.Module} app the Angular application to + * bootstrap + */ + ApplicationBootstrapper.prototype.bootstrap = function (app) { + var angular = this.angular, + document = this.document, + $log = this.$log; + $log.info("Bootstrapping application " + (app || {}).name); + angular.element(document).ready(function () { + angular.bootstrap(document, [app.name]); + }); + }; + return ApplicationBootstrapper; } ); diff --git a/platform/framework/src/load/Bundle.js b/platform/framework/src/load/Bundle.js index 147ca01ef1..a53d2761fd 100644 --- a/platform/framework/src/load/Bundle.js +++ b/platform/framework/src/load/Bundle.js @@ -56,13 +56,7 @@ define( function Bundle(path, bundleDefinition) { // Start with defaults var definition = Object.create(Constants.DEFAULT_BUNDLE), - logName = path, - self; - - // Utility function for resolving paths in this bundle - function resolvePath(elements) { - return [path].concat(elements || []).join(Constants.SEPARATOR); - } + logName = path; // Override defaults with specifics from bundle definition Object.keys(bundleDefinition).forEach(function (k) { @@ -81,135 +75,138 @@ define( logName += ")"; } - self = { - /** - * Get the path to this bundle. - * @memberof Bundle# - * @returns {string} - * @memberof platform/framework.Bundle# - */ - getPath: function () { - return path; - }, - /** - * Get the path to this bundle's source folder. If an - * argument is provided, the path will be to the source - * file within the bundle's source file. - * - * @memberof Bundle# - * @param {string} [sourceFile] optionally, give a path to - * a specific source file in the bundle. - * @returns {string} - * @memberof platform/framework.Bundle# - */ - getSourcePath: function (sourceFile) { - var subpath = sourceFile ? - [ definition.sources, sourceFile ] : - [ definition.sources ]; - - return resolvePath(subpath); - }, - /** - * Get the path to this bundle's resource folder. If an - * argument is provided, the path will be to the resource - * file within the bundle's resource file. - * - * @memberof Bundle# - * @param {string} [resourceFile] optionally, give a path to - * a specific resource file in the bundle. - * @returns {string} - * @memberof platform/framework.Bundle# - */ - getResourcePath: function (resourceFile) { - var subpath = resourceFile ? - [ definition.resources, resourceFile ] : - [ definition.resources ]; - - return resolvePath(subpath); - }, - /** - * Get the path to this bundle's library folder. If an - * argument is provided, the path will be to the library - * file within the bundle's resource file. - * - * @memberof Bundle# - * @param {string} [libraryFile] optionally, give a path to - * a specific library file in the bundle. - * @returns {string} - * @memberof platform/framework.Bundle# - */ - getLibraryPath: function (libraryFile) { - var subpath = libraryFile ? - [ definition.libraries, libraryFile ] : - [ definition.libraries ]; - - return resolvePath(subpath); - }, - /** - * Get library configuration for this bundle. This is read - * from the bundle's definition; if the bundle is well-formed, - * it will resemble a require.config object. - * @memberof Bundle# - * @returns {object} - * @memberof platform/framework.Bundle# - */ - getConfiguration: function () { - return definition.configuration || {}; - }, - /** - * Get a log-friendly name for this bundle; this will - * include both the key (machine-readable name for this - * bundle) and the name (human-readable name for this - * bundle.) - * @returns {string} log-friendly name for this bundle - * @memberof platform/framework.Bundle# - */ - getLogName: function () { - return logName; - }, - /** - * Get all extensions exposed by this bundle of a given - * category. - * - * @param category - * @memberof Bundle# - * @returns {Array} - * @memberof platform/framework.Bundle# - */ - getExtensions: function (category) { - var extensions = definition.extensions[category] || []; - - return extensions.map(function objectify(extDefinition) { - return new Extension(self, category, extDefinition); - }); - }, - /** - * Get a list of all categories of extension exposed by - * this bundle. - * - * @memberof Bundle# - * @returns {Array} - * @memberof platform/framework.Bundle# - */ - getExtensionCategories: function () { - return Object.keys(definition.extensions); - }, - /** - * Get the plain definition of this bundle, as read from - * its JSON declaration. - * - * @memberof Bundle# - * @returns {BundleDefinition} the raw definition of this bundle - * @memberof platform/framework.Bundle# - */ - getDefinition: function () { - return definition; - } - }; - - return self; + this.path = path; + this.definition = definition; + this.logName = logName; } + + // Utility function for resolving paths in this bundle + Bundle.prototype.resolvePath = function (elements) { + var path = this.path; + return [path].concat(elements || []).join(Constants.SEPARATOR); + }; + + + /** + * Get the path to this bundle. + * @returns {string} path to this bundle; + */ + Bundle.prototype.getPath = function () { + return this.path; + }; + + /** + * Get the path to this bundle's source folder. If an + * argument is provided, the path will be to the source + * file within the bundle's source file. + * + * @param {string} [sourceFile] optionally, give a path to + * a specific source file in the bundle. + * @returns {string} path to the source folder (or to the + * source file within it) + */ + Bundle.prototype.getSourcePath = function (sourceFile) { + var subpath = sourceFile ? + [ this.definition.sources, sourceFile ] : + [ this.definition.sources ]; + + return this.resolvePath(subpath); + }; + + /** + * Get the path to this bundle's resource folder. If an + * argument is provided, the path will be to the resource + * file within the bundle's resource file. + * + * @param {string} [resourceFile] optionally, give a path to + * a specific resource file in the bundle. + * @returns {string} path to the resource folder (or to the + * resource file within it) + */ + Bundle.prototype.getResourcePath = function (resourceFile) { + var subpath = resourceFile ? + [ this.definition.resources, resourceFile ] : + [ this.definition.resources ]; + + return this.resolvePath(subpath); + }; + + /** + * Get the path to this bundle's library folder. If an + * argument is provided, the path will be to the library + * file within the bundle's resource file. + * + * @param {string} [libraryFile] optionally, give a path to + * a specific library file in the bundle. + * @returns {string} path to the resource folder (or to the + * resource file within it) + */ + Bundle.prototype.getLibraryPath = function (libraryFile) { + var subpath = libraryFile ? + [ this.definition.libraries, libraryFile ] : + [ this.definition.libraries ]; + + return this.resolvePath(subpath); + }; + + /** + * Get library configuration for this bundle. This is read + * from the bundle's definition; if the bundle is well-formed, + * it will resemble a require.config object. + * @returns {object} library configuration + */ + Bundle.prototype.getConfiguration = function () { + return this.definition.configuration || {}; + }; + + /** + * Get a log-friendly name for this bundle; this will + * include both the key (machine-readable name for this + * bundle) and the name (human-readable name for this + * bundle.) + * @returns {string} log-friendly name for this bundle + */ + Bundle.prototype.getLogName = function () { + return this.logName; + }; + + /** + * Get all extensions exposed by this bundle of a given + * category. + * + * @param {string} category name of the extension category + * @returns {Array} extension definitions of that cataegory + */ + Bundle.prototype.getExtensions = function (category) { + var extensions = this.definition.extensions[category] || [], + self = this; + + return extensions.map(function objectify(extDefinition) { + return new Extension(self, category, extDefinition); + }); + }; + + /** + * Get a list of all extension categories exposed by this bundle. + * + * @returns {string[]} the extension categories + */ + Bundle.prototype.getExtensionCategories = function () { + return Object.keys(this.definition.extensions); + }; + + /** + * Get the plain definition of this bundle, as read from + * its JSON declaration. + * + * @returns {platform/framework.BundleDefinition} the raw + * definition of this bundle + */ + Bundle.prototype.getDefinition = function () { + return this.definition; + }; + return Bundle; } ); diff --git a/platform/framework/src/load/BundleLoader.js b/platform/framework/src/load/BundleLoader.js index 34f70b2502..14b404f195 100644 --- a/platform/framework/src/load/BundleLoader.js +++ b/platform/framework/src/load/BundleLoader.js @@ -41,10 +41,26 @@ define( * * @memberof platform/framework * @constructor - * @param {object} $http Angular's HTTP requester - * @param {object} $log Angular's logging service + * @param $http Angular's HTTP requester + * @param $log Angular's logging service */ function BundleLoader($http, $log) { + this.$http = $http; + this.$log = $log; + + } + + /** + * Load a group of bundles, to be used to constitute the + * application by later framework initialization phases. + * + * @param {string|string[]} an array of bundle names to load, or + * the name of a JSON file containing that array + * @returns {Promise.} a promise for the loaded bundles + */ + BundleLoader.prototype.loadBundles = function (bundles) { + var $http = this.$http, + $log = this.$log; // Utility function; load contents of JSON file using $http function getJSON(file) { @@ -92,7 +108,7 @@ define( var bundlePromises = bundleArray.map(loadBundle); return Promise.all(bundlePromises) - .then(filterBundles); + .then(filterBundles); } // Load all bundles named in the referenced file. The file is @@ -101,31 +117,10 @@ define( return getJSON(listFile).then(loadBundlesFromArray); } - // Load all indicated bundles. If the argument is an array, - // this is taken to be a list of all bundles to load; if it - // is a string, then it is treated as the name of a JSON - // file containing the list of bundles to load. - function loadBundles(bundles) { - return Array.isArray(bundles) ? loadBundlesFromArray(bundles) : - (typeof bundles === 'string') ? loadBundlesFromFile(bundles) : - Promise.reject(new Error(INVALID_ARGUMENT_MESSAGE)); - } - - - return { - /** - * Load a group of bundles, to be used to constitute the - * application by later framework initialization phases. - * - * @memberof BundleLoader# - * @param {string|string[]} an array of bundle names to load, or - * the name of a JSON file containing that array - * @returns {Promise.} - * @memberof platform/framework.BundleLoader# - */ - loadBundles: loadBundles - }; - } + return Array.isArray(bundles) ? loadBundlesFromArray(bundles) : + (typeof bundles === 'string') ? loadBundlesFromFile(bundles) : + Promise.reject(new Error(INVALID_ARGUMENT_MESSAGE)); + }; return BundleLoader; } diff --git a/platform/framework/src/load/Extension.js b/platform/framework/src/load/Extension.js index 7a2d46ae7b..d3b19f94fa 100644 --- a/platform/framework/src/load/Extension.js +++ b/platform/framework/src/load/Extension.js @@ -78,94 +78,93 @@ define( // Attach bundle metadata extensionDefinition.bundle = bundle.getDefinition(); - return { - /** - * Get the machine-readable identifier for this extension. - * - * @returns {string} - * @memberof platform/framework.Extension# - */ - getKey: function () { - return definition.key || "undefined"; - }, - /** - * Get the bundle which declared this extension. - * - * @memberof Extension# - * @returns {Bundle} - * @memberof platform/framework.Extension# - */ - getBundle: function () { - return bundle; - }, - /** - * Get the category into which this extension falls. - * (e.g. "directives") - * - * @memberof Extension# - * @returns {string} - * @memberof platform/framework.Extension# - */ - getCategory: function () { - return category; - }, - /** - * Check whether or not this extension should have an - * associated implementation module which may need to - * be loaded. - * - * @returns {boolean} true if an implementation separate - * from this definition should also be loaded - * @memberof platform/framework.Extension# - */ - hasImplementation: function () { - return definition.implementation !== undefined; - }, - /** - * Get the path to the AMD module which implements this - * extension. Will return undefined if there is no - * implementation associated with this extension. - * - * @memberof Extension# - * @returns {string} path to implementation, or undefined - * @memberof platform/framework.Extension# - */ - getImplementationPath: function () { - return definition.implementation ? - bundle.getSourcePath(definition.implementation) : - undefined; - }, - /** - * Get a log-friendly name for this extension; this will - * include both the key (machine-readable name for this - * extension) and the name (human-readable name for this - * extension.) - * @returns {string} log-friendly name for this extension - * @memberof platform/framework.Extension# - */ - getLogName: function () { - return logName; - }, - /** - * Get the plain definition of the extension. - * - * Note that this definition will have an additional "bundle" - * field which points back to the bundle which defined the - * extension, as a convenience. - * - * @memberof Extension# - * @returns {ExtensionDefinition} the plain definition of - * this extension, as read from the bundle - * declaration. - * @memberof platform/framework.Extension# - */ - getDefinition: function () { - return extensionDefinition; - } - - }; + this.logName = logName; + this.bundle = bundle; + this.category = category; + this.definition = definition; + this.extensionDefinition = extensionDefinition; } + /** + * Get the machine-readable identifier for this extension. + * + * @returns {string} the identifier for this extension + */ + Extension.prototype.getKey = function () { + return this.definition.key || "undefined"; + }; + + /** + * Get the bundle which declared this extension. + * + * @returns {Bundle} the declaring bundle + */ + Extension.prototype.getBundle = function () { + return this.bundle; + }; + + /** + * Get the category into which this extension falls. + * (e.g. "directives") + * + * @returns {string} the extension category + */ + Extension.prototype.getCategory = function () { + return this.category; + }; + + /** + * Check whether or not this extension should have an + * associated implementation module which may need to + * be loaded. + * + * @returns {boolean} true if an implementation separate + * from this definition should also be loaded + */ + Extension.prototype.hasImplementation = function () { + return this.definition.implementation !== undefined; + }; + + /** + * Get the path to the AMD module which implements this + * extension. Will return undefined if there is no + * implementation associated with this extension. + * + * @returns {string} path to implementation, or undefined + */ + Extension.prototype.getImplementationPath = function () { + return this.definition.implementation ? + this.bundle.getSourcePath(this.definition.implementation) : + undefined; + }; + + /** + * Get a log-friendly name for this extension; this will + * include both the key (machine-readable name for this + * extension) and the name (human-readable name for this + * extension.) + * + * @returns {string} log-friendly name for this extension + */ + Extension.prototype.getLogName = function () { + return this.logName; + }; + + /** + * Get the plain definition of the extension. + * + * Note that this definition will have an additional "bundle" + * field which points back to the bundle which defined the + * extension, as a convenience. + * + * @returns {ExtensionDefinition} the plain definition of + * this extension, as read from the bundle + * declaration. + */ + Extension.prototype.getDefinition = function () { + return this.extensionDefinition; + }; + return Extension; } diff --git a/platform/framework/src/register/CustomRegistrars.js b/platform/framework/src/register/CustomRegistrars.js index c9d40dd0ab..04c3bbce7a 100644 --- a/platform/framework/src/register/CustomRegistrars.js +++ b/platform/framework/src/register/CustomRegistrars.js @@ -37,131 +37,191 @@ define( * @constructor */ function CustomRegistrars(app, $log) { + this.app = app; + this.$log = $log; + } - // Used to create custom registration functions which map to - // named methods on Angular modules, which follow the normal - // app.method(key, [ deps..., function ]) pattern. - function CustomRegistrar(angularFunction) { - return function (extension, index) { - var key = extension.key, - dependencies = extension.depends || []; - - if (!key) { - $log.warn([ - "Cannot register ", - angularFunction, - " ", - index, - ", no key specified. ", - JSON.stringify(extension) - ].join("")); - } else { - $log.info([ - "Registering ", - angularFunction, - ": ", - key - ].join("")); - app[angularFunction]( - key, - dependencies.concat([extension]) - ); - } - }; - } - - function registerConstant(extension) { - var key = extension.key, - value = extension.value; - - if (typeof key === "string" && value !== undefined) { - $log.info([ - "Registering constant: ", - key, - " with value ", - value - ].join("")); - app.constant(key, value); - } else { - $log.warn([ - "Cannot register constant ", - key, - " with value ", - value - ].join("")); - } - - } - - // Custom registration function for extensions of category "runs" - function registerRun(extension) { - if (typeof extension === 'function') { - // Prepend dependencies, and schedule to run - app.run((extension.depends || []).concat([extension])); - } else { - // If it's not a function, no implementation was given - $log.warn([ - "Cannot register run extension from ", - (extension.bundle || {}).path, - "; no implementation." - ].join("")); - } - } - - // Custom registration function for extensions of category "route" - function registerRoute(extension) { - var route = Object.create(extension); - - // Adjust path for bundle - if (route.templateUrl) { - route.templateUrl = [ - route.bundle.path, - route.bundle.resources, - route.templateUrl - ].join(Constants.SEPARATOR); - } - - // Log the registration - $log.info("Registering route: " + (route.key || route.when)); - - // Register the route with Angular - app.config(['$routeProvider', function ($routeProvider) { - if (route.when) { - $routeProvider.when(route.when, route); - } else { - $routeProvider.otherwise(route); - } - }]); - } - - // Handle service compositing - function registerComponents(components) { - return new ServiceCompositor(app, $log) - .registerCompositeServices(components); - } - - // Utility; create a function which converts another function - // (which acts on single objects) to one which acts upon arrays. - function mapUpon(func) { - return function (array) { - return array.map(func); - }; - } - - // More like key-value pairs than methods; key is the - // name of the extension category to be handled, and the value - // is the function which handles it. - return { - constants: mapUpon(registerConstant), - routes: mapUpon(registerRoute), - directives: mapUpon(new CustomRegistrar("directive")), - controllers: mapUpon(new CustomRegistrar("controller")), - services: mapUpon(new CustomRegistrar("service")), - runs: mapUpon(registerRun), - components: registerComponents + // Utility; bind a function to a "this" pointer + function bind(fn, thisArg) { + return function () { + return fn.apply(thisArg, arguments); }; } + // Used to create custom registration functions which map to + // named methods on Angular modules, which follow the normal + // app.method(key, [ deps..., function ]) pattern. + function customRegistrar(angularFunction) { + return function (extension, index) { + var app = this.app, + $log = this.$log, + key = extension.key, + dependencies = extension.depends || []; + + if (!key) { + $log.warn([ + "Cannot register ", + angularFunction, + " ", + index, + ", no key specified. ", + JSON.stringify(extension) + ].join("")); + } else { + $log.info([ + "Registering ", + angularFunction, + ": ", + key + ].join("")); + app[angularFunction]( + key, + dependencies.concat([extension]) + ); + } + }; + } + + function registerConstant(extension) { + var app = this.app, + $log = this.$log, + key = extension.key, + value = extension.value; + + if (typeof key === "string" && value !== undefined) { + $log.info([ + "Registering constant: ", + key, + " with value ", + value + ].join("")); + app.constant(key, value); + } else { + $log.warn([ + "Cannot register constant ", + key, + " with value ", + value + ].join("")); + } + + } + + // Custom registration function for extensions of category "runs" + function registerRun(extension) { + var app = this.app, + $log = this.$log; + + if (typeof extension === 'function') { + // Prepend dependencies, and schedule to run + app.run((extension.depends || []).concat([extension])); + } else { + // If it's not a function, no implementation was given + $log.warn([ + "Cannot register run extension from ", + (extension.bundle || {}).path, + "; no implementation." + ].join("")); + } + } + + // Custom registration function for extensions of category "route" + function registerRoute(extension) { + var app = this.app, + $log = this.$log, + route = Object.create(extension); + + // Adjust path for bundle + if (route.templateUrl) { + route.templateUrl = [ + route.bundle.path, + route.bundle.resources, + route.templateUrl + ].join(Constants.SEPARATOR); + } + + // Log the registration + $log.info("Registering route: " + (route.key || route.when)); + + // Register the route with Angular + app.config(['$routeProvider', function ($routeProvider) { + if (route.when) { + $routeProvider.when(route.when, route); + } else { + $routeProvider.otherwise(route); + } + }]); + } + + // Handle service compositing + function registerComponents(components) { + var app = this.app, + $log = this.$log; + return new ServiceCompositor(app, $log) + .registerCompositeServices(components); + } + + // Utility; create a function which converts another function + // (which acts on single objects) to one which acts upon arrays. + function mapUpon(func) { + return function (array) { + return array.map(bind(func, this)); + }; + } + + // More like key-value pairs than methods; key is the + // name of the extension category to be handled, and the value + // is the function which handles it. + + /** + * Register constant values. + * @param {Array} extensions the resolved extensions + */ + CustomRegistrars.prototype.constants = + mapUpon(registerConstant); + + /** + * Register Angular routes. + * @param {Array} extensions the resolved extensions + */ + CustomRegistrars.prototype.routes = + mapUpon(registerRoute); + + /** + * Register Angular directives. + * @param {Array} extensions the resolved extensions + */ + CustomRegistrars.prototype.directives = + mapUpon(customRegistrar("directive")); + + /** + * Register Angular controllers. + * @param {Array} extensions the resolved extensions + */ + CustomRegistrars.prototype.controllers = + mapUpon(customRegistrar("controller")); + + /** + * Register Angular services. + * @param {Array} extensions the resolved extensions + */ + CustomRegistrars.prototype.services = + mapUpon(customRegistrar("service")); + + /** + * Register functions which will run after bootstrapping. + * @param {Array} extensions the resolved extensions + */ + CustomRegistrars.prototype.runs = + mapUpon(registerRun); + + /** + * Register components of composite services. + * @param {Array} extensions the resolved extensions + */ + CustomRegistrars.prototype.components = + registerComponents; + return CustomRegistrars; } ); diff --git a/platform/framework/src/register/ExtensionRegistrar.js b/platform/framework/src/register/ExtensionRegistrar.js index bc6f58084e..352d3b9f3f 100644 --- a/platform/framework/src/register/ExtensionRegistrar.js +++ b/platform/framework/src/register/ExtensionRegistrar.js @@ -47,14 +47,41 @@ define( // Track which extension categories have already been registered. // Exceptions will be thrown if the same extension category is // registered twice. - var registeredCategories = {}; + this.registeredCategories = {}; + this.customRegistrars = customRegistrars || {}; + this.app = app; + this.sorter = sorter; + this.$log = $log; + } + + /** + * Register a group of resolved extensions with the Angular + * module managed by this registrar. + * + * For convenient chaining (particularly from the framework + * initializer's perspective), this returns the Angular + * module with which extensions were registered. + * + * @param {Object.} extensionGroup an object + * containing key-value pairs, where keys are extension + * categories and values are arrays of resolved + * extensions + * @returns {angular.Module} the application module with + * which extensions were registered + */ + ExtensionRegistrar.prototype.registerExtensions = function (extensionGroup) { + var registeredCategories = this.registeredCategories, + customRegistrars = this.customRegistrars, + app = this.app, + sorter = this.sorter, + $log = this.$log; // Used to build unique identifiers for individual extensions, // so that these can be registered separately with Angular function identify(category, extension, index) { var name = extension.key ? - ("extension-" + extension.key + "#" + index) : - ("extension#" + index); + ("extension-" + extension.key + "#" + index) : + ("extension#" + index); return category + "[" + name + "]"; } @@ -76,8 +103,8 @@ define( function makeServiceArgument(category, extension) { var dependencies = extension.depends || [], factory = (typeof extension === 'function') ? - new PartialConstructor(extension) : - staticFunction(extension); + new PartialConstructor(extension) : + staticFunction(extension); return dependencies.concat([factory]); } @@ -129,9 +156,9 @@ define( // an extension category (e.g. is suffixed by []) function isExtensionDependency(dependency) { var index = dependency.indexOf( - Constants.EXTENSION_SUFFIX, - dependency.length - Constants.EXTENSION_SUFFIX.length - ); + Constants.EXTENSION_SUFFIX, + dependency.length - Constants.EXTENSION_SUFFIX.length + ); return index !== -1; } @@ -153,8 +180,8 @@ define( (extension.depends || []).filter( isExtensionDependency ).forEach(function (dependency) { - needed[dependency] = true; - }); + needed[dependency] = true; + }); }); // Remove categories which have been provided @@ -174,53 +201,29 @@ define( findEmptyExtensionDependencies( extensionGroup ).forEach(function (name) { - $log.info("Registering empty extension category " + name); - app.factory(name, [staticFunction([])]); - }); + $log.info("Registering empty extension category " + name); + app.factory(name, [staticFunction([])]); + }); } - function registerExtensionGroup(extensionGroup) { - // Announce we're entering a new phase - $log.info("Registering extensions..."); + // Announce we're entering a new phase + $log.info("Registering extensions..."); - // Register all declared extensions by category - Object.keys(extensionGroup).forEach(function (category) { - registerExtensionsForCategory( - category, - sorter.sort(extensionGroup[category]) - ); - }); + // Register all declared extensions by category + Object.keys(extensionGroup).forEach(function (category) { + registerExtensionsForCategory( + category, + sorter.sort(extensionGroup[category]) + ); + }); - // Also handle categories which are needed but not declared - registerEmptyDependencies(extensionGroup); + // Also handle categories which are needed but not declared + registerEmptyDependencies(extensionGroup); - // Return the application to which these extensions - // have been registered - return app; - } - - customRegistrars = customRegistrars || {}; - - return { - /** - * Register a group of resolved extensions with the Angular - * module managed by this registrar. - * - * For convenient chaining (particularly from the framework - * initializer's perspective), this returns the Angular - * module with which extensions were registered. - * - * @param {Object.} extensionGroup an object - * containing key-value pairs, where keys are extension - * categories and values are arrays of resolved - * extensions - * @returns {angular.Module} the application module with - * which extensions were registered - * @memberof platform/framework.ExtensionRegistrar# - */ - registerExtensions: registerExtensionGroup - }; - } + // Return the application to which these extensions + // have been registered + return app; + }; return ExtensionRegistrar; } diff --git a/platform/framework/src/register/ExtensionSorter.js b/platform/framework/src/register/ExtensionSorter.js index f10d7b62ce..9bc902da9e 100644 --- a/platform/framework/src/register/ExtensionSorter.js +++ b/platform/framework/src/register/ExtensionSorter.js @@ -38,6 +38,17 @@ define( * @constructor */ function ExtensionSorter($log) { + this.$log = $log; + } + + /** + * Sort extensions according to priority. + * + * @param {object[]} extensions array of resolved extensions + * @returns {object[]} the same extensions, in priority order + */ + ExtensionSorter.prototype.sort = function (extensions) { + var $log = this.$log; // Handle unknown or malformed priorities specified by extensions function unrecognizedPriority(extension) { @@ -68,7 +79,7 @@ define( // Should be a number; otherwise, issue a warning and // fall back to default priority level. return (typeof priority === 'number') ? - priority : unrecognizedPriority(extension); + priority : unrecognizedPriority(extension); } // Attach a numeric priority to an extension; this is done in @@ -98,22 +109,11 @@ define( return (b.priority - a.priority) || (a.index - b.index); } - return { - /** - * Sort extensions according to priority. - * - * @param {object[]} extensions array of resolved extensions - * @returns {object[]} the same extensions, in priority order - * @memberof platform/framework.ExtensionSorter# - */ - sort: function (extensions) { - return (extensions || []) - .map(prioritize) - .sort(compare) - .map(deprioritize); - } - }; - } + return (extensions || []) + .map(prioritize) + .sort(compare) + .map(deprioritize); + }; return ExtensionSorter; } diff --git a/platform/framework/src/register/ServiceCompositor.js b/platform/framework/src/register/ServiceCompositor.js index c76beeba49..349e0c92e4 100644 --- a/platform/framework/src/register/ServiceCompositor.js +++ b/platform/framework/src/register/ServiceCompositor.js @@ -37,8 +37,30 @@ define( * @constructor */ function ServiceCompositor(app, $log) { - var latest = {}, - providerLists = {}; // Track latest services registered + this.latest = {}; + this.providerLists = {}; // Track latest services registered + this.app = app; + this.$log = $log; + } + + /** + * Register composite services with Angular. This will build + * up a dependency hierarchy between providers, aggregators, + * and/or decorators, such that a dependency upon the service + * type they expose shall be satisfied by their fully-wired + * whole. + * + * Note that this method assumes that a complete set of + * components shall be provided. Multiple calls to this + * method may not behave as expected. + * + * @param {Array} components extensions of category component + */ + ServiceCompositor.prototype.registerCompositeServices = function (components) { + var latest = this.latest, + providerLists = this.providerLists, + app = this.app, + $log = this.$log; // Log a warning; defaults to "no service provided by" function warn(extension, category, message) { @@ -200,33 +222,13 @@ define( registerLatest(); } - // Initial point of entry; just separate components by type - function registerCompositeServices(components) { - registerComposites( - components.filter(hasType("provider")), - components.filter(hasType("aggregator")), - components.filter(hasType("decorator")) - ); - } - - return { - /** - * Register composite services with Angular. This will build - * up a dependency hierarchy between providers, aggregators, - * and/or decorators, such that a dependency upon the service - * type they expose shall be satisfied by their fully-wired - * whole. - * - * Note that this method assumes that a complete set of - * components shall be provided. Multiple calls to this - * method may not behave as expected. - * - * @param {Array} components extensions of category component - * @memberof platform/framework.ServiceCompositor# - */ - registerCompositeServices: registerCompositeServices - }; - } + // Initial point of entry; split into three component types. + registerComposites( + components.filter(hasType("provider")), + components.filter(hasType("aggregator")), + components.filter(hasType("decorator")) + ); + }; return ServiceCompositor; } diff --git a/platform/framework/src/resolve/BundleResolver.js b/platform/framework/src/resolve/BundleResolver.js index 02bb76110d..4360764aee 100644 --- a/platform/framework/src/resolve/BundleResolver.js +++ b/platform/framework/src/resolve/BundleResolver.js @@ -38,8 +38,27 @@ define( * @constructor */ function BundleResolver(extensionResolver, requireConfigurator, $log) { + this.extensionResolver = extensionResolver; + this.requireConfigurator = requireConfigurator; + this.$log = $log; + } - /** + /** + * Resolve all extensions exposed by these bundles. + * + * @param {Bundle[]} bundles the bundles to resolve + * @returns {Promise.>} an promise + * for an object containing + * key-value pairs, where keys are extension + * categories and values are arrays of resolved + * extensions belonging to those categories + */ + BundleResolver.prototype.resolveBundles = function (bundles) { + var extensionResolver = this.extensionResolver, + requireConfigurator = this.requireConfigurator, + $log = this.$log; + + /* * Merge resolved bundles (where each is expressed as an * object containing key-value pairs, where keys are extension * categories and values are arrays of resolved extensions) @@ -99,28 +118,13 @@ define( .then(giveResult); } - return { - /** - * Resolve all extensions exposed by these bundles. - * - * @param {Bundle[]} bundles the bundles to resolve - * @returns {Promise.>} an promise - * for an object containing - * key-value pairs, where keys are extension - * categories and values are arrays of resolved - * extensions belonging to those categories - * @memberof platform/framework.BundleResolver# - */ - resolveBundles: function (bundles) { - // First, make sure Require is suitably configured - requireConfigurator.configure(bundles); + // First, make sure Require is suitably configured + requireConfigurator.configure(bundles); - // Then, resolve all extension implementations. - return Promise.all(bundles.map(resolveBundle)) - .then(mergeResolvedBundles); - } - }; - } + // Then, resolve all extension implementations. + return Promise.all(bundles.map(resolveBundle)) + .then(mergeResolvedBundles); + }; return BundleResolver; } diff --git a/platform/framework/src/resolve/ExtensionResolver.js b/platform/framework/src/resolve/ExtensionResolver.js index 126b9ab3f9..e4c2710c0f 100644 --- a/platform/framework/src/resolve/ExtensionResolver.js +++ b/platform/framework/src/resolve/ExtensionResolver.js @@ -39,6 +39,27 @@ define( * @constructor */ function ExtensionResolver(loader, $log) { + this.loader = loader; + this.$log = $log; + } + + /** + * Resolve the provided extension; this will give a promise + * for the extension's implementation, if one has been + * specified, or for the plain definition of the extension + * otherwise. The plain definition will also be given + * if the implementation fails to load for some reason. + * + * All key-value pairs from the extension definition + * will additionally be attached to any loaded implementation. + * + * @param {Extension} extension the extension to resolve + * @returns {Promise} a promise for the resolved extension + */ + ExtensionResolver.prototype.resolve = function (extension) { + var loader = this.loader, + $log = this.$log; + function loadImplementation(extension) { var implPath = extension.getImplementationPath(), implPromise = loader.load(implPath), @@ -57,8 +78,8 @@ define( // loaded implementation. function attachDefinition(impl) { var result = (typeof impl === 'function') ? - constructorFor(impl) : - Object.create(impl); + constructorFor(impl) : + Object.create(impl); // Copy over static properties Object.keys(impl).forEach(function (k) { @@ -84,11 +105,11 @@ define( function handleError(err) { // Build up a log message from parts var message = [ - "Could not load implementation for extension ", - extension.getLogName(), - " due to ", - err.message - ].join(""); + "Could not load implementation for extension ", + extension.getLogName(), + " due to ", + err.message + ].join(""); // Log that the extension was not loaded $log.warn(message); @@ -107,33 +128,16 @@ define( return implPromise.then(attachDefinition, handleError); } - return { - /** - * Resolve the provided extension; this will give a promise - * for the extension's implementation, if one has been - * specified, or for the plain definition of the extension - * otherwise. The plain definition will also be given - * if the implementation fails to load for some reason. - * - * All key-value pairs from the extension definition - * will additionally be attached to any loaded implementation. - * - * @param {Extension} extension - * @memberof platform/framework.ExtensionResolver# - */ - resolve: function (extension) { - // Log that loading has begun - $log.info([ - "Resolving extension ", - extension.getLogName() - ].join("")); + // Log that loading has begun + $log.info([ + "Resolving extension ", + extension.getLogName() + ].join("")); - return extension.hasImplementation() ? - loadImplementation(extension) : - Promise.resolve(extension.getDefinition()); - } - }; - } + return extension.hasImplementation() ? + loadImplementation(extension) : + Promise.resolve(extension.getDefinition()); + }; return ExtensionResolver; } diff --git a/platform/framework/src/resolve/ImplementationLoader.js b/platform/framework/src/resolve/ImplementationLoader.js index b76c5035e8..c9f1ae8bc9 100644 --- a/platform/framework/src/resolve/ImplementationLoader.js +++ b/platform/framework/src/resolve/ImplementationLoader.js @@ -39,31 +39,27 @@ define( * @param {*} $log Angular's logging service */ function ImplementationLoader(require) { - function loadModule(path) { - return new Promise(function (fulfill, reject) { - require([path], fulfill, reject); - }); - } - - return { - /** - * Load an extension's implementation; or, equivalently, - * load an AMD module. This is fundamentally similar - * to a call to RequireJS, except that the result is - * wrapped in a promise. The promise will be fulfilled - * with the loaded module, or rejected with the error - * reported by Require. - * - * @method - * @memberof ImplementationLoader# - * @param {string} path the path to the module to load - * @returns {Promise} a promise for the specified module. - * @memberof platform/framework.ImplementationLoader# - */ - load: loadModule - }; + this.require = require; } + /** + * Load an extension's implementation; or, equivalently, + * load an AMD module. This is fundamentally similar + * to a call to RequireJS, except that the result is + * wrapped in a promise. The promise will be fulfilled + * with the loaded module, or rejected with the error + * reported by Require. + * + * @param {string} path the path to the module to load + * @returns {Promise} a promise for the specified module. + */ + ImplementationLoader.prototype.load = function loadModule(path) { + var require = this.require; + return new Promise(function (fulfill, reject) { + require([path], fulfill, reject); + }); + }; + return ImplementationLoader; } ); diff --git a/platform/framework/src/resolve/RequireConfigurator.js b/platform/framework/src/resolve/RequireConfigurator.js index 231a4c316f..f55ac559c1 100644 --- a/platform/framework/src/resolve/RequireConfigurator.js +++ b/platform/framework/src/resolve/RequireConfigurator.js @@ -35,79 +35,79 @@ define( * @param requirejs an instance of RequireJS */ function RequireConfigurator(requirejs) { - // Utility function to clone part of a bundle definition - function clone(obj) { - return JSON.parse(JSON.stringify(obj)); - } - - // Look up module configuration from the bundle definition. - // This will adjust paths to libraries as-needed. - function getConfiguration(bundle) { - var configuration = bundle.getConfiguration(); - - // Adjust paths to point to libraries - if (configuration.paths) { - // Don't modify the actual bundle definition... - configuration = clone(configuration); - // ...replace values in a clone instead. - Object.keys(configuration.paths).forEach(function (path) { - configuration.paths[path] = - bundle.getLibraryPath(configuration.paths[path]); - }); - } - - return configuration; - } - - // Build up paths and shim values from multiple bundles; - // this is sensitive to the value from baseConfiguration - // passed via reduce in buildConfiguration below, insofar - // as it assumes paths and shim will have initial empty values. - function mergeConfigurations(base, next) { - ["paths", "shim"].forEach(function (k) { - Object.keys(next[k] || {}).forEach(function (p) { - base[k][p] = next[k][p]; - }); - }); - return base; - } - - // Build a configuration object, to pass to requirejs.config, - // based on the defined configurations for all bundles. - // The paths and shim properties from all bundles will be - // merged to allow one requirejs.config call. - function buildConfiguration(bundles) { - // Provide an initial requirejs configuration... - var baseConfiguration = { - baseUrl: "", - paths: {}, - shim: {} - }, - // ...and pull out all bundle-specific parts - bundleConfigurations = bundles.map(getConfiguration); - - // Reduce this into one configuration object. - return bundleConfigurations.reduce( - mergeConfigurations, - baseConfiguration - ); - } - - return { - /** - * Configure RequireJS to utilize any path/shim definitions - * provided by these bundles. - * - * @param {Bundle[]} the bundles to include in this - * configuration - * @memberof platform/framework.RequireConfigurator# - */ - configure: function (bundles) { - return requirejs.config(buildConfiguration(bundles)); - } - }; + this.requirejs = requirejs; } + // Utility function to clone part of a bundle definition + function clone(obj) { + return JSON.parse(JSON.stringify(obj)); + } + + // Look up module configuration from the bundle definition. + // This will adjust paths to libraries as-needed. + function getConfiguration(bundle) { + var configuration = bundle.getConfiguration(); + + // Adjust paths to point to libraries + if (configuration.paths) { + // Don't modify the actual bundle definition... + configuration = clone(configuration); + // ...replace values in a clone instead. + Object.keys(configuration.paths).forEach(function (path) { + configuration.paths[path] = + bundle.getLibraryPath(configuration.paths[path]); + }); + } + + return configuration; + } + + // Build up paths and shim values from multiple bundles; + // this is sensitive to the value from baseConfiguration + // passed via reduce in buildConfiguration below, insofar + // as it assumes paths and shim will have initial empty values. + function mergeConfigurations(base, next) { + ["paths", "shim"].forEach(function (k) { + Object.keys(next[k] || {}).forEach(function (p) { + base[k][p] = next[k][p]; + }); + }); + return base; + } + + // Build a configuration object, to pass to requirejs.config, + // based on the defined configurations for all bundles. + // The paths and shim properties from all bundles will be + // merged to allow one requirejs.config call. + function buildConfiguration(bundles) { + // Provide an initial requirejs configuration... + var baseConfiguration = { + baseUrl: "", + paths: {}, + shim: {} + }, + // ...and pull out all bundle-specific parts + bundleConfigurations = bundles.map(getConfiguration); + + // Reduce this into one configuration object. + return bundleConfigurations.reduce( + mergeConfigurations, + baseConfiguration + ); + } + + /** + * Configure RequireJS to utilize any path/shim definitions + * provided by these bundles. + * + * @param {Bundle[]} the bundles to include in this + * configuration + * @memberof platform/framework.RequireConfigurator# + */ + RequireConfigurator.prototype.configure = function (bundles) { + return this.requirejs.config(buildConfiguration(bundles)); + }; + return RequireConfigurator; } From 3e8ea972c2ba19265bc0182cea7b4d5fb7b45b5f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 14 Aug 2015 15:20:46 -0700 Subject: [PATCH 62/84] [Code Style] Use prototypes in persistence bundles WTD-1482 --- .../cache/src/CachingPersistenceDecorator.js | 250 +++++++---------- .../persistence/couch/src/CouchIndicator.js | 82 +++--- .../couch/src/CouchPersistenceProvider.js | 244 +++++++--------- .../elastic/src/ElasticIndicator.js | 77 ++--- .../elastic/src/ElasticPersistenceProvider.js | 263 ++++++++---------- 5 files changed, 371 insertions(+), 545 deletions(-) diff --git a/platform/persistence/cache/src/CachingPersistenceDecorator.js b/platform/persistence/cache/src/CachingPersistenceDecorator.js index 5d9676cfe7..3053bc088a 100644 --- a/platform/persistence/cache/src/CachingPersistenceDecorator.js +++ b/platform/persistence/cache/src/CachingPersistenceDecorator.js @@ -38,71 +38,17 @@ define( * * @memberof platform/persistence/cache * @constructor - * @param {string[]} CACHE_SPACES persistence space names which + * @param {string[]} cacheSpaces persistence space names which * should be cached * @param {PersistenceService} persistenceService the service which * implements object persistence, whose inputs/outputs * should be cached. + * @implements {PersistenceService} */ - function CachingPersistenceDecorator(CACHE_SPACES, persistenceService) { - var spaces = CACHE_SPACES || [], // List of spaces to cache + function CachingPersistenceDecorator(cacheSpaces, persistenceService) { + var spaces = cacheSpaces || [], // List of spaces to cache cache = {}; // Where objects will be stored - // Update the cached instance of an object to a new value - function replaceValue(valueHolder, newValue) { - var v = valueHolder.value; - - // If it's a JS object, we want to replace contents, so that - // everybody gets the same instance. - if (typeof v === 'object' && v !== null) { - // Only update contents if these are different instances - if (v !== newValue) { - // Clear prior contents - Object.keys(v).forEach(function (k) { - delete v[k]; - }); - // Shallow-copy contents - Object.keys(newValue).forEach(function (k) { - v[k] = newValue[k]; - }); - } - } else { - // Otherwise, just store the new value - valueHolder.value = newValue; - } - } - - // Place value in the cache for space, if there is one. - function addToCache(space, key, value) { - if (cache[space]) { - if (cache[space][key]) { - replaceValue(cache[space][key], value); - } else { - cache[space][key] = { value: value }; - } - } - } - - // Create a function for putting value into a cache; - // useful for then-chaining. - function putCache(space, key) { - return function (value) { - addToCache(space, key, value); - return value; - }; - } - - // Wrap as a thenable; used instead of $q.when because that - // will resolve on a future tick, which can cause latency - // issues (which this decorator is intended to address.) - function fastPromise(value) { - return { - then: function (callback) { - return fastPromise(callback(value)); - } - }; - } - // Arrayify list of spaces to cache, if necessary. spaces = Array.isArray(spaces) ? spaces : [ spaces ]; @@ -111,103 +57,107 @@ define( cache[space] = {}; }); - // Provide PersistenceService interface; mostly delegate to the - // decorated service, intervene and cache where appropriate. + this.spaces = spaces; + this.cache = cache; + this.persistenceService = persistenceService; + } + + // Wrap as a thenable; used instead of $q.when because that + // will resolve on a future tick, which can cause latency + // issues (which this decorator is intended to address.) + function fastPromise(value) { return { - /** - * List all persistence spaces that are supported by the - * decorated service. - * @memberof CachingPersistenceDecorator# - * @returns {Promise.} spaces supported - * @memberof platform/persistence/cache.CachingPersistenceDecorator# - */ - listSpaces: function () { - return persistenceService.listSpaces(); - }, - /** - * List all objects in a specific space. - * @memberof CachingPersistenceDecorator# - * @param {string} space the space in which to list objects - * @returns {Promise.} keys for objects in this space - * @memberof platform/persistence/cache.CachingPersistenceDecorator# - */ - listObjects: function (space) { - return persistenceService.listObjects(space); - }, - /** - * Create an object in a specific space. This will - * be cached to expedite subsequent retrieval. - * @memberof CachingPersistenceDecorator# - * @param {string} space the space in which to create the object - * @param {string} key the key associate with the object for - * subsequent lookup - * @param {object} value a JSONifiable object to store - * @returns {Promise.} an indicator of the success or - * failure of this request - * @memberof platform/persistence/cache.CachingPersistenceDecorator# - */ - createObject: function (space, key, value) { - addToCache(space, key, value); - return persistenceService.createObject(space, key, value); - }, - /** - * Read an object from a specific space. This will read from a - * cache if the object is available. - * @memberof CachingPersistenceDecorator# - * @param {string} space the space in which to create the object - * @param {string} key the key which identifies the object - * @returns {Promise.} a promise for the object; may - * resolve to undefined (if the object does not exist - * in this space) - * @memberof platform/persistence/cache.CachingPersistenceDecorator# - */ - readObject: function (space, key) { - return (cache[space] && cache[space][key]) ? - fastPromise(cache[space][key].value) : - persistenceService.readObject(space, key) - .then(putCache(space, key)); - }, - /** - * Update an object in a specific space. This will - * be cached to expedite subsequent retrieval. - * @memberof CachingPersistenceDecorator# - * @param {string} space the space in which to create the object - * @param {string} key the key associate with the object for - * subsequent lookup - * @param {object} value a JSONifiable object to store - * @returns {Promise.} an indicator of the success or - * failure of this request - * @memberof platform/persistence/cache.CachingPersistenceDecorator# - */ - updateObject: function (space, key, value) { - return persistenceService.updateObject(space, key, value) - .then(function (result) { - addToCache(space, key, value); - return result; - }); - }, - /** - * Delete an object in a specific space. This will - * additionally be cleared from the cache. - * @memberof CachingPersistenceDecorator# - * @param {string} space the space in which to create the object - * @param {string} key the key associate with the object for - * subsequent lookup - * @param {object} value a JSONifiable object to delete - * @returns {Promise.} an indicator of the success or - * failure of this request - * @memberof platform/persistence/cache.CachingPersistenceDecorator# - */ - deleteObject: function (space, key, value) { - if (cache[space]) { - delete cache[space][key]; - } - return persistenceService.deleteObject(space, key, value); + then: function (callback) { + return fastPromise(callback(value)); } }; - } + // Update the cached instance of an object to a new value + function replaceValue(valueHolder, newValue) { + var v = valueHolder.value; + + // If it's a JS object, we want to replace contents, so that + // everybody gets the same instance. + if (typeof v === 'object' && v !== null) { + // Only update contents if these are different instances + if (v !== newValue) { + // Clear prior contents + Object.keys(v).forEach(function (k) { + delete v[k]; + }); + // Shallow-copy contents + Object.keys(newValue).forEach(function (k) { + v[k] = newValue[k]; + }); + } + } else { + // Otherwise, just store the new value + valueHolder.value = newValue; + } + } + + // Place value in the cache for space, if there is one. + CachingPersistenceDecorator.prototype.addToCache = function (space, key, value) { + var cache = this.cache; + if (cache[space]) { + if (cache[space][key]) { + replaceValue(cache[space][key], value); + } else { + cache[space][key] = { value: value }; + } + } + }; + + // Create a function for putting value into a cache; + // useful for then-chaining. + CachingPersistenceDecorator.prototype.putCache = function (space, key) { + var self = this; + return function (value) { + self.addToCache(space, key, value); + return value; + }; + }; + + + + CachingPersistenceDecorator.prototype.listSpaces = function () { + return this.persistenceService.listSpaces(); + }; + + CachingPersistenceDecorator.prototype.listObjects = function (space) { + return this.persistenceService.listObjects(space); + }; + + CachingPersistenceDecorator.prototype.createObject = function (space, key, value) { + this.addToCache(space, key, value); + return this.persistenceService.createObject(space, key, value); + }; + + CachingPersistenceDecorator.prototype.readObject = function (space, key) { + var cache = this.cache; + return (cache[space] && cache[space][key]) ? + fastPromise(cache[space][key].value) : + this.persistenceService.readObject(space, key) + .then(this.putCache(space, key)); + }; + + CachingPersistenceDecorator.prototype.updateObject = function (space, key, value) { + var self = this; + return this.persistenceService.updateObject(space, key, value) + .then(function (result) { + self.addToCache(space, key, value); + return result; + }); + }; + + CachingPersistenceDecorator.prototype.deleteObject = function (space, key, value) { + if (this.cache[space]) { + delete this.cache[space][key]; + } + return this.persistenceService.deleteObject(space, key, value); + }; + return CachingPersistenceDecorator; } ); diff --git a/platform/persistence/couch/src/CouchIndicator.js b/platform/persistence/couch/src/CouchIndicator.js index a57a129c21..684f2e58c5 100644 --- a/platform/persistence/couch/src/CouchIndicator.js +++ b/platform/persistence/couch/src/CouchIndicator.js @@ -57,74 +57,62 @@ define( * that the database is available. * @constructor * @memberof platform/persistence/couch + * @implements {Indicator} + * @param $http Angular's $http service + * @param $interval Angular's $interval service + * @param {string} path the URL to poll to check for couch availability + * @param {number} interval the interval, in milliseconds, to poll at */ - function CouchIndicator($http, $interval, PATH, INTERVAL) { + function CouchIndicator($http, $interval, path, interval) { + var self = this; + // Track the current connection state - var state = PENDING; + this.state = PENDING; + + this.$http = $http; + this.$interval = $interval; + this.path = path; + this.interval = interval; + // Callback if the HTTP request to Couch fails function handleError(err) { - state = DISCONNECTED; + self.state = DISCONNECTED; } // Callback if the HTTP request succeeds. CouchDB may // report an error, so check for that. function handleResponse(response) { var data = response.data; - state = data.error ? SEMICONNECTED : CONNECTED; + self.state = data.error ? SEMICONNECTED : CONNECTED; } // Try to connect to CouchDB, and update the indicator. function updateIndicator() { - $http.get(PATH).then(handleResponse, handleError); + $http.get(path).then(handleResponse, handleError); } // Update the indicator initially, and start polling. updateIndicator(); - $interval(updateIndicator, INTERVAL); - - return { - /** - * Get the glyph (single character used as an icon) - * to display in this indicator. This will return "D", - * which should appear as a database icon. - * @returns {string} the character of the database icon - * @memberof platform/persistence/couch.CouchIndicator# - */ - getGlyph: function () { - return "D"; - }, - /** - * Get the name of the CSS class to apply to the glyph. - * This is used to color the glyph to match its - * state (one of ok, caution or err) - * @returns {string} the CSS class to apply to this glyph - * @memberof platform/persistence/couch.CouchIndicator# - */ - getGlyphClass: function () { - return state.glyphClass; - }, - /** - * Get the text that should appear in the indicator. - * @returns {string} brief summary of connection status - * @memberof platform/persistence/couch.CouchIndicator# - */ - getText: function () { - return state.text; - }, - /** - * Get a longer-form description of the current connection - * space, suitable for display in a tooltip - * @returns {string} longer summary of connection status - * @memberof platform/persistence/couch.CouchIndicator# - */ - getDescription: function () { - return state.description; - } - }; - + $interval(updateIndicator, interval); } + CouchIndicator.prototype.getGlyph = function () { + return "D"; + }; + + CouchIndicator.prototype.getGlyphClass = function () { + return this.state.glyphClass; + }; + + CouchIndicator.prototype.getText = function () { + return this.state.text; + }; + + CouchIndicator.prototype.getDescription = function () { + return this.state.description; + }; + return CouchIndicator; } ); diff --git a/platform/persistence/couch/src/CouchPersistenceProvider.js b/platform/persistence/couch/src/CouchPersistenceProvider.js index 1269780b35..c50cc86386 100644 --- a/platform/persistence/couch/src/CouchPersistenceProvider.js +++ b/platform/persistence/couch/src/CouchPersistenceProvider.js @@ -42,154 +42,108 @@ define( * instance. * @memberof platform/persistence/couch * @constructor + * @implements {PersistenceService} + * @param $http Angular's $http service + * @param $interval Angular's $interval service + * @param {string} space the name of the persistence space being served + * @param {string} path the path to the CouchDB instance */ - function CouchPersistenceProvider($http, $q, SPACE, PATH) { - var spaces = [ SPACE ], - revs = {}; - - // Convert a subpath to a full path, suitable to pass - // to $http. - function url(subpath) { - return PATH + '/' + subpath; - } - - // Issue a request using $http; get back the plain JS object - // from the expected JSON response - function request(subpath, method, value) { - return $http({ - method: method, - url: url(subpath), - data: value - }).then(function (response) { - return response.data; - }, function () { - return undefined; - }); - } - - // Shorthand methods for GET/PUT methods - function get(subpath) { - return request(subpath, "GET"); - } - function put(subpath, value) { - return request(subpath, "PUT", value); - } - - // Pull out a list of document IDs from CouchDB's - // _all_docs response - function getIdsFromAllDocs(allDocs) { - return allDocs.rows.map(function (r) { return r.id; }); - } - - // Get a domain object model out of CouchDB's response - function getModel(response) { - if (response && response.model) { - revs[response[ID]] = response[REV]; - return response.model; - } else { - return undefined; - } - } - - // Check the response to a create/update/delete request; - // track the rev if it's valid, otherwise return false to - // indicate that the request failed. - function checkResponse(response) { - if (response && response.ok) { - revs[response.id] = response.rev; - return response.ok; - } else { - return false; - } - } - - return { - /** - * List all persistence spaces which this provider - * recognizes. - * - * @returns {Promise.} a promise for a list of - * spaces supported by this provider - * @memberof platform/persistence/couch.CouchPersistenceProvider# - */ - listSpaces: function () { - return $q.when(spaces); - }, - /** - * List all objects (by their identifiers) that are stored - * in the given persistence space, per this provider. - * @param {string} space the space to check - * @returns {Promise.} a promise for the list of - * identifiers - * @memberof platform/persistence/couch.CouchPersistenceProvider# - */ - listObjects: function (space) { - return get("_all_docs").then(getIdsFromAllDocs); - }, - /** - * Create a new object in the specified persistence space. - * @param {string} space the space in which to store the object - * @param {string} key the identifier for the persisted object - * @param {object} value a JSONifiable object that should be - * stored and associated with the provided identifier - * @returns {Promise.} a promise for an indication - * of the success (true) or failure (false) of this - * operation - * @memberof platform/persistence/couch.CouchPersistenceProvider# - */ - createObject: function (space, key, value) { - return put(key, new CouchDocument(key, value)) - .then(checkResponse); - }, - - /** - * Read an existing object back from persistence. - * @param {string} space the space in which to look for - * the object - * @param {string} key the identifier for the persisted object - * @returns {Promise.} a promise for the stored - * object; this will resolve to undefined if no such - * object is found. - * @memberof platform/persistence/couch.CouchPersistenceProvider# - */ - readObject: function (space, key) { - return get(key).then(getModel); - }, - /** - * Update an existing object in the specified persistence space. - * @param {string} space the space in which to store the object - * @param {string} key the identifier for the persisted object - * @param {object} value a JSONifiable object that should be - * stored and associated with the provided identifier - * @returns {Promise.} a promise for an indication - * of the success (true) or failure (false) of this - * operation - * @memberof platform/persistence/couch.CouchPersistenceProvider# - */ - updateObject: function (space, key, value) { - return put(key, new CouchDocument(key, value, revs[key])) - .then(checkResponse); - }, - /** - * Delete an object in the specified persistence space. - * @param {string} space the space from which to delete this - * object - * @param {string} key the identifier of the persisted object - * @param {object} value a JSONifiable object that should be - * deleted - * @returns {Promise.} a promise for an indication - * of the success (true) or failure (false) of this - * operation - * @memberof platform/persistence/couch.CouchPersistenceProvider# - */ - deleteObject: function (space, key, value) { - return put(key, new CouchDocument(key, value, revs[key], true)) - .then(checkResponse); - } - }; - + function CouchPersistenceProvider($http, $q, space, path) { + this.spaces = [ space ]; + this.revs = {}; + this.$q = $q; + this.$http = $http; + this.path = path; } + function bind(fn, thisArg) { + return function () { + return fn.apply(thisArg, arguments); + }; + } + + // Pull out a list of document IDs from CouchDB's + // _all_docs response + function getIdsFromAllDocs(allDocs) { + return allDocs.rows.map(function (r) { return r.id; }); + } + + // Check the response to a create/update/delete request; + // track the rev if it's valid, otherwise return false to + // indicate that the request failed. + function checkResponse(response) { + if (response && response.ok) { + this.revs[response.id] = response.rev; + return response.ok; + } else { + return false; + } + } + + // Get a domain object model out of CouchDB's response + function getModel(response) { + if (response && response.model) { + this.revs[response[ID]] = response[REV]; + return response.model; + } else { + return undefined; + } + } + + // Issue a request using $http; get back the plain JS object + // from the expected JSON response + CouchPersistenceProvider.prototype.request = function (subpath, method, value) { + return this.$http({ + method: method, + url: this.path + '/' + subpath, + data: value + }).then(function (response) { + return response.data; + }, function () { + return undefined; + }); + }; + + // Shorthand methods for GET/PUT methods + CouchPersistenceProvider.prototype.get = function (subpath) { + return this.request(subpath, "GET"); + }; + + CouchPersistenceProvider.prototype.put = function (subpath, value) { + return this.request(subpath, "PUT", value); + }; + + + CouchPersistenceProvider.prototype.listSpaces = function () { + return this.$q.when(this.spaces); + }; + + CouchPersistenceProvider.prototype.listObjects = function (space) { + return this.get("_all_docs").then(bind(getIdsFromAllDocs, this)); + }; + + CouchPersistenceProvider.prototype.createObject = function (space, key, value) { + return this.put(key, new CouchDocument(key, value)) + .then(bind(checkResponse, this)); + }; + + + CouchPersistenceProvider.prototype.readObject = function (space, key) { + return this.get(key).then(bind(getModel, this)); + }; + + CouchPersistenceProvider.prototype.updateObject = function (space, key, value) { + var rev = this.revs[key]; + return this.put(key, new CouchDocument(key, value, rev)) + .then(bind(checkResponse, this)); + }; + + CouchPersistenceProvider.prototype.deleteObject = function (space, key, value) { + var rev = this.revs[key]; + return this.put(key, new CouchDocument(key, value, rev, true)) + .then(bind(checkResponse, this)); + }; + return CouchPersistenceProvider; } ); diff --git a/platform/persistence/elastic/src/ElasticIndicator.js b/platform/persistence/elastic/src/ElasticIndicator.js index 17eb4e28db..9eb87e70eb 100644 --- a/platform/persistence/elastic/src/ElasticIndicator.js +++ b/platform/persistence/elastic/src/ElasticIndicator.js @@ -51,72 +51,51 @@ define( * that the database is available. * @constructor * @memberof platform/persistence/elastic + * @implements {Indicator} + * @param $http Angular's $http service + * @param $interval Angular's $interval service + * @param {string} path the URL to poll to check for couch availability + * @param {number} interval the interval, in milliseconds, to poll at */ - function ElasticIndicator($http, $interval, PATH, INTERVAL) { + function ElasticIndicator($http, $interval, path, interval) { // Track the current connection state - var state = PENDING; + var self = this; + + this.state = PENDING; // Callback if the HTTP request to Couch fails - function handleError(err) { - state = DISCONNECTED; + function handleError() { + self.state = DISCONNECTED; } // Callback if the HTTP request succeeds. - function handleResponse(response) { - state = CONNECTED; + function handleResponse() { + self.state = CONNECTED; } // Try to connect to CouchDB, and update the indicator. function updateIndicator() { - $http.get(PATH).then(handleResponse, handleError); + $http.get(path).then(handleResponse, handleError); } // Update the indicator initially, and start polling. updateIndicator(); - $interval(updateIndicator, INTERVAL, false); - - return { - /** - * Get the glyph (single character used as an icon) - * to display in this indicator. This will return "D", - * which should appear as a database icon. - * @returns {string} the character of the database icon - * @memberof platform/persistence/elastic.ElasticIndicator# - */ - getGlyph: function () { - return "D"; - }, - /** - * Get the name of the CSS class to apply to the glyph. - * This is used to color the glyph to match its - * state (one of ok, caution or err) - * @returns {string} the CSS class to apply to this glyph - * @memberof platform/persistence/elastic.ElasticIndicator# - */ - getGlyphClass: function () { - return state.glyphClass; - }, - /** - * Get the text that should appear in the indicator. - * @returns {string} brief summary of connection status - * @memberof platform/persistence/elastic.ElasticIndicator# - */ - getText: function () { - return state.text; - }, - /** - * Get a longer-form description of the current connection - * space, suitable for display in a tooltip - * @returns {string} longer summary of connection status - * @memberof platform/persistence/elastic.ElasticIndicator# - */ - getDescription: function () { - return state.description; - } - }; - + $interval(updateIndicator, interval, false); } + ElasticIndicator.prototype.getGlyph = function () { + return "D"; + }; + ElasticIndicator.prototype.getGlyphClass = function () { + return this.state.glyphClass; + }; + ElasticIndicator.prototype.getText = function () { + return this.state.text; + }; + ElasticIndicator.prototype.getDescription = function () { + return this.state.description; + }; + return ElasticIndicator; } ); diff --git a/platform/persistence/elastic/src/ElasticPersistenceProvider.js b/platform/persistence/elastic/src/ElasticPersistenceProvider.js index 2cc864ded2..f5d083d7ea 100644 --- a/platform/persistence/elastic/src/ElasticPersistenceProvider.js +++ b/platform/persistence/elastic/src/ElasticPersistenceProvider.js @@ -44,169 +44,124 @@ define( * instance. * @memberof platform/persistence/elastic * @constructor + * @implements {PersistenceService} + * @param $http Angular's $http service + * @param $interval Angular's $interval service + * @param {string} space the name of the persistence space being served + * @param {string} root the root of the path to ElasticSearch + * @param {stirng} path the path to domain objects within ElasticSearch */ - function ElasticPersistenceProvider($http, $q, SPACE, ROOT, PATH) { - var spaces = [ SPACE ], - revs = {}; + function ElasticPersistenceProvider($http, $q, space, root, path) { + this.spaces = [ space ]; + this.revs = {}; + this.$http = $http; + this.$q = $q; + this.root = root; + this.path = path; + } - // Convert a subpath to a full path, suitable to pass - // to $http. - function url(subpath) { - return ROOT + '/' + PATH + '/' + subpath; - } + function bind(fn, thisArg) { + return function () { + return fn.apply(thisArg, arguments); + }; + } - // Issue a request using $http; get back the plain JS object - // from the expected JSON response - function request(subpath, method, value, params) { - return $http({ - method: method, - url: url(subpath), - params: params, - data: value - }).then(function (response) { - return response.data; - }, function (response) { - return (response || {}).data; + // Issue a request using $http; get back the plain JS object + // from the expected JSON response + ElasticPersistenceProvider.prototype.request = function (subpath, method, value, params) { + return this.http({ + method: method, + url: this.root + '/' + this.path + '/' + subpath, + params: params, + data: value + }).then(function (response) { + return response.data; + }, function (response) { + return (response || {}).data; + }); + }; + + // Shorthand methods for GET/PUT methods + ElasticPersistenceProvider.prototype.get = function (subpath) { + return this.request(subpath, "GET"); + }; + ElasticPersistenceProvider.prototype.put = function (subpath, value, params) { + return this.request(subpath, "PUT", value, params); + }; + ElasticPersistenceProvider.prototype.del = function (subpath) { + return this.request(subpath, "DELETE"); + }; + + + // Handle an update error + ElasticPersistenceProvider.prototype.handleError = function (response, key) { + var error = new Error("Persistence error."), + $q = this.$q; + if ((response || {}).status === CONFLICT) { + error.key = "revision"; + // Load the updated model, then reject the promise + return this.get(key).then(function (response) { + error.model = response[SRC]; + return $q.reject(error); }); } + // Reject the promise + return this.$q.reject(error); + }; - // Shorthand methods for GET/PUT methods - function get(subpath) { - return request(subpath, "GET"); + // Get a domain object model out of CouchDB's response + function getModel(response) { + if (response && response[SRC]) { + this.revs[response[ID]] = response[REV]; + return response[SRC]; + } else { + return undefined; } - function put(subpath, value, params) { - return request(subpath, "PUT", value, params); - } - function del(subpath) { - return request(subpath, "DELETE"); - } - - // Get a domain object model out of CouchDB's response - function getModel(response) { - if (response && response[SRC]) { - revs[response[ID]] = response[REV]; - return response[SRC]; - } else { - return undefined; - } - } - - // Handle an update error - function handleError(response, key) { - var error = new Error("Persistence error."); - if ((response || {}).status === CONFLICT) { - error.key = "revision"; - // Load the updated model, then reject the promise - return get(key).then(function (response) { - error.model = response[SRC]; - return $q.reject(error); - }); - } - // Reject the promise - return $q.reject(error); - } - - // Check the response to a create/update/delete request; - // track the rev if it's valid, otherwise return false to - // indicate that the request failed. - function checkResponse(response, key) { - var error; - if (response && !response.error) { - revs[key] = response[REV]; - return response; - } else { - return handleError(response, key); - } - } - - return { - /** - * List all persistence spaces which this provider - * recognizes. - * - * @returns {Promise.} a promise for a list of - * spaces supported by this provider - * @memberof platform/persistence/elastic.ElasticPersistenceProvider# - */ - listSpaces: function () { - return $q.when(spaces); - }, - /** - * List all objects (by their identifiers) that are stored - * in the given persistence space, per this provider. - * @param {string} space the space to check - * @returns {Promise.} a promise for the list of - * identifiers - * @memberof platform/persistence/elastic.ElasticPersistenceProvider# - */ - listObjects: function (space) { - return $q.when([]); - }, - /** - * Create a new object in the specified persistence space. - * @param {string} space the space in which to store the object - * @param {string} key the identifier for the persisted object - * @param {object} value a JSONifiable object that should be - * stored and associated with the provided identifier - * @returns {Promise.} a promise for an indication - * of the success (true) or failure (false) of this - * operation - * @memberof platform/persistence/elastic.ElasticPersistenceProvider# - */ - createObject: function (space, key, value) { - return put(key, value).then(checkResponse); - }, - - /** - * Read an existing object back from persistence. - * @param {string} space the space in which to look for - * the object - * @param {string} key the identifier for the persisted object - * @returns {Promise.} a promise for the stored - * object; this will resolve to undefined if no such - * object is found. - * @memberof platform/persistence/elastic.ElasticPersistenceProvider# - */ - readObject: function (space, key) { - return get(key).then(getModel); - }, - /** - * Update an existing object in the specified persistence space. - * @param {string} space the space in which to store the object - * @param {string} key the identifier for the persisted object - * @param {object} value a JSONifiable object that should be - * stored and associated with the provided identifier - * @returns {Promise.} a promise for an indication - * of the success (true) or failure (false) of this - * operation - * @memberof platform/persistence/elastic.ElasticPersistenceProvider# - */ - updateObject: function (space, key, value) { - function checkUpdate(response) { - return checkResponse(response, key); - } - return put(key, value, { version: revs[key] }) - .then(checkUpdate); - }, - /** - * Delete an object in the specified persistence space. - * @param {string} space the space from which to delete this - * object - * @param {string} key the identifier of the persisted object - * @param {object} value a JSONifiable object that should be - * deleted - * @returns {Promise.} a promise for an indication - * of the success (true) or failure (false) of this - * operation - * @memberof platform/persistence/elastic.ElasticPersistenceProvider# - */ - deleteObject: function (space, key, value) { - return del(key).then(checkResponse); - } - }; - } + // Check the response to a create/update/delete request; + // track the rev if it's valid, otherwise return false to + // indicate that the request failed. + ElasticPersistenceProvider.prototype.checkResponse = function (response, key) { + if (response && !response.error) { + this.revs[key] = response[REV]; + return response; + } else { + return this.handleError(response, key); + } + }; + + // Public API + ElasticPersistenceProvider.prototype.listSpaces = function () { + return this.$q.when(this.spaces); + }; + + ElasticPersistenceProvider.prototype.listObjects = function () { + // Not yet implemented + return this.$q.when([]); + }; + + + ElasticPersistenceProvider.prototype.createObject = function (space, key, value) { + return this.put(key, value).then(bind(this.checkResponse, this)); + }; + + ElasticPersistenceProvider.prototype.readObject = function (space, key) { + return this.get(key).then(bind(getModel, this)); + }; + + ElasticPersistenceProvider.prototype.updateObject = function (space, key, value) { + function checkUpdate(response) { + return this.checkResponse(response, key); + } + return this.put(key, value, { version: this.revs[key] }) + .then(bind(checkUpdate, this)); + }; + + ElasticPersistenceProvider.prototype.deleteObject = function (space, key, value) { + return this.del(key).then(bind(this.checkResponse, this)); + }; + return ElasticPersistenceProvider; } ); From f8cb3f464cafaa7ed450549b14d1f172c91f8fec Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 14 Aug 2015 15:40:20 -0700 Subject: [PATCH 63/84] [Code Style] Use prototypes in persistence queue WTD-1482 --- .../queue/src/PersistenceFailureController.js | 34 ++--- .../queue/src/PersistenceFailureHandler.js | 59 ++++---- .../queue/src/PersistenceQueueHandler.js | 44 +++--- .../queue/src/PersistenceQueueImpl.js | 129 ++++++++++-------- .../QueuingPersistenceCapabilityDecorator.js | 47 +++---- 5 files changed, 155 insertions(+), 158 deletions(-) diff --git a/platform/persistence/queue/src/PersistenceFailureController.js b/platform/persistence/queue/src/PersistenceFailureController.js index 54c957b618..8586854857 100644 --- a/platform/persistence/queue/src/PersistenceFailureController.js +++ b/platform/persistence/queue/src/PersistenceFailureController.js @@ -33,25 +33,25 @@ define( * @memberof platform/persistence/queue */ function PersistenceFailureController() { - return { - /** - * Format a timestamp for display in the dialog. - * @memberof platform/persistence/queue.PersistenceFailureController# - */ - formatTimestamp: function (timestamp) { - return moment.utc(timestamp) - .format(Constants.TIMESTAMP_FORMAT); - }, - /** - * Format a user name for display in the dialog. - * @memberof platform/persistence/queue.PersistenceFailureController# - */ - formatUsername: function (username) { - return username || Constants.UNKNOWN_USER; - } - }; } + /** + * Format a timestamp for display in the dialog. + * @memberof platform/persistence/queue.PersistenceFailureController# + */ + PersistenceFailureController.prototype.formatTimestamp = function (timestamp) { + return moment.utc(timestamp) + .format(Constants.TIMESTAMP_FORMAT); + }; + + /** + * Format a user name for display in the dialog. + * @memberof platform/persistence/queue.PersistenceFailureController# + */ + PersistenceFailureController.prototype.formatUsername = function (username) { + return username || Constants.UNKNOWN_USER; + }; + return PersistenceFailureController; } ); diff --git a/platform/persistence/queue/src/PersistenceFailureHandler.js b/platform/persistence/queue/src/PersistenceFailureHandler.js index 45f4360662..8920ee5543 100644 --- a/platform/persistence/queue/src/PersistenceFailureHandler.js +++ b/platform/persistence/queue/src/PersistenceFailureHandler.js @@ -34,6 +34,24 @@ define( * @memberof platform/persistence/queue */ function PersistenceFailureHandler($q, dialogService) { + this.$q = $q; + this.dialogService = dialogService; + } + + /** + * Handle persistence failures by providing the user with a + * dialog summarizing these failures, and giving the option + * to overwrite/cancel as appropriate. + * @param {Array} failures persistence failures, as prepared + * by PersistenceQueueHandler + * @memberof platform/persistence/queue.PersistenceFailureHandler# + */ + PersistenceFailureHandler.prototype.handle = function handleFailures(failures) { + // Prepare dialog for display + var dialogModel = new PersistenceFailureDialog(failures), + revisionErrors = dialogModel.model.revised, + $q = this.$q; + // Refresh revision information for the domain object associated // with this persistence failure function refresh(failure) { @@ -100,39 +118,20 @@ define( return $q.all(failures.map(discard)); } - // Handle failures in persistence - function handleFailures(failures) { - // Prepare dialog for display - var dialogModel = new PersistenceFailureDialog(failures), - revisionErrors = dialogModel.model.revised; - - // Handle user input (did they choose to overwrite?) - function handleChoice(key) { - // If so, try again - if (key === PersistenceFailureConstants.OVERWRITE_KEY) { - return retry(revisionErrors); - } else { - return discardAll(revisionErrors); - } + // Handle user input (did they choose to overwrite?) + function handleChoice(key) { + // If so, try again + if (key === PersistenceFailureConstants.OVERWRITE_KEY) { + return retry(revisionErrors); + } else { + return discardAll(revisionErrors); } - - // Prompt for user input, the overwrite if they said so. - return dialogService.getUserChoice(dialogModel) - .then(handleChoice, handleChoice); } - return { - /** - * Handle persistence failures by providing the user with a - * dialog summarizing these failures, and giving the option - * to overwrite/cancel as appropriate. - * @param {Array} failures persistence failures, as prepared - * by PersistenceQueueHandler - * @memberof platform/persistence/queue.PersistenceFailureHandler# - */ - handle: handleFailures - }; - } + // Prompt for user input, the overwrite if they said so. + return this.dialogService.getUserChoice(dialogModel) + .then(handleChoice, handleChoice); + }; return PersistenceFailureHandler; } diff --git a/platform/persistence/queue/src/PersistenceQueueHandler.js b/platform/persistence/queue/src/PersistenceQueueHandler.js index 2965edfc80..4d630ce208 100644 --- a/platform/persistence/queue/src/PersistenceQueueHandler.js +++ b/platform/persistence/queue/src/PersistenceQueueHandler.js @@ -38,6 +38,25 @@ define( * @memberof platform/persistence/queue */ function PersistenceQueueHandler($q, failureHandler) { + this.$q = $q; + this.failureHandler = failureHandler; + } + + /** + * Invoke the persist method on the provided persistence + * capabilities. + * @param {Object.} persistences + * capabilities to invoke, in id->capability pairs. + * @param {Object.} domainObjects + * associated domain objects, in id->object pairs. + * @param {PersistenceQueue} queue the persistence queue, + * to requeue as necessary + * @memberof platform/persistence/queue.PersistenceQueueHandler# + */ + PersistenceQueueHandler.prototype.persist = function (persistences, domainObjects, queue) { + var ids = Object.keys(persistences), + $q = this.$q, + failureHandler = this.failureHandler; // Handle a group of persistence invocations function persistGroup(ids, persistences, domainObjects, queue) { @@ -81,33 +100,16 @@ define( // Handle any failures from the full operation function handleFailure(value) { return failures.length > 0 ? - failureHandler.handle(failures) : - value; + failureHandler.handle(failures) : + value; } // Try to persist everything, then handle any failures return $q.all(ids.map(tryPersist)).then(handleFailure); } - - return { - /** - * Invoke the persist method on the provided persistence - * capabilities. - * @param {Object.} persistences - * capabilities to invoke, in id->capability pairs. - * @param {Object.} domainObjects - * associated domain objects, in id->object pairs. - * @param {PersistenceQueue} queue the persistence queue, - * to requeue as necessary - * @memberof platform/persistence/queue.PersistenceQueueHandler# - */ - persist: function (persistences, domainObjects, queue) { - var ids = Object.keys(persistences); - return persistGroup(ids, persistences, domainObjects, queue); - } - }; - } + return persistGroup(ids, persistences, domainObjects, queue); + }; return PersistenceQueueHandler; } diff --git a/platform/persistence/queue/src/PersistenceQueueImpl.js b/platform/persistence/queue/src/PersistenceQueueImpl.js index d0c77ee057..fa68ca864c 100644 --- a/platform/persistence/queue/src/PersistenceQueueImpl.js +++ b/platform/persistence/queue/src/PersistenceQueueImpl.js @@ -44,18 +44,32 @@ define( * @constructor * @memberof platform/persistence/queue */ - function PersistenceQueueImpl($q, $timeout, handler, DELAY) { - var self, - persistences = {}, - objects = {}, - lastObservedSize = 0, - pendingTimeout, - flushPromise, - activeDefer = $q.defer(); + function PersistenceQueueImpl($q, $timeout, handler, delay) { + + this.persistences = {}; + this.objects = {}; + this.lastObservedSize = 0; + this.activeDefer = $q.defer(); + + // If no delay is provided, use a default + this.delay = delay || 0; + this.handler = handler; + this.$timeout = $timeout; + this.$q = $q; + } + + // Schedule a flushing of the queue (that is, plan to flush + // all objects in the queue) + PersistenceQueueImpl.prototype.scheduleFlush = function () { + var self = this, + $timeout = this.$timeout, + $q = this.$q, + handler = this.handler; // Check if the queue's size has stopped increasing) function quiescent() { - return Object.keys(persistences).length === lastObservedSize; + return Object.keys(self.persistences).length + === self.lastObservedSize; } // Persist all queued objects @@ -64,74 +78,71 @@ define( // this will be replaced with a promise for the next round // of persistence calls, so we want to make sure we clear // the correct one when this flush completes. - var flushingDefer = activeDefer; + var flushingDefer = self.activeDefer; // Clear the active promise for a queue flush function clearFlushPromise(value) { - flushPromise = undefined; + self.flushPromise = undefined; flushingDefer.resolve(value); return value; } // Persist all queued objects - flushPromise = handler.persist(persistences, objects, self) - .then(clearFlushPromise, clearFlushPromise); + self.flushPromise = handler.persist( + self.persistences, + self.objects, + self + ).then(clearFlushPromise, clearFlushPromise); // Reset queue, etc. - persistences = {}; - objects = {}; - lastObservedSize = 0; - pendingTimeout = undefined; - activeDefer = $q.defer(); + self.persistences = {}; + self.objects = {}; + self.lastObservedSize = 0; + self.pendingTimeout = undefined; + self.activeDefer = $q.defer(); } - // Schedule a flushing of the queue (that is, plan to flush - // all objects in the queue) - function scheduleFlush() { - function maybeFlush() { - // Timeout fired, so clear it - pendingTimeout = undefined; - // Only flush when we've stopped receiving updates - (quiescent() ? flush : scheduleFlush)(); - // Update lastObservedSize to detect quiescence - lastObservedSize = Object.keys(persistences).length; - } - - // If we are already flushing the queue... - if (flushPromise) { - // Wait until that's over before considering a flush - flushPromise.then(maybeFlush); + function maybeFlush() { + // Timeout fired, so clear it + self.pendingTimeout = undefined; + // Only flush when we've stopped receiving updates + if (quiescent()) { + flush(); } else { - // Otherwise, schedule a flush on a timeout (to give - // a window for other updates to get aggregated) - pendingTimeout = pendingTimeout || - $timeout(maybeFlush, DELAY, false); + self.scheduleFlush(); } - - return activeDefer.promise; + // Update lastObservedSize to detect quiescence + self.lastObservedSize = Object.keys(self.persistences).length; } - // If no delay is provided, use a default - DELAY = DELAY || 0; + // If we are already flushing the queue... + if (self.flushPromise) { + // Wait until that's over before considering a flush + self.flushPromise.then(maybeFlush); + } else { + // Otherwise, schedule a flush on a timeout (to give + // a window for other updates to get aggregated) + self.pendingTimeout = self.pendingTimeout || + $timeout(maybeFlush, self.delay, false); + } - self = { - /** - * Queue persistence of a domain object. - * @param {DomainObject} domainObject the domain object - * @param {PersistenceCapability} persistence the object's - * undecorated persistence capability - * @memberof platform/persistence/queue.PersistenceQueueImpl# - */ - put: function (domainObject, persistence) { - var id = domainObject.getId(); - persistences[id] = persistence; - objects[id] = domainObject; - return scheduleFlush(); - } - }; + return self.activeDefer.promise; + }; - return self; - } + + /** + * Queue persistence of a domain object. + * @param {DomainObject} domainObject the domain object + * @param {PersistenceCapability} persistence the object's + * undecorated persistence capability + * @returns {Promise} a promise which will resolve upon persistence + */ + PersistenceQueueImpl.prototype.put = function (domainObject, persistence) { + var id = domainObject.getId(); + this.persistences[id] = persistence; + this.objects[id] = domainObject; + return this.scheduleFlush(); + }; return PersistenceQueueImpl; } diff --git a/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js b/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js index fddaebfead..a86fe60515 100644 --- a/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js +++ b/platform/persistence/queue/src/QueuingPersistenceCapabilityDecorator.js @@ -40,11 +40,21 @@ define( * * @memberof platform/persistence/queue * @constructor + * @implements {CapabilityService} + * @param {platform/persistence/queue.PersistenceQueue} persistenceQueue + * @param {CapabilityService} the decorated capability service */ function QueuingPersistenceCapabilityDecorator( persistenceQueue, capabilityService ) { + this.persistenceQueue = persistenceQueue; + this.capabilityService = capabilityService; + } + + QueuingPersistenceCapabilityDecorator.prototype.getCapabilities = function (model) { + var capabilityService = this.capabilityService, + persistenceQueue = this.persistenceQueue; function decoratePersistence(capabilities) { var originalPersistence = capabilities.persistence; @@ -53,8 +63,8 @@ define( // Get/instantiate the original var original = (typeof originalPersistence === 'function') ? - originalPersistence(domainObject) : - originalPersistence; + originalPersistence(domainObject) : + originalPersistence; // Provide a decorated version return new QueuingPersistenceCapability( @@ -67,35 +77,10 @@ define( return capabilities; } - function getCapabilities(model) { - return decoratePersistence( - capabilityService.getCapabilities(model) - ); - } - - return { - /** - * Get all capabilities associated with a given domain - * object. - * - * This returns a promise for an object containing key-value - * pairs, where keys are capability names and values are - * either: - * - * * Capability instances - * * Capability constructors (which take a domain object - * as their argument.) - * - * - * @param {*} model the object model - * @returns {Object.} all - * capabilities known to be valid for this model, as - * key-value pairs - * @memberof platform/persistence/queue.QueuingPersistenceCapabilityDecorator# - */ - getCapabilities: getCapabilities - }; - } + return decoratePersistence( + capabilityService.getCapabilities(model) + ); + }; return QueuingPersistenceCapabilityDecorator; } From 07a2065c111d29b29573850885a1eb4ff0ac037e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 14 Aug 2015 15:49:45 -0700 Subject: [PATCH 64/84] [Code Style] Use prototypes in policy bundle WTD-1482. --- platform/policy/src/PolicyActionDecorator.js | 34 ++++---- platform/policy/src/PolicyProvider.js | 91 +++++++++++--------- platform/policy/src/PolicyViewDecorator.js | 38 ++++---- 3 files changed, 82 insertions(+), 81 deletions(-) diff --git a/platform/policy/src/PolicyActionDecorator.js b/platform/policy/src/PolicyActionDecorator.js index 9b86a2692f..96dbd9498e 100644 --- a/platform/policy/src/PolicyActionDecorator.js +++ b/platform/policy/src/PolicyActionDecorator.js @@ -33,29 +33,25 @@ define( * @param {ActionService} actionService the service to decorate * @constructor * @memberof platform/policy + * @implements {ActionService} */ function PolicyActionDecorator(policyService, actionService) { - return { - /** - * Get actions which are applicable in this context. - * These will be filtered to remove any actions which - * are deemed inapplicable by policy. - * @param context the context in which the action will occur - * @returns {Action[]} applicable actions - * @memberof platform/policy.PolicyActionDecorator# - */ - getActions: function (context) { - // Check if an action is allowed by policy. - function allow(action) { - return policyService.allow('action', action, context); - } - - // Look up actions, filter out the disallowed ones. - return actionService.getActions(context).filter(allow); - } - }; + this.policyService = policyService; + this.actionService = actionService; } + PolicyActionDecorator.prototype.getActions = function (context) { + var policyService = this.policyService; + + // Check if an action is allowed by policy. + function allow(action) { + return policyService.allow('action', action, context); + } + + // Look up actions, filter out the disallowed ones. + return this.actionService.getActions(context).filter(allow); + }; + return PolicyActionDecorator; } ); diff --git a/platform/policy/src/PolicyProvider.js b/platform/policy/src/PolicyProvider.js index a15b296b1b..38858cadcc 100644 --- a/platform/policy/src/PolicyProvider.js +++ b/platform/policy/src/PolicyProvider.js @@ -53,12 +53,37 @@ define( * @returns {boolean} false if disallowed; otherwise, true */ + + /** + * The `policyService` handles decisions about what things + * are and are not allowed in certain contexts. + * @interface PolicyService + */ + + /** + * Check whether or not a certain decision is allowed by + * policy. + * @param {string} category a machine-readable identifier + * for the kind of decision being made + * @param candidate the object about which the decision is + * being made + * @param context the context in which the decision occurs + * @param {Function} [callback] callback to invoke with a + * string message describing the reason a decision + * was disallowed (if its disallowed) + * @returns {boolean} true if the decision is allowed, + * otherwise false. + * @method PolicyService#allow + */ + /** * Provides an implementation of `policyService` which consults * various policy extensions to determine whether or not a specific * decision should be allowed. * @memberof platform/policy * @constructor + * @implements {PolicyService} + * @param {Policy[]} policies the policies to enforce */ function PolicyProvider(policies) { var policyMap = {}; @@ -87,49 +112,33 @@ define( // Populate the map for subsequent lookup policies.forEach(addToMap); - - return { - /** - * Check whether or not a certain decision is allowed by - * policy. - * @param {string} category a machine-readable identifier - * for the kind of decision being made - * @param candidate the object about which the decision is - * being made - * @param context the context in which the decision occurs - * @param {Function} [callback] callback to invoke with a - * string message describing the reason a decision - * was disallowed (if its disallowed) - * @returns {boolean} true if the decision is allowed, - * otherwise false. - * @memberof platform/policy.PolicyProvider# - */ - allow: function (category, candidate, context, callback) { - var policyList = policyMap[category] || [], - i; - - // Iterate through policies. We do this instead of map or - // forEach so that we can return immediately if a policy - // chooses to disallow this decision. - for (i = 0; i < policyList.length; i += 1) { - // Consult the policy... - if (!policyList[i].allow(candidate, context)) { - // ...it disallowed, so pass its message to - // the callback (if any) - if (callback) { - callback(policyList[i].message); - } - // And return the failed result. - return false; - } - } - - // No policy disallowed this decision. - return true; - } - }; + this.policyMap = policyMap; } + PolicyProvider.prototype.allow = function (category, candidate, context, callback) { + var policyList = this.policyMap[category] || [], + i; + + // Iterate through policies. We do this instead of map or + // forEach so that we can return immediately if a policy + // chooses to disallow this decision. + for (i = 0; i < policyList.length; i += 1) { + // Consult the policy... + if (!policyList[i].allow(candidate, context)) { + // ...it disallowed, so pass its message to + // the callback (if any) + if (callback) { + callback(policyList[i].message); + } + // And return the failed result. + return false; + } + } + + // No policy disallowed this decision. + return true; + }; + return PolicyProvider; } ); diff --git a/platform/policy/src/PolicyViewDecorator.js b/platform/policy/src/PolicyViewDecorator.js index d1570ffa4e..c9ac54b173 100644 --- a/platform/policy/src/PolicyViewDecorator.js +++ b/platform/policy/src/PolicyViewDecorator.js @@ -33,29 +33,25 @@ define( * @param {ViewService} viewService the service to decorate * @constructor * @memberof platform/policy + * @implements {ViewService} */ - function PolicyActionDecorator(policyService, viewService) { - return { - /** - * Get views which are applicable to this domain object. - * These will be filtered to remove any views which - * are deemed inapplicable by policy. - * @param {DomainObject} the domain object to view - * @returns {View[]} applicable views - * @memberof platform/policy.PolicyViewDecorator# - */ - getViews: function (domainObject) { - // Check if an action is allowed by policy. - function allow(view) { - return policyService.allow('view', view, domainObject); - } - - // Look up actions, filter out the disallowed ones. - return viewService.getViews(domainObject).filter(allow); - } - }; + function PolicyViewDecorator(policyService, viewService) { + this.policyService = policyService; + this.viewService = viewService; } - return PolicyActionDecorator; + PolicyViewDecorator.prototype.getViews = function (domainObject) { + var policyService = this.policyService; + + // Check if an action is allowed by policy. + function allow(view) { + return policyService.allow('view', view, domainObject); + } + + // Look up actions, filter out the disallowed ones. + return this.viewService.getViews(domainObject).filter(allow); + }; + + return PolicyViewDecorator; } ); From 365134b085a3309bbf40522d16201e8997b9ecac Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 14 Aug 2015 16:10:41 -0700 Subject: [PATCH 65/84] [Code Style] Use prototypes in representation bundle WTD-1482 --- .../representation/src/MCTRepresentation.js | 19 +++ .../src/actions/ContextMenuAction.js | 129 +++++++++--------- .../src/gestures/ContextMenuGesture.js | 38 +++--- .../src/gestures/DragGesture.js | 24 ++-- .../src/gestures/DropGesture.js | 22 ++- .../src/gestures/GestureProvider.js | 115 +++++++++------- .../src/gestures/GestureRepresenter.js | 61 +++------ 7 files changed, 216 insertions(+), 192 deletions(-) diff --git a/platform/representation/src/MCTRepresentation.js b/platform/representation/src/MCTRepresentation.js index 8a02fa07e7..49b2ae0f57 100644 --- a/platform/representation/src/MCTRepresentation.js +++ b/platform/representation/src/MCTRepresentation.js @@ -238,6 +238,25 @@ define( }; } + /** + * A representer participates in the process of instantiating a + * representation of a domain object. + * + * @interface Representer + * @augments {Destroyable} + */ + /** + * Set the current representation in use, and the domain + * object being represented. + * + * @method Representer#represent + * @param {RepresentationDefinition} representation the + * definition of the representation in use + * @param {DomainObject} domainObject the domain object + * being represented + */ + + return MCTRepresentation; } ); diff --git a/platform/representation/src/actions/ContextMenuAction.js b/platform/representation/src/actions/ContextMenuAction.js index 9544f26ca9..14367c7f55 100644 --- a/platform/representation/src/actions/ContextMenuAction.js +++ b/platform/representation/src/actions/ContextMenuAction.js @@ -47,71 +47,78 @@ define( * @param $rootScope Angular's root scope * @param actionContexr the context in which the action * should be performed + * @implements {Action} */ function ContextMenuAction($compile, $document, $window, $rootScope, actionContext) { - - function perform() { - var winDim = [$window.innerWidth, $window.innerHeight], - eventCoors = [actionContext.event.pageX, actionContext.event.pageY], - menuDim = GestureConstants.MCT_MENU_DIMENSIONS, - body = $document.find('body'), - scope = $rootScope.$new(), - goLeft = eventCoors[0] + menuDim[0] > winDim[0], - goUp = eventCoors[1] + menuDim[1] > winDim[1], - menu; - - // Remove the context menu - function dismiss() { - menu.remove(); - body.off("click", dismiss); - dismissExistingMenu = undefined; - } - - // Dismiss any menu which was already showing - if (dismissExistingMenu) { - dismissExistingMenu(); - } - - // ...and record the presence of this menu. - dismissExistingMenu = dismiss; - - // Set up the scope, including menu positioning - scope.domainObject = actionContext.domainObject; - scope.menuStyle = {}; - scope.menuStyle[goLeft ? "right" : "left"] = - (goLeft ? (winDim[0] - eventCoors[0]) : eventCoors[0]) + 'px'; - scope.menuStyle[goUp ? "bottom" : "top"] = - (goUp ? (winDim[1] - eventCoors[1]) : eventCoors[1]) + 'px'; - scope.menuClass = { - "go-left": goLeft, - "go-up": goUp, - "context-menu-holder": true - }; - - // Create the context menu - menu = $compile(MENU_TEMPLATE)(scope); - - // Add the menu to the body - body.append(menu); - - // Stop propagation so that clicks on the menu do not close the menu - menu.on('mousedown', function (event) { - event.stopPropagation(); - }); - - // Dismiss the menu when body is clicked elsewhere - // ('mousedown' because 'click' breaks left-click context menus) - body.on('mousedown', dismiss); - - // Don't launch browser's context menu - actionContext.event.preventDefault(); - } - - return { - perform: perform - }; + this.$compile = $compile; + this.actionContext = actionContext; + this.getDocument = function () { return $document; }; + this.getWindow = function () { return $window; }; + this.getRootScope = function () { return $rootScope; }; } + ContextMenuAction.prototype.perform = function () { + var $compile = this.$compile, + $document = this.getDocument(), + $window = this.getWindow(), + $rootScope = this.getRootScope(), + actionContext = this.actionContext, + winDim = [$window.innerWidth, $window.innerHeight], + eventCoors = [actionContext.event.pageX, actionContext.event.pageY], + menuDim = GestureConstants.MCT_MENU_DIMENSIONS, + body = $document.find('body'), + scope = $rootScope.$new(), + goLeft = eventCoors[0] + menuDim[0] > winDim[0], + goUp = eventCoors[1] + menuDim[1] > winDim[1], + menu; + + // Remove the context menu + function dismiss() { + menu.remove(); + body.off("click", dismiss); + dismissExistingMenu = undefined; + } + + // Dismiss any menu which was already showing + if (dismissExistingMenu) { + dismissExistingMenu(); + } + + // ...and record the presence of this menu. + dismissExistingMenu = dismiss; + + // Set up the scope, including menu positioning + scope.domainObject = actionContext.domainObject; + scope.menuStyle = {}; + scope.menuStyle[goLeft ? "right" : "left"] = + (goLeft ? (winDim[0] - eventCoors[0]) : eventCoors[0]) + 'px'; + scope.menuStyle[goUp ? "bottom" : "top"] = + (goUp ? (winDim[1] - eventCoors[1]) : eventCoors[1]) + 'px'; + scope.menuClass = { + "go-left": goLeft, + "go-up": goUp, + "context-menu-holder": true + }; + + // Create the context menu + menu = $compile(MENU_TEMPLATE)(scope); + + // Add the menu to the body + body.append(menu); + + // Stop propagation so that clicks on the menu do not close the menu + menu.on('mousedown', function (event) { + event.stopPropagation(); + }); + + // Dismiss the menu when body is clicked elsewhere + // ('mousedown' because 'click' breaks left-click context menus) + body.on('mousedown', dismiss); + + // Don't launch browser's context menu + actionContext.event.preventDefault(); + }; + return ContextMenuAction; } ); diff --git a/platform/representation/src/gestures/ContextMenuGesture.js b/platform/representation/src/gestures/ContextMenuGesture.js index a0de0cce85..5d6d7c325f 100644 --- a/platform/representation/src/gestures/ContextMenuGesture.js +++ b/platform/representation/src/gestures/ContextMenuGesture.js @@ -36,33 +36,31 @@ define( * @memberof platform/representation * @constructor * @param element the jqLite-wrapped element which should exhibit - * the context mennu + * the context menu * @param {DomainObject} domainObject the object on which actions * in the context menu will be performed + * @implements {Gesture} */ function ContextMenuGesture(element, domainObject) { - var actionContext, - stop; - + function showMenu(event) { + domainObject.getCapability('action').perform({ + key: 'menu', + domainObject: domainObject, + event: event + }); + } + // When context menu event occurs, show object actions instead - element.on('contextmenu', function (event) { - actionContext = {key: 'menu', domainObject: domainObject, event: event}; - stop = domainObject.getCapability('action').perform(actionContext); - }); - - return { - /** - * Detach any event handlers associated with this gesture. - * @method - * @memberof ContextMenuGesture - * @memberof platform/representation.ContextMenuGesture# - */ - destroy: function () { - element.off('contextmenu', stop); - } - }; + element.on('contextmenu', showMenu); + + this.showMenuCallback = showMenu; + this.element = element; } + ContextMenuGesture.prototype.destroy = function () { + this.element.off('contextmenu', this.showMenu); + }; + return ContextMenuGesture; } ); diff --git a/platform/representation/src/gestures/DragGesture.js b/platform/representation/src/gestures/DragGesture.js index 6a4dfb0d63..f240aa156e 100644 --- a/platform/representation/src/gestures/DragGesture.js +++ b/platform/representation/src/gestures/DragGesture.js @@ -35,6 +35,7 @@ define( * * @memberof platform/representation * @constructor + * @implements {Gesture} * @param $log Angular's logging service * @param element the jqLite-wrapped element which should become * draggable @@ -104,22 +105,19 @@ define( element.on('dragstart', startDrag); element.on('dragend', endDrag); - return { - /** - * Detach any event handlers associated with this gesture. - * @memberof DragGesture - * @method - * @memberof platform/representation.DragGesture# - */ - destroy: function () { - // Detach listener - element.removeAttr('draggable'); - element.off('dragstart', startDrag); - } - }; + this.element = element; + this.startDragCallback = startDrag; + this.endDragCallback = endDrag; } + DragGesture.prototype.destroy = function () { + // Detach listener + this.element.removeAttr('draggable'); + this.element.off('dragstart', this.startDragCallback); + this.element.off('dragend', this.endDragCallback); + }; + return DragGesture; } ); diff --git a/platform/representation/src/gestures/DropGesture.js b/platform/representation/src/gestures/DropGesture.js index 7afffc3c03..bfcb85d3bb 100644 --- a/platform/representation/src/gestures/DropGesture.js +++ b/platform/representation/src/gestures/DropGesture.js @@ -32,7 +32,7 @@ define( /** * A DropGesture adds and maintains event handlers upon an element * such that it may act as a drop target for drag-drop composition. - + * * @memberof platform/representation * @constructor * @param $q Angular's $q, for promise handling @@ -40,7 +40,6 @@ define( * @param {DomainObject} domainObject the domain object whose * composition should be modified as a result of the drop. */ - function DropGesture(dndService, $q, element, domainObject) { var actionCapability = domainObject.getCapability('action'), action; // Action for the drop, when it occurs @@ -122,19 +121,16 @@ define( element.on('drop', drop); } - return { - /** - * Detach any event handlers associated with this gesture. - * @memberof platform/representation.DropGesture# - */ - destroy: function () { - element.off('dragover', dragOver); - element.off('drop', drop); - } - }; - + this.element = element; + this.dragOverCallback = dragOver; + this.dropCallback = drop; } + DropGesture.prototype.destroy = function () { + this.element.off('dragover', this.dragOverCallback); + this.element.off('drop', this.dropCallback); + }; + return DropGesture; } diff --git a/platform/representation/src/gestures/GestureProvider.js b/platform/representation/src/gestures/GestureProvider.js index 255c33a28f..30b463505d 100644 --- a/platform/representation/src/gestures/GestureProvider.js +++ b/platform/representation/src/gestures/GestureProvider.js @@ -29,6 +29,29 @@ define( function () { "use strict"; + /** + * Handles the attachment of gestures (responses to DOM events, + * generally) to DOM elements which represent domain objects. + * + * @interface GestureService + */ + /** + * Attach a set of gestures (indicated by key) to a + * DOM element which represents a specific domain object. + * @method GestureService#attachGestures + * @param element the jqLite-wrapped DOM element which the + * user will interact with + * @param {DomainObject} domainObject the domain object which + * is represented by that element + * @param {string[]} gestureKeys an array of keys identifying + * which gestures should apply; these will be matched + * against the keys defined in the gestures' extension + * definitions + * @return {Destroyable} an object with a `destroy` + * method which can (and should) be used when + * gestures should no longer be applied to an element. + */ + /** * The GestureProvider exposes defined gestures. Gestures are used * do describe and handle general-purpose interactions with the DOM @@ -41,6 +64,7 @@ define( * where they are used. * * @memberof platform/representation + * @implements {GestureService} * @constructor * @param {Gesture[]} gestures an array of all gestures which are * available as extensions @@ -48,19 +72,28 @@ define( function GestureProvider(gestures) { var gestureMap = {}; - function releaseGesture(gesture) { - // Invoke the gesture's "destroy" method (if there is one) - // to release any held resources and detach event handlers. - if (gesture && gesture.destroy) { - gesture.destroy(); - } - } + // Assemble all gestures into a map, for easy look up + gestures.forEach(function (gesture) { + gestureMap[gesture.key] = gesture; + }); - function attachGestures(element, domainObject, gestureKeys) { - // Look up the desired gestures, filter for applicability, - // and instantiate them. Maintain a reference to allow them - // to be destroyed as a group later. - var attachedGestures = gestureKeys.map(function (key) { + this.gestureMap = gestureMap; + } + + function releaseGesture(gesture) { + // Invoke the gesture's "destroy" method (if there is one) + // to release any held resources and detach event handlers. + if (gesture && gesture.destroy) { + gesture.destroy(); + } + } + + GestureProvider.prototype.attachGestures = function attachGestures(element, domainObject, gestureKeys) { + // Look up the desired gestures, filter for applicability, + // and instantiate them. Maintain a reference to allow them + // to be destroyed as a group later. + var gestureMap = this.gestureMap, + attachedGestures = gestureKeys.map(function (key) { return gestureMap[key]; }).filter(function (Gesture) { return Gesture !== undefined && (Gesture.appliesTo ? @@ -70,42 +103,32 @@ define( return new Gesture(element, domainObject); }); - return { - destroy: function () { - // Just call all the individual "destroy" methods - attachedGestures.forEach(releaseGesture); - } - }; - } - - // Assemble all gestures into a map, for easy look up - gestures.forEach(function (gesture) { - gestureMap[gesture.key] = gesture; - }); - - return { - /** - * Attach a set of gestures (indicated by key) to a - * DOM element which represents a specific domain object. - * @method - * @memberof GestureProvider - * @param element the jqLite-wrapped DOM element which the - * user will interact with - * @param {DomainObject} domainObject the domain object which - * is represented by that element - * @param {string[]} gestureKeys an array of keys identifying - * which gestures should apply; these will be matched - * against the keys defined in the gestures' extension - * definitions - * @return {{ destroy: function }} an object with a `destroy` - * method which can (and should) be used when a - * gesture should no longer be applied to an element. - * @memberof platform/representation.GestureProvider# - */ - attachGestures: attachGestures + destroy: function () { + // Just call all the individual "destroy" methods + attachedGestures.forEach(releaseGesture); + } }; - } + }; + + /** + * A destroyable object may have resources allocated which require + * explicit release. + * + * @interface Destroyable + */ + /** + * Release any resources associated with this object. + * + * @method Destroyable#destroy + */ + + /** + * A gesture describes manners in which certain representations of + * domain objects may respond to DOM events upon those representations. + * @interface Gesture + * @augments Destroyable + */ return GestureProvider; } diff --git a/platform/representation/src/gestures/GestureRepresenter.js b/platform/representation/src/gestures/GestureRepresenter.js index db74d923eb..9353722ae8 100644 --- a/platform/representation/src/gestures/GestureRepresenter.js +++ b/platform/representation/src/gestures/GestureRepresenter.js @@ -38,50 +38,33 @@ define( * @param {Scope} scope the Angular scope for this representation * @param element the JQLite-wrapped mct-representation element * @constructor + * @implements {Representer} * @memberof platform/representation */ function GestureRepresenter(gestureService, scope, element) { - var gestureHandle; - - function destroy() { - // Release any resources associated with these gestures - if (gestureHandle) { - gestureHandle.destroy(); - } - } - - function represent(representation, domainObject) { - // Clear out any existing gestures - destroy(); - - // Attach gestures - by way of the service. - gestureHandle = gestureService.attachGestures( - element, - domainObject, - (representation || {}).gestures || [] - ); - } - - return { - /** - * Set the current representation in use, and the domain - * object being represented. - * - * @param {RepresentationDefinition} representation the - * definition of the representation in use - * @param {DomainObject} domainObject the domain object - * being represented - * @memberof platform/representation.GestureRepresenter# - */ - represent: represent, - /** - * Release any resources associated with this representer. - * @memberof platform/representation.GestureRepresenter# - */ - destroy: destroy - }; + this.gestureService = gestureService; + this.element = element; } + GestureRepresenter.prototype.represent = function represent(representation, domainObject) { + // Clear out any existing gestures + this.destroy(); + + // Attach gestures - by way of the service. + this.gestureHandle = this.gestureService.attachGestures( + this.element, + domainObject, + (representation || {}).gestures || [] + ); + }; + + GestureRepresenter.prototype.destroy = function () { + // Release any resources associated with these gestures + if (this.gestureHandle) { + this.gestureHandle.destroy(); + } + }; + return GestureRepresenter; } ); From 1ea6f7620e235c6500a98c6ffd9ea78c29a14aa1 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 14 Aug 2015 16:14:15 -0700 Subject: [PATCH 66/84] [Code Style] Begin refactoring telemetry bundle Begin refactoring telemetry bundle to use prototype for methods, WTD-1482. --- platform/telemetry/src/TelemetryAggregator.js | 137 +++++++++--------- 1 file changed, 68 insertions(+), 69 deletions(-) diff --git a/platform/telemetry/src/TelemetryAggregator.js b/platform/telemetry/src/TelemetryAggregator.js index d824518207..fb4cf81fe0 100644 --- a/platform/telemetry/src/TelemetryAggregator.js +++ b/platform/telemetry/src/TelemetryAggregator.js @@ -31,6 +31,32 @@ define( function () { "use strict"; + /** + * Request telemetry data. + * @param {TelemetryRequest[]} requests and array of + * requests to be handled + * @returns {Promise} a promise for telemetry data + * which may (or may not, depending on + * availability) satisfy the requests + * @method TelemetryService#requestTelemetry + */ + /** + * Subscribe to streaming updates to telemetry data. + * The provided callback will be invoked as new + * telemetry becomes available; as an argument, it + * will receive an object of key-value pairs, where + * keys are source identifiers and values are objects + * of key-value pairs, where keys are point identifiers + * and values are TelemetrySeries objects containing + * the latest streaming telemetry. + * @param {Function} callback the callback to invoke + * @param {TelemetryRequest[]} requests an array of + * requests to be subscribed upon + * @returns {Function} a function which can be called + * to unsubscribe + * @method TelmetryService#subscribe + */ + /** * A telemetry aggregator makes many telemetry providers * appear as one. @@ -39,77 +65,50 @@ define( * @constructor */ function TelemetryAggregator($q, telemetryProviders) { - - // Merge the results from many providers into one - // result object. - function mergeResults(results) { - var merged = {}; - - results.forEach(function (result) { - Object.keys(result).forEach(function (k) { - merged[k] = result[k]; - }); - }); - - return merged; - } - - // Request telemetry from all providers; once they've - // responded, merge the results into one result object. - function requestTelemetry(requests) { - return $q.all(telemetryProviders.map(function (provider) { - return provider.requestTelemetry(requests); - })).then(mergeResults); - } - - // Subscribe to updates from all providers - function subscribe(callback, requests) { - var unsubscribes = telemetryProviders.map(function (provider) { - return provider.subscribe(callback, requests); - }); - - // Return an unsubscribe function that invokes unsubscribe - // for all providers. - return function () { - unsubscribes.forEach(function (unsubscribe) { - if (unsubscribe) { - unsubscribe(); - } - }); - }; - } - - return { - /** - * Request telemetry data. - * @param {TelemetryRequest[]} requests and array of - * requests to be handled - * @returns {Promise} a promise for telemetry data - * which may (or may not, depending on - * availability) satisfy the requests - * @memberof platform/telemetry.TelemetryAggregator# - */ - requestTelemetry: requestTelemetry, - /** - * Subscribe to streaming updates to telemetry data. - * The provided callback will be invoked as new - * telemetry becomes available; as an argument, it - * will receive an object of key-value pairs, where - * keys are source identifiers and values are objects - * of key-value pairs, where keys are point identifiers - * and values are TelemetrySeries objects containing - * the latest streaming telemetry. - * @param {Function} callback the callback to invoke - * @param {TelemetryRequest[]} requests an array of - * requests to be subscribed upon - * @returns {Function} a function which can be called - * to unsubscribe - * @memberof platform/telemetry.TelemetryAggregator# - */ - subscribe: subscribe - }; + this.$q = $q; + this.telemetryProviders = telemetryProviders; } + // Merge the results from many providers into one + // result object. + function mergeResults(results) { + var merged = {}; + + results.forEach(function (result) { + Object.keys(result).forEach(function (k) { + merged[k] = result[k]; + }); + }); + + return merged; + } + + // Request telemetry from all providers; once they've + // responded, merge the results into one result object. + TelemetryAggregator.prototype.requestTelemetry = function (requests) { + return this.$q.all(this.telemetryProviders.map(function (provider) { + return provider.requestTelemetry(requests); + })).then(mergeResults); + }; + + // Subscribe to updates from all providers + TelemetryAggregator.prototype.subscribe = function (callback, requests) { + var unsubscribes = this.telemetryProviders.map(function (provider) { + return provider.subscribe(callback, requests); + }); + + // Return an unsubscribe function that invokes unsubscribe + // for all providers. + return function () { + unsubscribes.forEach(function (unsubscribe) { + if (unsubscribe) { + unsubscribe(); + } + }); + }; + }; + + return TelemetryAggregator; } ); From 2ccca016a5cb5e0c65d2168c01123f454537807d Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 14 Aug 2015 16:47:20 -0700 Subject: [PATCH 67/84] [Code Style] Use prototypes in telemetry bundle WTD-1482 --- platform/telemetry/src/TelemetryCapability.js | 263 ++++++++-------- platform/telemetry/src/TelemetryController.js | 1 + platform/telemetry/src/TelemetryDelegator.js | 61 ++-- platform/telemetry/src/TelemetryFormatter.js | 60 ++-- platform/telemetry/src/TelemetryHandler.js | 34 ++- platform/telemetry/src/TelemetryQueue.js | 86 +++--- platform/telemetry/src/TelemetrySubscriber.js | 59 ++-- .../telemetry/src/TelemetrySubscription.js | 289 +++++++++--------- platform/telemetry/src/TelemetryTable.js | 51 +--- 9 files changed, 443 insertions(+), 461 deletions(-) diff --git a/platform/telemetry/src/TelemetryCapability.js b/platform/telemetry/src/TelemetryCapability.js index 041379e497..1fbd12a691 100644 --- a/platform/telemetry/src/TelemetryCapability.js +++ b/platform/telemetry/src/TelemetryCapability.js @@ -42,154 +42,147 @@ define( * at the specific data which is appropriate to the domain object.) * * @memberof platform/telemetry + * @implements {Capability} * @constructor */ function TelemetryCapability($injector, $q, $log, domainObject) { - var telemetryService, - subscriptions = [], - unsubscribeFunction; - // We could depend on telemetryService directly, but - // there isn't a platform implementation of this; - function getTelemetryService() { - if (telemetryService === undefined) { - try { - telemetryService = - $injector.get("telemetryService"); - } catch (e) { - // $injector should throw if telemetryService - // is unavailable or unsatisfiable. - $log.warn("Telemetry service unavailable"); - telemetryService = null; - } + // there isn't a platform implementation of this. + this.initializeTelemetryService = function () { + try { + return (this.telemetryService = + $injector.get("telemetryService")); + } catch (e) { + // $injector should throw if telemetryService + // is unavailable or unsatisfiable. + $log.warn("Telemetry service unavailable"); + return (this.telemetryService = null); } - return telemetryService; - } - - // Build a request object. This takes the request that was - // passed to the capability, and adds source, id, and key - // fields associated with the object (from its type definition - // and/or its model) - function buildRequest(request) { - // Start with any "telemetry" field in type; use that as a - // basis for the request. - var type = domainObject.getCapability("type"), - typeRequest = (type && type.getDefinition().telemetry) || {}, - modelTelemetry = domainObject.getModel().telemetry, - fullRequest = Object.create(typeRequest); - - // Add properties from the telemetry field of this - // specific domain object. - Object.keys(modelTelemetry).forEach(function (k) { - fullRequest[k] = modelTelemetry[k]; - }); - - // Add properties from this specific requestData call. - Object.keys(request).forEach(function (k) { - fullRequest[k] = request[k]; - }); - - // Ensure an ID and key are present - if (!fullRequest.id) { - fullRequest.id = domainObject.getId(); - } - if (!fullRequest.key) { - fullRequest.key = domainObject.getId(); - } - - return fullRequest; - } - - // Issue a request for telemetry data - function requestTelemetry(request) { - // Bring in any defaults from the object model - var fullRequest = buildRequest(request || {}), - source = fullRequest.source, - key = fullRequest.key; - - // Pull out the relevant field from the larger, - // structured response. - function getRelevantResponse(response) { - return ((response || {})[source] || {})[key] || - EMPTY_SERIES; - } - - // Issue a request to the service - function requestTelemetryFromService() { - return telemetryService.requestTelemetry([fullRequest]); - } - - // If a telemetryService is not available, - // getTelemetryService() should reject, and this should - // bubble through subsequent then calls. - return getTelemetryService() && - requestTelemetryFromService() - .then(getRelevantResponse); - } - - // Listen for real-time and/or streaming updates - function subscribe(callback, request) { - var fullRequest = buildRequest(request || {}); - - // Unpack the relevant telemetry series - function update(telemetries) { - var source = fullRequest.source, - key = fullRequest.key, - result = ((telemetries || {})[source] || {})[key]; - if (result) { - callback(result); - } - } - - return getTelemetryService() && - telemetryService.subscribe(update, [fullRequest]); - } - - return { - /** - * Request telemetry data for this specific domain object. - * @param {TelemetryRequest} [request] parameters for this - * specific request - * @returns {Promise} a promise for the resulting telemetry - * object - * @memberof platform/telemetry.TelemetryCapability# - */ - requestData: requestTelemetry, - - /** - * Get metadata about this domain object's associated - * telemetry. - * @memberof platform/telemetry.TelemetryCapability# - */ - getMetadata: function () { - // metadata just looks like a request, - // so use buildRequest to bring in both - // type-level and object-level telemetry - // properties - return buildRequest({}); - }, - - /** - * Subscribe to updates to telemetry data for this domain - * object. - * @param {Function} callback a function to call when new - * data becomes available; the telemetry series - * containing the data will be given as an argument. - * @param {TelemetryRequest} [request] parameters for the - * subscription request - * @memberof platform/telemetry.TelemetryCapability# - */ - subscribe: subscribe }; + + + this.$q = $q; + this.$log = $log; + this.domainObject = domainObject; } + // Build a request object. This takes the request that was + // passed to the capability, and adds source, id, and key + // fields associated with the object (from its type definition + // and/or its model) + TelemetryCapability.prototype.buildRequest = function (request) { + // Start with any "telemetry" field in type; use that as a + // basis for the request. + var domainObject = this.domainObject, + type = domainObject.getCapability("type"), + typeRequest = (type && type.getDefinition().telemetry) || {}, + modelTelemetry = domainObject.getModel().telemetry, + fullRequest = Object.create(typeRequest); + + // Add properties from the telemetry field of this + // specific domain object. + Object.keys(modelTelemetry).forEach(function (k) { + fullRequest[k] = modelTelemetry[k]; + }); + + // Add properties from this specific requestData call. + Object.keys(request).forEach(function (k) { + fullRequest[k] = request[k]; + }); + + // Ensure an ID and key are present + if (!fullRequest.id) { + fullRequest.id = domainObject.getId(); + } + if (!fullRequest.key) { + fullRequest.key = domainObject.getId(); + } + + return fullRequest; + }; + + + /** + * Request telemetry data for this specific domain object. + * @param {TelemetryRequest} [request] parameters for this + * specific request + * @returns {Promise} a promise for the resulting telemetry + * object + */ + TelemetryCapability.prototype.requestData = function requestTelemetry(request) { + // Bring in any defaults from the object model + var fullRequest = this.buildRequest(request || {}), + source = fullRequest.source, + key = fullRequest.key, + telemetryService = this.telemetryService || + this.initializeTelemetryService(); // Lazy initialization + + // Pull out the relevant field from the larger, + // structured response. + function getRelevantResponse(response) { + return ((response || {})[source] || {})[key] || + EMPTY_SERIES; + } + + // Issue a request to the service + function requestTelemetryFromService() { + return telemetryService.requestTelemetry([fullRequest]); + } + + // If a telemetryService is not available, + // getTelemetryService() should reject, and this should + // bubble through subsequent then calls. + return telemetryService && + requestTelemetryFromService().then(getRelevantResponse); + }; + + /** + * Get metadata about this domain object's associated + * telemetry. + * @returns {TelemetryMetadata} metadata about this object's telemetry + */ + TelemetryCapability.prototype.getMetadata = function () { + // metadata just looks like a request, + // so use buildRequest to bring in both + // type-level and object-level telemetry + // properties + return (this.metadata = this.metadata || this.buildRequest({})); + }; + + /** + * Subscribe to updates to telemetry data for this domain + * object. + * @param {Function} callback a function to call when new + * data becomes available; the telemetry series + * containing the data will be given as an argument. + * @param {TelemetryRequest} [request] parameters for the + * subscription request + */ + TelemetryCapability.prototype.subscribe = function subscribe(callback, request) { + var fullRequest = this.buildRequest(request || {}), + telemetryService = this.telemetryService || + this.initializeTelemetryService(); // Lazy initialization + + // Unpack the relevant telemetry series + function update(telemetries) { + var source = fullRequest.source, + key = fullRequest.key, + result = ((telemetries || {})[source] || {})[key]; + if (result) { + callback(result); + } + } + + return telemetryService && + telemetryService.subscribe(update, [fullRequest]); + }; + /** * The telemetry capability is applicable when a * domain object model has a "telemetry" field. */ TelemetryCapability.appliesTo = function (model) { - return (model && - model.telemetry) ? true : false; + return (model && model.telemetry) ? true : false; }; return TelemetryCapability; diff --git a/platform/telemetry/src/TelemetryController.js b/platform/telemetry/src/TelemetryController.js index 3334baf48d..83279252d5 100644 --- a/platform/telemetry/src/TelemetryController.js +++ b/platform/telemetry/src/TelemetryController.js @@ -36,6 +36,7 @@ define( * * @memberof platform/telemetry * @constructor + * @deprecated use platform/telemetry.TelemetryHandler instead */ function TelemetryController($scope, $q, $timeout, $log) { diff --git a/platform/telemetry/src/TelemetryDelegator.js b/platform/telemetry/src/TelemetryDelegator.js index 865503154d..37fd1bedbf 100644 --- a/platform/telemetry/src/TelemetryDelegator.js +++ b/platform/telemetry/src/TelemetryDelegator.js @@ -33,37 +33,40 @@ define( * @memberof platform/telemetry */ function TelemetryDelegator($q) { - return { - /** - * Promise telemetry-providing objects associated with - * this domain object (either the domain object itself, - * or the objects it delegates) - * @returns {Promise.} domain objects with - * a telemetry capability - * @memberof platform/telemetry.TelemetryDelegator# - */ - promiseTelemetryObjects: function (domainObject) { - // If object has been cleared, there are no relevant - // telemetry-providing domain objects. - if (!domainObject) { - return $q.when([]); - } - - // Otherwise, try delegation first, and attach the - // object itself if it has a telemetry capability. - return $q.when(domainObject.useCapability( - "delegation", - "telemetry" - )).then(function (result) { - var head = domainObject.hasCapability("telemetry") ? - [ domainObject ] : [], - tail = result || []; - return head.concat(tail); - }); - } - }; + this.$q = $q; } + /** + * Promise telemetry-providing objects associated with + * this domain object (either the domain object itself, + * or the objects it delegates) + * @param {DomainObject} the domain object which may have + * or delegate telemetry + * @returns {Promise.} domain objects with + * a telemetry capability + */ + TelemetryDelegator.prototype.promiseTelemetryObjects = function (domainObject) { + var $q = this.$q; + + // If object has been cleared, there are no relevant + // telemetry-providing domain objects. + if (!domainObject) { + return $q.when([]); + } + + // Otherwise, try delegation first, and attach the + // object itself if it has a telemetry capability. + return $q.when(domainObject.useCapability( + "delegation", + "telemetry" + )).then(function (result) { + var head = domainObject.hasCapability("telemetry") ? + [ domainObject ] : [], + tail = result || []; + return head.concat(tail); + }); + }; + return TelemetryDelegator; } ); diff --git a/platform/telemetry/src/TelemetryFormatter.js b/platform/telemetry/src/TelemetryFormatter.js index 277ad0ca24..bbd4cf100c 100644 --- a/platform/telemetry/src/TelemetryFormatter.js +++ b/platform/telemetry/src/TelemetryFormatter.js @@ -39,41 +39,35 @@ define( * @constructor */ function TelemetryFormatter() { - function formatDomainValue(v, key) { - return isNaN(v) ? "" : moment.utc(v).format(DATE_FORMAT); - } - - function formatRangeValue(v, key) { - return isNaN(v) ? v : v.toFixed(3); - } - - return { - /** - * Format a domain value. - * @param {number} v the domain value; a timestamp - * in milliseconds since start of 1970 - * @param {string} [key] the key which identifies the - * domain; if unspecified or unknown, this will - * be treated as a standard timestamp. - * @returns {string} a textual representation of the - * data and time, suitable for display. - * @memberof platform/telemetry.TelemetryFormatter# - */ - formatDomainValue: formatDomainValue, - /** - * Format a range value. - * @param {number} v the range value; a numeric value - * @param {string} [key] the key which identifies the - * range; if unspecified or unknown, this will - * be treated as a numeric value. - * @returns {string} a textual representation of the - * value, suitable for display. - * @memberof platform/telemetry.TelemetryFormatter# - */ - formatRangeValue: formatRangeValue - }; } + /** + * Format a domain value. + * @param {number} v the domain value; a timestamp + * in milliseconds since start of 1970 + * @param {string} [key] the key which identifies the + * domain; if unspecified or unknown, this will + * be treated as a standard timestamp. + * @returns {string} a textual representation of the + * data and time, suitable for display. + */ + TelemetryFormatter.prototype.formatDomainValue = function (v, key) { + return isNaN(v) ? "" : moment.utc(v).format(DATE_FORMAT); + }; + + /** + * Format a range value. + * @param {number} v the range value; a numeric value + * @param {string} [key] the key which identifies the + * range; if unspecified or unknown, this will + * be treated as a numeric value. + * @returns {string} a textual representation of the + * value, suitable for display. + */ + TelemetryFormatter.prototype.formatRangeValue = function (v, key) { + return isNaN(v) ? String(v) : v.toFixed(VALUE_FORMAT_DIGITS); + }; + return TelemetryFormatter; } ); diff --git a/platform/telemetry/src/TelemetryHandler.js b/platform/telemetry/src/TelemetryHandler.js index f600f52cb7..cd0df98724 100644 --- a/platform/telemetry/src/TelemetryHandler.js +++ b/platform/telemetry/src/TelemetryHandler.js @@ -36,19 +36,31 @@ define( * @param $q Angular's $q */ function TelemetryHandler($q, telemetrySubscriber) { - return { - handle: function (domainObject, callback, lossless) { - var subscription = telemetrySubscriber.subscribe( - domainObject, - callback, - lossless - ); - - return new TelemetryHandle($q, subscription); - } - }; + this.$q = $q; + this.telemetrySubscriber = telemetrySubscriber; } + /** + * Start receiving telemetry associated with this domain object + * (either directly, or via delegation.) + * @param {DomainObject} domainObject the domain object + * @param {Function} callback callback to invoke when new data is + * available + * @param {boolean} lossless true if the callback should be invoked + * one separate time for each new latest value + * @returns {TelemetryHandle} a handle to telemetry data + * associated with this object + */ + TelemetryHandler.prototype.handle = function (domainObject, callback, lossless) { + var subscription = this.telemetrySubscriber.subscribe( + domainObject, + callback, + lossless + ); + + return new TelemetryHandle(this.$q, subscription); + }; + return TelemetryHandler; } diff --git a/platform/telemetry/src/TelemetryQueue.js b/platform/telemetry/src/TelemetryQueue.js index b5da77d717..d51c42a98f 100644 --- a/platform/telemetry/src/TelemetryQueue.js +++ b/platform/telemetry/src/TelemetryQueue.js @@ -34,6 +34,7 @@ define( * objects.) * @memberof platform/telemetry * @constructor + * @implements {platform/telemetry.TelemetryPool} */ function TelemetryQueue() { // General approach here: @@ -60,9 +61,37 @@ define( // 0 1 2 3 4 // a * * * * * // b * * * - // c * * * - var queue = [], - counts = {}; + // c * * * + + this.queue = []; + this.counts = {}; + } + + + TelemetryQueue.prototype.isEmpty = function () { + return this.queue.length < 1; + }; + + TelemetryQueue.prototype.poll = function () { + var counts = this.counts; + + // Decrement counts for a specific key + function decrementCount(key) { + if (counts[key] < 2) { + delete counts[key]; + } else { + counts[key] -= 1; + } + } + + // Decrement counts for the object that will be popped + Object.keys(counts).forEach(decrementCount); + return this.queue.shift(); + }; + + TelemetryQueue.prototype.put = function (key, value) { + var queue = this.queue, + counts = this.counts; // Look up an object in the queue that does not have a value // assigned to this key (or, add a new one) @@ -71,7 +100,7 @@ define( // Track the largest free position for this key counts[key] = index + 1; - + // If it's before the end of the queue, add it there if (index < queue.length) { return queue[index]; @@ -84,54 +113,9 @@ define( queue.push(object); return object; } - - // Decrement counts for a specific key - function decrementCount(key) { - if (counts[key] < 2) { - delete counts[key]; - } else { - counts[key] -= 1; - } - } - - // Decrement all counts - function decrementCounts() { - Object.keys(counts).forEach(decrementCount); - } - return { - /** - * Check if any value groups remain in this pool. - * @return {boolean} true if value groups remain - * @memberof platform/telemetry.TelemetryQueue# - */ - isEmpty: function () { - return queue.length < 1; - }, - /** - * Retrieve the next value group from this pool. - * This gives an object containing key-value pairs, - * where keys and values correspond to the arguments - * given to previous put functions. - * @return {object} key-value pairs - * @memberof platform/telemetry.TelemetryQueue# - */ - poll: function () { - // Decrement counts for the object that will be popped - decrementCounts(); - return queue.shift(); - }, - /** - * Put a key-value pair into the pool. - * @param {string} key the key to store the value under - * @param {*} value the value to store - * @memberof platform/telemetry.TelemetryQueue# - */ - put: function (key, value) { - getFreeObject(key)[key] = value; - } - }; - } + getFreeObject(key)[key] = value; + }; return TelemetryQueue; } diff --git a/platform/telemetry/src/TelemetrySubscriber.js b/platform/telemetry/src/TelemetrySubscriber.js index 7f8a6fd58e..c6e7ec0bf1 100644 --- a/platform/telemetry/src/TelemetrySubscriber.js +++ b/platform/telemetry/src/TelemetrySubscriber.js @@ -44,39 +44,36 @@ define( * @param $timeout Angular's $timeout */ function TelemetrySubscriber($q, $timeout) { - return { - /** - * Subscribe to streaming telemetry updates - * associated with this domain object (either - * directly or via capability delegation.) - * - * @param {DomainObject} domainObject the object whose - * associated telemetry data is of interest - * @param {Function} callback a function to invoke - * when new data has become available. - * @param {boolean} lossless flag to indicate whether the - * callback should be notified for all values - * (otherwise, multiple values in quick succession - * will call back with only the latest value.) - * @returns {TelemetrySubscription} the subscription, - * which will provide access to latest values. - * - * @method - * @memberof TelemetrySubscriber - * @memberof platform/telemetry.TelemetrySubscriber# - */ - subscribe: function (domainObject, callback, lossless) { - return new TelemetrySubscription( - $q, - $timeout, - domainObject, - callback, - lossless - ); - } - }; + this.$q = $q; + this.$timeout = $timeout; } + /** + * Subscribe to streaming telemetry updates + * associated with this domain object (either + * directly or via capability delegation.) + * + * @param {DomainObject} domainObject the object whose + * associated telemetry data is of interest + * @param {Function} callback a function to invoke + * when new data has become available. + * @param {boolean} lossless flag to indicate whether the + * callback should be notified for all values + * (otherwise, multiple values in quick succession + * will call back with only the latest value.) + * @returns {platform/telemetry.TelemetrySubscription} the + * subscription, which will provide access to latest values. + */ + TelemetrySubscriber.prototype.subscribe = function (domainObject, callback, lossless) { + return new TelemetrySubscription( + this.$q, + this.$timeout, + domainObject, + callback, + lossless + ); + }; + return TelemetrySubscriber; } ); diff --git a/platform/telemetry/src/TelemetrySubscription.js b/platform/telemetry/src/TelemetrySubscription.js index b4ecdd4770..8b4d7d7a9c 100644 --- a/platform/telemetry/src/TelemetrySubscription.js +++ b/platform/telemetry/src/TelemetrySubscription.js @@ -26,6 +26,32 @@ define( function (TelemetryQueue, TelemetryTable, TelemetryDelegator) { "use strict"; + /** + * A pool of telemetry values. + * @interface platform/telemetry.TelemetryPool + * @private + */ + /** + * Check if any value groups remain in this pool. + * @return {boolean} true if value groups remain + * @method platform/telemetry.TelemetryPool#isEmpty + */ + /** + * Retrieve the next value group from this pool. + * This gives an object containing key-value pairs, + * where keys and values correspond to the arguments + * given to previous put functions. + * @return {object} key-value pairs + * @method platform/telemetry.TelemetryPool#poll + */ + /** + * Put a key-value pair into the pool. + * @param {string} key the key to store the value under + * @param {*} value the value to store + * @method platform/telemetry.TelemetryPool#put + */ + + /** * A TelemetrySubscription tracks latest values for streaming * telemetry data and handles notifying interested observers. @@ -52,14 +78,9 @@ define( * the callback once, with access to the latest data */ function TelemetrySubscription($q, $timeout, domainObject, callback, lossless) { - var delegator = new TelemetryDelegator($q), - unsubscribePromise, - telemetryObjectPromise, - latestValues = {}, - telemetryObjects = [], + var self = this, + delegator = new TelemetryDelegator($q), pool = lossless ? new TelemetryQueue() : new TelemetryTable(), - metadatas, - unlistenToMutation, updatePending; // Look up domain objects which have telemetry capabilities. @@ -72,7 +93,7 @@ define( function updateValuesFromPool() { var values = pool.poll(); Object.keys(values).forEach(function (k) { - latestValues[k] = values[k]; + self.latestValues[k] = values[k]; }); } @@ -165,8 +186,8 @@ define( // initial subscription chain; this allows `getTelemetryObjects()` // to return a non-Promise to simplify usage elsewhere. function cacheObjectReferences(objects) { - telemetryObjects = objects; - metadatas = objects.map(lookupMetadata); + self.telemetryObjects = objects; + self.metadatas = objects.map(lookupMetadata); // Fire callback, as this will be the first time that // telemetry objects are available, or these objects // will have changed. @@ -176,14 +197,6 @@ define( return objects; } - function unsubscribeAll() { - return unsubscribePromise.then(function (unsubscribes) { - return $q.all(unsubscribes.map(function (unsubscribe) { - return unsubscribe(); - })); - }); - } - function initialize() { // Get a reference to relevant objects (those with telemetry // capabilities) and subscribe to their telemetry updates. @@ -191,23 +204,23 @@ define( // will be unsubscribe functions. (This must be a promise // because delegation is supported, and retrieving delegate // telemetry-capable objects may be an asynchronous operation.) - telemetryObjectPromise = promiseRelevantObjects(domainObject); - unsubscribePromise = telemetryObjectPromise + self.telemetryObjectPromise = promiseRelevantObjects(domainObject); + self.unsubscribePromise = self.telemetryObjectPromise .then(cacheObjectReferences) .then(subscribeAll); } function idsMatch(ids) { - return ids.length === telemetryObjects.length && + return ids.length === self.telemetryObjects.length && ids.every(function (id, index) { - return telemetryObjects[index].getId() === id; + return self.telemetryObjects[index].getId() === id; }); } function modelChange(model) { if (!idsMatch((model || {}).composition || [])) { // Reinitialize if composition has changed - unsubscribeAll().then(initialize); + self.unsubscribeAll().then(initialize); } } @@ -219,122 +232,126 @@ define( } } - initialize(); - unlistenToMutation = addMutationListener(); + this.$q = $q; + this.latestValues = {}; + this.telemetryObjects = []; + this.metadatas = []; - return { - /** - * Terminate all underlying subscriptions associated - * with this object. - * @method - * @memberof TelemetrySubscription - * @memberof platform/telemetry.TelemetrySubscription# - */ - unsubscribe: function () { - if (unlistenToMutation) { - unlistenToMutation(); - } - return unsubscribeAll(); - }, - /** - * Get the most recent domain value that has been observed - * for the specified domain object. This will typically be - * a timestamp. - * - * The domain object passed here should be one that is - * subscribed-to here; that is, it should be one of the - * domain objects returned by `getTelemetryObjects()`. - * - * @param {DomainObject} domainObject the object of interest - * @returns the most recent domain value observed - * @method - * @memberof TelemetrySubscription - * @memberof platform/telemetry.TelemetrySubscription# - */ - getDomainValue: function (domainObject) { - var id = domainObject.getId(); - return (latestValues[id] || {}).domain; - }, - /** - * Get the most recent range value that has been observed - * for the specified domain object. This will typically - * be a numeric measurement. - * - * The domain object passed here should be one that is - * subscribed-to here; that is, it should be one of the - * domain objects returned by `getTelemetryObjects()`. - * - * @param {DomainObject} domainObject the object of interest - * @returns the most recent range value observed - * @method - * @memberof TelemetrySubscription - * @memberof platform/telemetry.TelemetrySubscription# - */ - getRangeValue: function (domainObject) { - var id = domainObject.getId(); - return (latestValues[id] || {}).range; - }, - /** - * Get the latest telemetry datum for this domain object. - * - * @param {DomainObject} domainObject the object of interest - * @returns {TelemetryDatum} the most recent datum - * @memberof platform/telemetry.TelemetrySubscription# - */ - getDatum: function (domainObject) { - var id = domainObject.getId(); - return (latestValues[id] || {}).datum; - }, - /** - * Get all telemetry-providing domain objects which are - * being observed as part of this subscription. - * - * Capability delegation will be taken into account (so, if - * a Telemetry Panel was passed in the constructor, this will - * return its contents.) Capability delegation is resolved - * asynchronously so the return value here may change over - * time; while this resolution is pending, this method will - * return an empty array. - * - * @returns {DomainObject[]} all subscribed-to domain objects - * @method - * @memberof TelemetrySubscription - * @memberof platform/telemetry.TelemetrySubscription# - */ - getTelemetryObjects: function () { - return telemetryObjects; - }, - /** - * Get all telemetry metadata associated with - * telemetry-providing domain objects managed by - * this controller. - * - * This will ordered in the - * same manner as `getTelemetryObjects()` or - * `getResponse()`; that is, the metadata at a - * given index will correspond to the telemetry-providing - * domain object at the same index. - * @returns {Array} an array of metadata objects - * @memberof platform/telemetry.TelemetrySubscription# - */ - getMetadata: function () { - return metadatas; - }, - /** - * Get a promise for all telemetry-providing objects - * associated with this subscription. - * @returns {Promise.} a promise for - * telemetry-providing objects - * @memberof platform/telemetry.TelemetrySubscription# - */ - promiseTelemetryObjects: function () { - // Unsubscribe promise is available after objects - // are loaded. - return telemetryObjectPromise; - } - }; + initialize(); + this.unlistenToMutation = addMutationListener(); } + TelemetrySubscription.prototype.unsubscribeAll = function () { + var $q = this.$q; + return this.unsubscribePromise.then(function (unsubscribes) { + return $q.all(unsubscribes.map(function (unsubscribe) { + return unsubscribe(); + })); + }); + }; + + /** + * Terminate all underlying subscriptions associated + * with this object. + */ + TelemetrySubscription.prototype.unsubscribe = function () { + if (this.unlistenToMutation) { + this.unlistenToMutation(); + } + return this.unsubscribeAll(); + }; + + /** + * Get the most recent domain value that has been observed + * for the specified domain object. This will typically be + * a timestamp. + * + * The domain object passed here should be one that is + * subscribed-to here; that is, it should be one of the + * domain objects returned by `getTelemetryObjects()`. + * + * @param {DomainObject} domainObject the object of interest + * @returns the most recent domain value observed + */ + TelemetrySubscription.prototype.getDomainValue = function (domainObject) { + var id = domainObject.getId(); + return (this.latestValues[id] || {}).domain; + }; + + /** + * Get the most recent range value that has been observed + * for the specified domain object. This will typically + * be a numeric measurement. + * + * The domain object passed here should be one that is + * subscribed-to here; that is, it should be one of the + * domain objects returned by `getTelemetryObjects()`. + * + * @param {DomainObject} domainObject the object of interest + * @returns the most recent range value observed + */ + TelemetrySubscription.prototype.getRangeValue = function (domainObject) { + var id = domainObject.getId(); + return (this.latestValues[id] || {}).range; + }; + + /** + * Get the latest telemetry datum for this domain object. + * + * @param {DomainObject} domainObject the object of interest + * @returns {TelemetryDatum} the most recent datum + */ + TelemetrySubscription.prototype.getDatum = function (domainObject) { + var id = domainObject.getId(); + return (this.latestValues[id] || {}).datum; + }; + + /** + * Get all telemetry-providing domain objects which are + * being observed as part of this subscription. + * + * Capability delegation will be taken into account (so, if + * a Telemetry Panel was passed in the constructor, this will + * return its contents.) Capability delegation is resolved + * asynchronously so the return value here may change over + * time; while this resolution is pending, this method will + * return an empty array. + * + * @returns {DomainObject[]} all subscribed-to domain objects + */ + TelemetrySubscription.prototype.getTelemetryObjects = function () { + return this.telemetryObjects; + }; + + /** + * Get all telemetry metadata associated with + * telemetry-providing domain objects managed by + * this controller. + * + * This will ordered in the + * same manner as `getTelemetryObjects()` or + * `getResponse()`; that is, the metadata at a + * given index will correspond to the telemetry-providing + * domain object at the same index. + * @returns {TelemetryMetadata[]} an array of metadata objects + */ + TelemetrySubscription.prototype.getMetadata = function () { + return this.metadatas; + }; + + /** + * Get a promise for all telemetry-providing objects + * associated with this subscription. + * @returns {Promise.} a promise for + * telemetry-providing objects + * @memberof platform/telemetry.TelemetrySubscription# + */ + TelemetrySubscription.prototype.promiseTelemetryObjects = function () { + // Unsubscribe promise is available after objects + // are loaded. + return this.telemetryObjectPromise; + }; + return TelemetrySubscription; } diff --git a/platform/telemetry/src/TelemetryTable.js b/platform/telemetry/src/TelemetryTable.js index c992a3ec18..2cfcf8823d 100644 --- a/platform/telemetry/src/TelemetryTable.js +++ b/platform/telemetry/src/TelemetryTable.js @@ -34,45 +34,26 @@ define( * values. * @memberof platform/telemetry * @constructor + * @implements {platform/telemetry.TelemetryPool} */ function TelemetryTable() { - var table; - - return { - /** - * Check if any value groups remain in this pool. - * @return {boolean} true if value groups remain - * @memberof platform/telemetry.TelemetryTable# - */ - isEmpty: function () { - return !table; - }, - /** - * Retrieve the next value group from this pool. - * This gives an object containing key-value pairs, - * where keys and values correspond to the arguments - * given to previous put functions. - * @return {object} key-value pairs - * @memberof platform/telemetry.TelemetryTable# - */ - poll: function () { - var t = table; - table = undefined; - return t; - }, - /** - * Put a key-value pair into the pool. - * @param {string} key the key to store the value under - * @param {*} value the value to store - * @memberof platform/telemetry.TelemetryTable# - */ - put: function (key, value) { - table = table || {}; - table[key] = value; - } - }; } + TelemetryTable.prototype.isEmpty = function () { + return !this.table; + }; + + TelemetryTable.prototype.poll = function () { + var t = this.table; + this.table = undefined; + return t; + }; + + TelemetryTable.prototype.put = function (key, value) { + this.table = this.table || {}; + this.table[key] = value; + }; + return TelemetryTable; } ); From 4481c44c4bda753a3fba029f3405fee8361c24c2 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 17 Aug 2015 11:20:23 -0700 Subject: [PATCH 68/84] [Code Style] Refactor search to use prototypes WTD-1482. --- .../src/ElasticsearchSearchProvider.js | 174 +++++++++--------- platform/search/src/GenericSearchProvider.js | 167 ++++++++--------- platform/search/src/SearchAggregator.js | 135 +++++++------- 3 files changed, 239 insertions(+), 237 deletions(-) diff --git a/platform/persistence/elastic/src/ElasticsearchSearchProvider.js b/platform/persistence/elastic/src/ElasticsearchSearchProvider.js index af13628af9..d7dea9b1f0 100644 --- a/platform/persistence/elastic/src/ElasticsearchSearchProvider.js +++ b/platform/persistence/elastic/src/ElasticsearchSearchProvider.js @@ -44,17 +44,52 @@ define( * @param $http Angular's $http service, for working with urls. * @param {ObjectService} objectService the service from which * domain objects can be gotten. - * @param ROOT the constant ELASTIC_ROOT which allows us to + * @param root the constant `ELASTIC_ROOT` which allows us to * interact with ElasticSearch. */ - function ElasticsearchSearchProvider($http, objectService, ROOT) { - - // Add the fuzziness operator to the search term + function ElasticsearchSearchProvider($http, objectService, root) { + this.$http = $http; + this.objectService = objectService; + this.root = root; + } + + /** + * Searches through the filetree for domain objects using a search + * term. This is done through querying elasticsearch. Returns a + * promise for a result object that has the format + * {hits: searchResult[], total: number, timedOut: boolean} + * where a searchResult has the format + * {id: string, object: domainObject, score: number} + * + * Notes: + * * The order of the results is from highest to lowest score, + * as elsaticsearch determines them to be. + * * Uses the fuzziness operator to get more results. + * * More about this search's behavior at + * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html + * + * @param searchTerm The text input that is the query. + * @param timestamp The time at which this function was called. + * This timestamp is used as a unique identifier for this + * query and the corresponding results. + * @param maxResults (optional) The maximum number of results + * that this function should return. + * @param timeout (optional) The time after which the search should + * stop calculations and return partial results. Elasticsearch + * does not guarentee that this timeout will be strictly followed. + */ + ElasticsearchSearchProvider.prototype.query = function query(searchTerm, timestamp, maxResults, timeout) { + var $http = this.$http, + objectService = this.objectService, + root = this.root, + esQuery; + + // Add the fuzziness operator to the search term function addFuzziness(searchTerm, editDistance) { if (!editDistance) { editDistance = ''; } - + return searchTerm.split(' ').map(function (s) { // Don't add fuzziness for quoted strings if (s.indexOf('"') !== -1) { @@ -64,11 +99,11 @@ define( } }).join(' '); } - + // Currently specific to elasticsearch function processSearchTerm(searchTerm) { var spaceIndex; - + // Cut out any extra spaces while (searchTerm.substr(0, 1) === ' ') { searchTerm = searchTerm.substring(1, searchTerm.length); @@ -79,18 +114,18 @@ define( spaceIndex = searchTerm.indexOf(' '); while (spaceIndex !== -1) { searchTerm = searchTerm.substring(0, spaceIndex) + - searchTerm.substring(spaceIndex + 1, searchTerm.length); + searchTerm.substring(spaceIndex + 1, searchTerm.length); spaceIndex = searchTerm.indexOf(' '); } - + // Add fuzziness for completeness searchTerm = addFuzziness(searchTerm); - + return searchTerm; } - - // Processes results from the format that elasticsearch returns to - // a list of searchResult objects, then returns a result object + + // Processes results from the format that elasticsearch returns to + // a list of searchResult objects, then returns a result object // (See documentation for query for object descriptions) function processResults(rawResults, timestamp) { var results = rawResults.data.hits.hits, @@ -99,25 +134,25 @@ define( scores = {}, searchResults = [], i; - + // Get the result objects' IDs for (i = 0; i < resultsLength; i += 1) { ids.push(results[i][ID]); } - + // Get the result objects' scores for (i = 0; i < resultsLength; i += 1) { scores[ids[i]] = results[i][SCORE]; } - + // Get the domain objects from their IDs return objectService.getObjects(ids).then(function (objects) { var j, id; - + for (j = 0; j < resultsLength; j += 1) { id = ids[j]; - + // Include items we can get models for if (objects[id].getModel) { // Format the results as searchResult objects @@ -128,7 +163,7 @@ define( }); } } - + return { hits: searchResults, total: rawResults.data.hits.total, @@ -136,76 +171,43 @@ define( }; }); } - - // For documentation, see query below. - function query(searchTerm, timestamp, maxResults, timeout) { - var esQuery; - - // Check to see if the user provided a maximum - // number of results to display - if (!maxResults) { - // Else, we provide a default value. - maxResults = DEFAULT_MAX_RESULTS; - } - - // If the user input is empty, we want to have no search results. - if (searchTerm !== '' && searchTerm !== undefined) { - // Process the search term - searchTerm = processSearchTerm(searchTerm); - // Create the query to elasticsearch - esQuery = ROOT + "/_search/?q=" + searchTerm + - "&size=" + maxResults; - if (timeout) { - esQuery += "&timeout=" + timeout; - } - // Get the data... - return $http({ - method: "GET", - url: esQuery - }).then(function (rawResults) { - // ...then process the data - return processResults(rawResults, timestamp); - }, function (err) { - // In case of error, return nothing. (To prevent - // infinite loading time.) - return {hits: [], total: 0}; - }); - } else { - return {hits: [], total: 0}; - } + // Check to see if the user provided a maximum + // number of results to display + if (!maxResults) { + // Else, we provide a default value. + maxResults = DEFAULT_MAX_RESULTS; } - - return { - /** - * Searches through the filetree for domain objects using a search - * term. This is done through querying elasticsearch. Returns a - * promise for a result object that has the format - * {hits: searchResult[], total: number, timedOut: boolean} - * where a searchResult has the format - * {id: string, object: domainObject, score: number} - * - * Notes: - * * The order of the results is from highest to lowest score, - * as elsaticsearch determines them to be. - * * Uses the fuzziness operator to get more results. - * * More about this search's behavior at - * https://www.elastic.co/guide/en/elasticsearch/reference/current/search-uri-request.html - * - * @param searchTerm The text input that is the query. - * @param timestamp The time at which this function was called. - * This timestamp is used as a unique identifier for this - * query and the corresponding results. - * @param maxResults (optional) The maximum number of results - * that this function should return. - * @param timeout (optional) The time after which the search should - * stop calculations and return partial results. Elasticsearch - * does not guarentee that this timeout will be strictly followed. - */ - query: query - }; - } + + // If the user input is empty, we want to have no search results. + if (searchTerm !== '' && searchTerm !== undefined) { + // Process the search term + searchTerm = processSearchTerm(searchTerm); + + // Create the query to elasticsearch + esQuery = root + "/_search/?q=" + searchTerm + + "&size=" + maxResults; + if (timeout) { + esQuery += "&timeout=" + timeout; + } + + // Get the data... + return this.$http({ + method: "GET", + url: esQuery + }).then(function (rawResults) { + // ...then process the data + return processResults(rawResults, timestamp); + }, function (err) { + // In case of error, return nothing. (To prevent + // infinite loading time.) + return {hits: [], total: 0}; + }); + } else { + return {hits: [], total: 0}; + } + }; return ElasticsearchSearchProvider; diff --git a/platform/search/src/GenericSearchProvider.js b/platform/search/src/GenericSearchProvider.js index dae2cab9a9..014d8d7fda 100644 --- a/platform/search/src/GenericSearchProvider.js +++ b/platform/search/src/GenericSearchProvider.js @@ -48,10 +48,14 @@ define( * domain objects' IDs. */ function GenericSearchProvider($q, $timeout, objectService, workerService, ROOTS) { - var worker = workerService.run('genericSearchWorker'), - indexed = {}, - pendingQueries = {}; - // pendingQueries is a dictionary with the key value pairs st + var indexed = {}, + pendingQueries = {}, + worker = workerService.run('genericSearchWorker'); + + this.worker = worker; + this.pendingQueries = pendingQueries; + this.$q = $q; + // pendingQueries is a dictionary with the key value pairs st // the key is the timestamp and the value is the promise // Tell the web worker to add a domain object's model to its list of items. @@ -71,20 +75,7 @@ define( } } - // Tell the worker to search for items it has that match this searchInput. - // Takes the searchInput, as well as a max number of results (will return - // less than that if there are fewer matches). - function workerSearch(searchInput, maxResults, timestamp, timeout) { - var message = { - request: 'search', - input: searchInput, - maxNumber: maxResults, - timestamp: timestamp, - timeout: timeout - }; - worker.postMessage(message); - } - + // Handles responses from the web worker. Namely, the results of // a search request. function handleResponse(event) { @@ -120,8 +111,6 @@ define( } } - worker.onmessage = handleResponse; - // Helper function for getItems(). Indexes the tree. function indexItems(nodes) { nodes.forEach(function (node) { @@ -193,75 +182,87 @@ define( indexItems(objects); }); } - - // For documentation, see query below - function query(input, timestamp, maxResults, timeout) { - var terms = [], - searchResults = [], - defer = $q.defer(); - - // If the input is nonempty, do a search - if (input !== '' && input !== undefined) { - - // Allow us to access this promise later to resolve it later - pendingQueries[timestamp] = defer; - - // Check to see if the user provided a maximum - // number of results to display - if (!maxResults) { - // Else, we provide a default value - maxResults = DEFAULT_MAX_RESULTS; - } - // Similarly, check if timeout was provided - if (!timeout) { - timeout = DEFAULT_TIMEOUT; - } - // Send the query to the worker - workerSearch(input, maxResults, timestamp, timeout); + worker.onmessage = handleResponse; - return defer.promise; - } else { - // Otherwise return an empty result - return {hits: [], total: 0}; - } - } - // Index the tree's contents once at the beginning getItems(); - - return { - /** - * Searches through the filetree for domain objects which match - * the search term. This function is to be used as a fallback - * in the case where other search services are not avaliable. - * Returns a promise for a result object that has the format - * {hits: searchResult[], total: number, timedOut: boolean} - * where a searchResult has the format - * {id: string, object: domainObject, score: number} - * - * Notes: - * * The order of the results is not guarenteed. - * * A domain object qualifies as a match for a search input if - * the object's name property contains any of the search terms - * (which are generated by splitting the input at spaces). - * * Scores are higher for matches that have more of the terms - * as substrings. - * - * @param input The text input that is the query. - * @param timestamp The time at which this function was called. - * This timestamp is used as a unique identifier for this - * query and the corresponding results. - * @param maxResults (optional) The maximum number of results - * that this function should return. - * @param timeout (optional) The time after which the search should - * stop calculations and return partial results. - */ - query: query - - }; } + /** + * Searches through the filetree for domain objects which match + * the search term. This function is to be used as a fallback + * in the case where other search services are not avaliable. + * Returns a promise for a result object that has the format + * {hits: searchResult[], total: number, timedOut: boolean} + * where a searchResult has the format + * {id: string, object: domainObject, score: number} + * + * Notes: + * * The order of the results is not guarenteed. + * * A domain object qualifies as a match for a search input if + * the object's name property contains any of the search terms + * (which are generated by splitting the input at spaces). + * * Scores are higher for matches that have more of the terms + * as substrings. + * + * @param input The text input that is the query. + * @param timestamp The time at which this function was called. + * This timestamp is used as a unique identifier for this + * query and the corresponding results. + * @param maxResults (optional) The maximum number of results + * that this function should return. + * @param timeout (optional) The time after which the search should + * stop calculations and return partial results. + */ + GenericSearchProvider.prototype.query = function query(input, timestamp, maxResults, timeout) { + var terms = [], + searchResults = [], + pendingQueries = this.pendingQueries, + worker = this.worker, + defer = this.$q.defer(); + + // Tell the worker to search for items it has that match this searchInput. + // Takes the searchInput, as well as a max number of results (will return + // less than that if there are fewer matches). + function workerSearch(searchInput, maxResults, timestamp, timeout) { + var message = { + request: 'search', + input: searchInput, + maxNumber: maxResults, + timestamp: timestamp, + timeout: timeout + }; + worker.postMessage(message); + } + + // If the input is nonempty, do a search + if (input !== '' && input !== undefined) { + + // Allow us to access this promise later to resolve it later + pendingQueries[timestamp] = defer; + + // Check to see if the user provided a maximum + // number of results to display + if (!maxResults) { + // Else, we provide a default value + maxResults = DEFAULT_MAX_RESULTS; + } + // Similarly, check if timeout was provided + if (!timeout) { + timeout = DEFAULT_TIMEOUT; + } + + // Send the query to the worker + workerSearch(input, maxResults, timestamp, timeout); + + return defer.promise; + } else { + // Otherwise return an empty result + return { hits: [], total: 0 }; + } + }; + return GenericSearchProvider; } diff --git a/platform/search/src/SearchAggregator.js b/platform/search/src/SearchAggregator.js index da267214bf..2324090595 100644 --- a/platform/search/src/SearchAggregator.js +++ b/platform/search/src/SearchAggregator.js @@ -42,33 +42,55 @@ define( * aggregated. */ function SearchAggregator($q, providers) { - - // Remove duplicate objects that have the same ID. Modifies the passed - // array, and returns the number that were removed. + this.$q = $q; + this.providers = providers; + } + + /** + * Sends a query to each of the providers. Returns a promise for + * a result object that has the format + * {hits: searchResult[], total: number, timedOut: boolean} + * where a searchResult has the format + * {id: string, object: domainObject, score: number} + * + * @param inputText The text input that is the query. + * @param maxResults (optional) The maximum number of results + * that this function should return. If not provided, a + * default of 100 will be used. + */ + SearchAggregator.prototype.query = function queryAll(inputText, maxResults) { + var $q = this.$q, + providers = this.providers, + i, + timestamp = Date.now(), + resultPromises = []; + + // Remove duplicate objects that have the same ID. Modifies the passed + // array, and returns the number that were removed. function filterDuplicates(results, total) { var ids = {}, numRemoved = 0, i; - + for (i = 0; i < results.length; i += 1) { if (ids[results[i].id]) { // If this result's ID is already there, remove the object results.splice(i, 1); numRemoved += 1; - - // Reduce loop index because we shortened the array + + // Reduce loop index because we shortened the array i -= 1; } else { - // Otherwise add the ID to the list of the ones we have seen + // Otherwise add the ID to the list of the ones we have seen ids[results[i].id] = true; } } - + return numRemoved; } - + // Order the objects from highest to lowest score in the array. - // Modifies the passed array, as well as returns the modified array. + // Modifies the passed array, as well as returns the modified array. function orderByScore(results) { results.sort(function (a, b) { if (a.score > b.score) { @@ -81,65 +103,42 @@ define( }); return results; } - - // For documentation, see query below. - function queryAll(inputText, maxResults) { - var i, - timestamp = Date.now(), - resultPromises = []; - - if (!maxResults) { - maxResults = DEFAULT_MAX_RESULTS; - } - - // Send the query to all the providers - for (i = 0; i < providers.length; i += 1) { - resultPromises.push( - providers[i].query(inputText, timestamp, maxResults, DEFUALT_TIMEOUT) - ); - } - - // Get promises for results arrays - return $q.all(resultPromises).then(function (resultObjects) { - var results = [], - totalSum = 0, - i; - - // Merge results - for (i = 0; i < resultObjects.length; i += 1) { - results = results.concat(resultObjects[i].hits); - totalSum += resultObjects[i].total; - } - // Order by score first, so that when removing repeats we keep the higher scored ones - orderByScore(results); - totalSum -= filterDuplicates(results, totalSum); - - return { - hits: results, - total: totalSum, - timedOut: resultObjects.some(function (obj) { - return obj.timedOut; - }) - }; - }); + + if (!maxResults) { + maxResults = DEFAULT_MAX_RESULTS; } - - return { - /** - * Sends a query to each of the providers. Returns a promise for - * a result object that has the format - * {hits: searchResult[], total: number, timedOut: boolean} - * where a searchResult has the format - * {id: string, object: domainObject, score: number} - * - * @param inputText The text input that is the query. - * @param maxResults (optional) The maximum number of results - * that this function should return. If not provided, a - * default of 100 will be used. - */ - query: queryAll - }; - } + + // Send the query to all the providers + for (i = 0; i < providers.length; i += 1) { + resultPromises.push( + providers[i].query(inputText, timestamp, maxResults, DEFUALT_TIMEOUT) + ); + } + + // Get promises for results arrays + return $q.all(resultPromises).then(function (resultObjects) { + var results = [], + totalSum = 0, + i; + + // Merge results + for (i = 0; i < resultObjects.length; i += 1) { + results = results.concat(resultObjects[i].hits); + totalSum += resultObjects[i].total; + } + // Order by score first, so that when removing repeats we keep the higher scored ones + orderByScore(results); + totalSum -= filterDuplicates(results, totalSum); + + return { + hits: results, + total: totalSum, + timedOut: resultObjects.some(function (obj) { + return obj.timedOut; + }) + }; + }); + }; return SearchAggregator; } From a4e2aba6dcbb7a1ac8014accbf80793d694f097a Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 17 Aug 2015 15:07:47 -0700 Subject: [PATCH 69/84] [Code Style] Add trailing newline WTD-1482. --- jsdoc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsdoc.json b/jsdoc.json index 4f4ee0afd4..f913b650d1 100644 --- a/jsdoc.json +++ b/jsdoc.json @@ -9,4 +9,4 @@ "plugins": [ "plugins/markdown" ] -} \ No newline at end of file +} From 841273edf642e0e36ae44b4294f38cdd1d4c1395 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 17 Aug 2015 15:22:26 -0700 Subject: [PATCH 70/84] [Code Style] Add CONTRIBUTING.md Add CONTRIBUTING.md to formalize changes to code style requirements for WTD-1482. --- CONTRIBUTING.md | 298 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 298 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..5f2fb18d84 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,298 @@ +# Contributing to Open MCT Web + +This document describes the process of contributing to Open MCT Web as well +as the standards that will be applied when evaluating contributions. + +Please be aware that additional agreements will be necessary before we can +accept changes from external contributors. + +## Summary + +The short version: + +1. Write your contribution. +2. Make sure your contribution meets code, test, and commit message + standards as described below. +3. Submit a pull request from a topic branch back to `master`. Include a check + list, as described below. (Optionally, assign this to a specific member + for review.) +4. Respond to any discussion. When the reviewer decides it's ready, they + will merge back `master` and fill out their own check list. + +## Contribution Process + +Open MCT Web uses git for software version control, and for branching and +merging. The central repository is at +https://github.com/nasa/openmctweb.git. + +### Roles + +References to roles are made throughout this document. These are not intended +to reflect titles or long-term job assignments; rather, these are used as +descriptors to refer to members of the development team performing tasks in +the check-in process. These roles are: + +* _Author_: The individual who has made changes to files in the software + repository, and wishes to check these in. +* _Reviewer_: The individual who reviews changes to files before they are + checked in. +* _Integrator_: The individual who performs the task of merging these files. + Usually the reviewer. + +### Branching + +Three basic types of branches may be included in the above repository: + +1. Master branch. +2. Topic branches. +3. Developer branches. + +Branches which do not fit into the above categories may be created and used +during the course of development for various reasons, such as large-scale +refactoring of code or implementation of complex features which may cause +instability. In these exceptional cases it is the responsibility of the +developer who initiates the task which motivated this branching to +communicate to the team the role of these branches and any associated +procedures for the duration of their use. + +#### Master Branch + +The role of the `master` branches is to represent the latest +"ready for test" version of the software. Source code on the master +branch has undergone peer review, and will undergo regular automated +testing with notification on failure. Master branches may be unstable +(particularly for recent features), but the intent is for the stability of +any features on master branches to be non-decreasing. It is the shared +responsibility of authors, reviewers, and integrators to ensure this. + +#### Topic Branches + +Topic branches are used by developers to perform and record work on issues. + +Topic branches need not necessarily be stable, even when pushed to the +central repository; in fact, the practice of making incremental commits +while working on an issue and pushing these to the central repository is +encouraged, to avoid lost work and to share work-in-progress. (Small commits +also help isolate changes, which can help in identifying which change +introduced a defect, particularly when that defect went unnoticed for some +time, e.g. using `git bisect`.) + +Topic branches should be named according to their corresponding issue +identifiers, all lower case, without hyphens. (e.g. branch mct9 would refer +to issue #9.) + +In some cases, work on an issue may warrant the use of multiple divergent +branches; for instance, when a developer wants to try more than one solution +and compare them, or when a "dead end" is reached and an initial approach to +resolving an issue needs to be abandoned. In these cases, a short suffix +should be added to the additional branches; this may be simply a single +character (e.g. wtd481b) or, where useful, a descriptive term for what +distinguishes the branches (e.g. wtd481verbose). It is the responsibility of +the author to communicate which branch is intended to be merged to both the +reviewer and the integrator. + +#### Developer Branches + +Developer branches are any branches used for purposes outside of the scope +of the above; e.g. to try things out, or maintain a "my latest stuff" +branch that is not delayed by the review and integration process. These +may be pushed to the central repository, and may follow any naming convention +desired so long as the owner of the branch is identifiable, and so long as +the name chosen could not be mistaken for a topic or master branch. + +### Merging + +When development is complete on an issue, the first step toward merging it +back into the master branch is to file a Pull Request. The contributions +should meet code, test, and commit message standards as described below, +and the pull request should include a completed author checklist, also +as described below. Pull requests may be assigned to specific team +members when appropriate (e.g. to draw to a specific person's attention.) + +Code review should take place using discussion features within the pull +request. When the reviewer is satisfied, they should add a comment to +the pull request containing the reviewer checklist (from below) and complete +the merge back to the master branch. + +## Standards + +Contributions to Open MCT Web are expected to meet the following standards. +In addition, reviewers should use general discretion before accepting +changes. + +### Code Standards + +JavaScript sources in Open MCT Web must satisfy JSLint under its default +settings. This is verified by the command line build. + +#### Code Guidelines + +JavaScript sources in Open MCT Web should: + +* Use four spaces for indentation. Tabs should not be used. +* Include JSDoc for any exposed API (e.g. public methods, constructors.) +* Include non-JSDoc comments as-needed for explaining private variables, + methods, or algorithms when they are non-obvious. +* Define one public class per script, expressed as a constructor function + returned from an AMD-style module. +* Follow “Java-like” naming conventions. These includes: + * Classes should use camel case, first letter capitalized + (e.g. SomeClassName.) + * Methods, variables, fields, and function names should use camel case, + first letter lower-case (e.g. someVariableName.) Constants + (variables or fields which are meant to be declared and initialized + statically, and never changed) should use only capital letters, with + underscores between words (e.g. SOME_CONSTANT.) + * File name should be the name of the exported class, plus a .js extension + (e.g. SomeClassName.js) +* Avoid anonymous functions, except when functions are short (a few lines) + and/or their inclusion makes sense within the flow of the code + (e.g. as arguments to a forEach call.) +* Avoid deep nesting (especially of functions), except where necessary + (e.g. due to closure scope.) +* End with a single new-line character. +* Expose public methods by declaring them on the class's prototype. +* Within a given function's scope, do not mix declarations and imperative + code, and present these in the following order: + * First, variable declarations and initialization. + * Second, function declarations. + * Third, imperative statements. + * Finally, the returned value. + +Deviations from Open MCT Web code style guidelines require two-party agreement, +typically from the author of the change and its reviewer. + +#### Code Example + +```js +/*global define*/ + +/** + * Bundles should declare themselves as namespaces in whichever source + * file is most like the "main point of entry" to the bundle. + * @namespace some/bundle + */ +define( + ['./OtherClass'], + function (OtherClass) { + "use strict"; + + /** + * A summary of how to use this class goes here. + * + * @constructor + * @memberof some/bundle + */ + function ExampleClass() { + } + + // Methods which are not intended for external use should + // not have JSDoc (or should be marked @private) + ExampleClass.prototype.privateMethod = function () { + }; + + /** + * A summary of this method goes here. + * @param {number} n a parameter + * @returns {number} a return value + */ + ExampleClass.prototype.publicMethod = function (n) { + return n * 2; + } + + return ExampleClass; + } +); +``` + +### Test Standards + +Automated testing shall occur whenever changes are merged into the main +development branch and must be confirmed alongside any pull request. + +Automated tests are typically unit tests which exercise individual software +components. Tests are subject to code review along with the actual +implementation, to ensure that tests are applicable and useful. + +Examples of useful tests: +* Tests which replicate bugs (or their root causes) to verify their + resolution. +* Tests which reflect details from software specifications. +* Tests which exercise edge or corner cases among inputs. +* Tests which verify expected interactions with other components in the + system. + +During automated testing, code coverage metrics will be reported. Line +coverage must remain at or above 80%. + +### Commit Message Standards + +Commit messages should: + +* Contain a one-line subject, followed by one line of white space, + followed by one or more descriptive paragraphs, each separated by one + line of white space. +* Contain a short (usually one word) reference to the feature or subsystem + the commit effects, in square brackets, at the start of the subject line + (e.g. `[Documentation] Draft of check-in process`) +* Contain a reference to a relevant issue number in the body of the commit. + * This is important for traceability; while branch names also provide this, + you cannot tell from looking at a commit what branch it was authored on. +* Describe the change that was made, and any useful rationale therefore. + * Comments in code should explain what things do, commit messages describe + how they came to be done that way. +* Provide sufficient information for a reviewer to understand the changes + made and their relationship to previous code. + +Commit messages should not: + +* Exceed 54 characters in length on the subject line. +* Exceed 72 characters in length in the body of the commit. + * Except where necessary to maintain the structure of machine-readable or + machine-generated text (e.g. error messages) + +See [Contributing to a Project](http://git-scm.com/book/ch5-2.html) from +Pro Git by Shawn Chacon and Ben Straub for a bit of the rationale behind +these standards. + +## Issue Reporting + +Issues are tracked at https://github.com/nasa/openmctweb/issues + +Issues should include: + +* A short description of the issue encountered. +* A longer-form description of the issue encountered. When possible, steps to + reproduce the issue. +* When possible, a description of the impact of the issue. What use case does + it impede? +* An assessment of the severity of the issue. + +Issue severity is categorized as follows (in ascending order): + +* _Trivial_: Minimal impact on the usefulness and functionality of the + software; a "nice-to-have." +* _(Unspecified)_: Major loss of functionality or impairment of use. +* _Critical_: Large-scale loss of functionality or impairment of use, + such that remaining utility becomes marginal. +* _Blocker_: Harmful or otherwise unacceptable behavior. Must fix. + +## Check Lists + +The following check lists should be completed and attached to pull requests +when they are filed (author checklist) and when they are merged (reviewer +checklist.) + +### Author Checklist + +1. Changes address original issue? +2. Unit tests included and/or updated with changes? +3. Command line build passes? +4. Expect to pass code review? + +### Reviewer Checklist + +1. Changes appear to address issue? +2. Appropriate unit tests included? +3. Code style and in-line documentation are appropriate? +4. Commit messages meet standards? From 86f0a9100f0de2b2735d66aa618c9a2b591c7933 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 17 Aug 2015 16:57:46 -0700 Subject: [PATCH 71/84] [Code Style] Fix merge error Fix merge error in ContextMenuAction which caused test failure. WTD-1482. --- platform/representation/src/actions/ContextMenuAction.js | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/representation/src/actions/ContextMenuAction.js b/platform/representation/src/actions/ContextMenuAction.js index ffe3a190df..60fdd9042f 100644 --- a/platform/representation/src/actions/ContextMenuAction.js +++ b/platform/representation/src/actions/ContextMenuAction.js @@ -114,6 +114,7 @@ define( // Dismiss the menu when body is clicked elsewhere // ('mousedown' because 'click' breaks left-click context menus) body.on('mousedown', dismiss); + menu.on('click', dismiss); // Don't launch browser's context menu actionContext.event.preventDefault(); From f6cf4c321553bde3ec684a852926a703d5d25517 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 17 Aug 2015 17:00:21 -0700 Subject: [PATCH 72/84] [Code Style] Fix error in persistence Fix typo in persistence provider for ElasticSearch related to refactoring to use prototypes, WTD-1482. --- platform/persistence/elastic/src/ElasticPersistenceProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/persistence/elastic/src/ElasticPersistenceProvider.js b/platform/persistence/elastic/src/ElasticPersistenceProvider.js index f5d083d7ea..d70d6aa34f 100644 --- a/platform/persistence/elastic/src/ElasticPersistenceProvider.js +++ b/platform/persistence/elastic/src/ElasticPersistenceProvider.js @@ -69,7 +69,7 @@ define( // Issue a request using $http; get back the plain JS object // from the expected JSON response ElasticPersistenceProvider.prototype.request = function (subpath, method, value, params) { - return this.http({ + return this.$http({ method: method, url: this.root + '/' + this.path + '/' + subpath, params: params, From eb776e69c055b3b0fb567a460685b86640f4615f Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Wed, 19 Aug 2015 11:13:24 -0700 Subject: [PATCH 73/84] [JSDoc] Document LocationCapability constructor --- .../entanglement/src/capabilities/LocationCapability.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js index c40a3810c1..7336d5f852 100644 --- a/platform/entanglement/src/capabilities/LocationCapability.js +++ b/platform/entanglement/src/capabilities/LocationCapability.js @@ -4,6 +4,14 @@ define( function () { "use strict"; + /** + * The location capability allows a domain object to know its current + * parent, and also know its original parent. When a domain object's + * current parent is its original parent, the object is considered an + * original, otherwise it's a link. + * + * @constructor + */ function LocationCapability(domainObject) { this.domainObject = domainObject; return this; From 9cf30f42134d483f491b6f1dd190c86a573352fd Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Wed, 19 Aug 2015 11:15:09 -0700 Subject: [PATCH 74/84] [Location] setPrimaryLocation takes location. Rename "persistLocation" to be more clearly named, and make it take an argument to allow for greater control outside the capability. --- .../src/capabilities/LocationCapability.js | 12 ++++++++---- .../entanglement/src/services/MoveService.js | 18 +++++++++++++----- .../capabilities/LocationCapabilitySpec.js | 3 ++- .../test/services/MoveServiceSpec.js | 9 +++++---- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js index 7336d5f852..c55d15787d 100644 --- a/platform/entanglement/src/capabilities/LocationCapability.js +++ b/platform/entanglement/src/capabilities/LocationCapability.js @@ -18,15 +18,19 @@ define( } /** - * Persist the current location of the current domain object as it's - * primary location. Returns a promise. + * Set the primary location (the parent id) of the current domain + * object. + * + * @param {String} location the primary location to persist. + * @returns {Promise} a promise that is resolved when the operation + * completes. */ - LocationCapability.prototype.persistLocation = function () { + LocationCapability.prototype.setPrimaryLocation = function (location) { var capability = this; return this.domainObject.useCapability( 'mutation', function (model) { - model.location = capability.getLocation(); + model.location = location; } ).then(function () { return capability.domainObject diff --git a/platform/entanglement/src/services/MoveService.js b/platform/entanglement/src/services/MoveService.js index 7ee5876e4a..c5406f93c6 100644 --- a/platform/entanglement/src/services/MoveService.js +++ b/platform/entanglement/src/services/MoveService.js @@ -70,13 +70,21 @@ define( return linkService .perform(object, parentObject) .then(function (objectInNewContext) { - if (!object.hasCapability('location')) { + var newLocationCapability = objectInNewContext + .getCapability('location'), + oldLocationCapability = object + .getCapability('location'); + if (!newLocationCapability || + oldLocationCapability) { + return; } - if (object.getCapability('location').isOriginal()) { - return objectInNewContext - .getCapability('location') - .persistLocation(); + + + if (oldLocationCapability.isOriginal()) { + return newLocationCapability.setPrimaryLocation( + newLocationCapability.getLocation() + ); } }) .then(function () { diff --git a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js index 83f166cbec..8c96500a8a 100644 --- a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js +++ b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js @@ -70,7 +70,8 @@ define( }); it("can persist location", function () { - var persistResult = locationCapability.persistLocation(), + var persistResult = locationCapability + .setPrimaryLocation('root'), whenComplete = jasmine.createSpy('whenComplete'); persistResult.then(whenComplete); diff --git a/platform/entanglement/test/services/MoveServiceSpec.js b/platform/entanglement/test/services/MoveServiceSpec.js index b48dd4e66e..fed7878ac7 100644 --- a/platform/entanglement/test/services/MoveServiceSpec.js +++ b/platform/entanglement/test/services/MoveServiceSpec.js @@ -162,12 +162,13 @@ define( 'locationCapability', [ 'isOriginal', - 'persistLocation' + 'setPrimaryLocation' ] ); locationPromise = new ControlledPromise(); - locationCapability.persistLocation.andReturn(locationPromise); + locationCapability.setPrimaryLocation + .andReturn(locationPromise); object = domainObjectFactory({ name: 'object', @@ -199,7 +200,7 @@ define( }); it("updates location", function () { - expect(locationCapability.persistLocation) + expect(locationCapability.setPrimaryLocation) .toHaveBeenCalled(); }); @@ -223,7 +224,7 @@ define( }); it("does not update location", function () { - expect(locationCapability.persistLocation) + expect(locationCapability.setPrimaryLocation) .not .toHaveBeenCalled(); }); From 94854e5965f425a5aa8059d478f4074b38e5bb6c Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Wed, 19 Aug 2015 11:28:58 -0700 Subject: [PATCH 75/84] [Location] can retrieve contextual location Clarify naming of method for retrieving contextual location of a domain object. Default behavior for objects that do not have a context is to return undefined. Note that default behavior is not specified and could change if needed. --- .../src/capabilities/LocationCapability.js | 17 +++++++++-------- .../entanglement/src/services/MoveService.js | 3 ++- .../test/capabilities/LocationCapabilitySpec.js | 4 ++-- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js index c55d15787d..1bc2f8b931 100644 --- a/platform/entanglement/src/capabilities/LocationCapability.js +++ b/platform/entanglement/src/capabilities/LocationCapability.js @@ -40,16 +40,17 @@ define( }; /** - * Return the current location of the current domain object. Only + * Returns the contextual location of the current domain object. Only * valid for domain objects that have a context capability. + * + * @returns {String} the contextual location of the object; the id of + * its parent. */ - LocationCapability.prototype.getLocation = function () { - var context = this.domainObject.getCapability("context"), - pathObjects, - pathIds; + LocationCapability.prototype.getContextualLocation = function () { + var context = this.domainObject.getCapability("context"); if (!context) { - return ''; + return; } return context.getParent().getId(); @@ -65,7 +66,7 @@ define( } var model = this.domainObject.getModel(); - return model.location !== this.getLocation(); + return model.location !== this.getContextualLocation(); }; /** @@ -78,7 +79,7 @@ define( } var model = this.domainObject.getModel(); - return model.location === this.getLocation(); + return model.location === this.getContextualLocation(); }; function createLocationCapability(domainObject) { diff --git a/platform/entanglement/src/services/MoveService.js b/platform/entanglement/src/services/MoveService.js index c5406f93c6..9dc8b80169 100644 --- a/platform/entanglement/src/services/MoveService.js +++ b/platform/entanglement/src/services/MoveService.js @@ -83,7 +83,8 @@ define( if (oldLocationCapability.isOriginal()) { return newLocationCapability.setPrimaryLocation( - newLocationCapability.getLocation() + newLocationCapability + .getContextualLocation() ); } }) diff --git a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js index 8c96500a8a..9cbfcc1bea 100644 --- a/platform/entanglement/test/capabilities/LocationCapabilitySpec.js +++ b/platform/entanglement/test/capabilities/LocationCapabilitySpec.js @@ -52,8 +52,8 @@ define( locationCapability = new LocationCapability(domainObject); }); - it("returns location", function () { - expect(locationCapability.getLocation()) + it("returns contextual location", function () { + expect(locationCapability.getContextualLocation()) .toBe('root'); }); From 5c74365f4bb0958007e6c726d852c6ac747f144f Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Wed, 19 Aug 2015 11:49:03 -0700 Subject: [PATCH 76/84] [Root] Root model provider sets location Root model provider sets the location of roods so that the location capability does not need special handling for this. --- platform/core/src/models/RootModelProvider.js | 10 +++++++--- platform/core/test/models/RootModelProviderSpec.js | 8 +++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/platform/core/src/models/RootModelProvider.js b/platform/core/src/models/RootModelProvider.js index 804537ccf2..d3f64c5e36 100644 --- a/platform/core/src/models/RootModelProvider.js +++ b/platform/core/src/models/RootModelProvider.js @@ -42,8 +42,12 @@ define( * @constructor */ function RootModelProvider(roots, $q, $log) { - // Pull out identifiers to used as ROOT's - var ids = roots.map(function (root) { return root.id; }), + // Pull out identifiers to used as ROOT's, while setting locations. + var ids = roots.map(function (root) { + if (!root.model) root.model = {}; + root.model.location = 'ROOT'; + return root.id; + }), baseProvider = new StaticModelProvider(roots, $q, $log); function addRoot(models) { @@ -77,4 +81,4 @@ define( return RootModelProvider; } -); \ No newline at end of file +); diff --git a/platform/core/test/models/RootModelProviderSpec.js b/platform/core/test/models/RootModelProviderSpec.js index 897b38656e..3de505a6cd 100644 --- a/platform/core/test/models/RootModelProviderSpec.js +++ b/platform/core/test/models/RootModelProviderSpec.js @@ -79,6 +79,12 @@ define( expect(captured.b.someProperty).toEqual("Some Value B"); }); + it("provides models with a location", function () { + provider.getModels(["a", "b"]).then(capture); + expect(captured.a.location).toBe('ROOT'); + expect(captured.b.location).toBe('ROOT'); + }); + it("does not provide models which are not in extension declarations", function () { provider.getModels(["c"]).then(capture); @@ -96,4 +102,4 @@ define( }); } -); \ No newline at end of file +); From 26892e7104063a8428e0dfa98fe8cfa551eec295 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Wed, 19 Aug 2015 11:49:45 -0700 Subject: [PATCH 77/84] [Location] isLink/isOriginal are antonyms Simplify implementation of isLink/isOriginal for better maintainability. --- .../src/capabilities/LocationCapability.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/platform/entanglement/src/capabilities/LocationCapability.js b/platform/entanglement/src/capabilities/LocationCapability.js index 1bc2f8b931..17d678f57e 100644 --- a/platform/entanglement/src/capabilities/LocationCapability.js +++ b/platform/entanglement/src/capabilities/LocationCapability.js @@ -59,11 +59,10 @@ define( /** * Returns true if the domainObject is a link, false if it's an * original. + * + * @returns {Boolean} */ LocationCapability.prototype.isLink = function () { - if (this.domainObject.getId() === "mine") { - return false; - } var model = this.domainObject.getModel(); return model.location !== this.getContextualLocation(); @@ -72,14 +71,11 @@ define( /** * Returns true if the domainObject is an original, false if it's a * link. + * + * @returns {Boolean} */ LocationCapability.prototype.isOriginal = function () { - if (this.domainObject.getId() === "mine") { - return true; - } - var model = this.domainObject.getModel(); - - return model.location === this.getContextualLocation(); + return !this.isLink(); }; function createLocationCapability(domainObject) { From a94763041efc0a464b142ab9b38b8bfc8c510fa8 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Wed, 19 Aug 2015 13:16:36 -0700 Subject: [PATCH 78/84] [Move] correct logic and specification --- platform/entanglement/src/services/MoveService.js | 2 +- platform/entanglement/test/services/MoveServiceSpec.js | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/platform/entanglement/src/services/MoveService.js b/platform/entanglement/src/services/MoveService.js index 9dc8b80169..e6e1238979 100644 --- a/platform/entanglement/src/services/MoveService.js +++ b/platform/entanglement/src/services/MoveService.js @@ -75,7 +75,7 @@ define( oldLocationCapability = object .getCapability('location'); if (!newLocationCapability || - oldLocationCapability) { + !oldLocationCapability) { return; } diff --git a/platform/entanglement/test/services/MoveServiceSpec.js b/platform/entanglement/test/services/MoveServiceSpec.js index fed7878ac7..02494a0afb 100644 --- a/platform/entanglement/test/services/MoveServiceSpec.js +++ b/platform/entanglement/test/services/MoveServiceSpec.js @@ -162,7 +162,8 @@ define( 'locationCapability', [ 'isOriginal', - 'setPrimaryLocation' + 'setPrimaryLocation', + 'getContextualLocation' ] ); @@ -195,13 +196,15 @@ define( describe("when moving an original", function () { beforeEach(function () { + locationCapability.getContextualLocation + .andReturn('new-location'); locationCapability.isOriginal.andReturn(true); linkService.perform.mostRecentCall.promise.resolve(); }); it("updates location", function () { expect(locationCapability.setPrimaryLocation) - .toHaveBeenCalled(); + .toHaveBeenCalledWith('new-location'); }); describe("after location update", function () { From c118234bbf1bb009f4ae4fbb476a994b9ed0b4f3 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Wed, 19 Aug 2015 13:55:02 -0700 Subject: [PATCH 79/84] [Style] Brace after if criteria --- platform/core/src/models/RootModelProvider.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/core/src/models/RootModelProvider.js b/platform/core/src/models/RootModelProvider.js index d3f64c5e36..f60d359af8 100644 --- a/platform/core/src/models/RootModelProvider.js +++ b/platform/core/src/models/RootModelProvider.js @@ -44,7 +44,7 @@ define( function RootModelProvider(roots, $q, $log) { // Pull out identifiers to used as ROOT's, while setting locations. var ids = roots.map(function (root) { - if (!root.model) root.model = {}; + if (!root.model) { root.model = {}; } root.model.location = 'ROOT'; return root.id; }), From 08d68f99a58e8dda1f30eb37996e9b91585d9cc0 Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Wed, 19 Aug 2015 16:09:55 -0700 Subject: [PATCH 80/84] [Frontend] Fix word wrapping issues in hover bubble #75 CSS modified to utilize word-break property; --- .../general/res/css/theme-espresso.css | 75 ++++++++++--------- .../general/res/sass/helpers/_bubbles.scss | 40 ++++++---- 2 files changed, 67 insertions(+), 48 deletions(-) diff --git a/platform/commonUI/general/res/css/theme-espresso.css b/platform/commonUI/general/res/css/theme-espresso.css index 5c6b8af3bd..5d41793946 100644 --- a/platform/commonUI/general/res/css/theme-espresso.css +++ b/platform/commonUI/general/res/css/theme-espresso.css @@ -92,7 +92,7 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 5, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, @@ -113,38 +113,38 @@ time, mark, audio, video { font-size: 100%; vertical-align: baseline; } -/* line 22, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html { line-height: 1; } -/* line 24, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ ol, ul { list-style: none; } -/* line 26, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ table { border-collapse: collapse; border-spacing: 0; } -/* line 28, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } -/* line 30, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q, blockquote { quotes: none; } - /* line 103, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ + /* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q:before, q:after, blockquote:before, blockquote:after { content: ""; content: none; } -/* line 32, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ a img { border: none; } -/* line 116, ../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } @@ -4429,26 +4429,26 @@ input[type="text"] { .l-infobubble-wrapper .l-infobubble table tr td { padding: 2px 0; vertical-align: top; } - /* line 57, ../sass/helpers/_bubbles.scss */ + /* line 53, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper .l-infobubble table tr td.label { padding-right: 10px; white-space: nowrap; } - /* line 61, ../sass/helpers/_bubbles.scss */ + /* line 57, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper .l-infobubble table tr td.value { - white-space: nowrap; } - /* line 65, ../sass/helpers/_bubbles.scss */ + word-break: break-all; } + /* line 61, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper .l-infobubble table tr td.align-wrap { white-space: normal; } - /* line 71, ../sass/helpers/_bubbles.scss */ + /* line 67, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper .l-infobubble .title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-bottom: 5px; } - /* line 78, ../sass/helpers/_bubbles.scss */ + /* line 74, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper.arw-left { margin-left: 20px; } - /* line 80, ../sass/helpers/_bubbles.scss */ + /* line 76, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper.arw-left .l-infobubble::before { right: 100%; width: 0; @@ -4456,10 +4456,10 @@ input[type="text"] { border-top: 6.66667px solid transparent; border-bottom: 6.66667px solid transparent; border-right: 10px solid #ddd; } - /* line 86, ../sass/helpers/_bubbles.scss */ + /* line 82, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper.arw-right { margin-right: 20px; } - /* line 88, ../sass/helpers/_bubbles.scss */ + /* line 84, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper.arw-right .l-infobubble::before { left: 100%; width: 0; @@ -4467,16 +4467,16 @@ input[type="text"] { border-top: 6.66667px solid transparent; border-bottom: 6.66667px solid transparent; border-left: 10px solid #ddd; } - /* line 95, ../sass/helpers/_bubbles.scss */ + /* line 91, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper.arw-top .l-infobubble::before { top: 20px; } - /* line 101, ../sass/helpers/_bubbles.scss */ + /* line 97, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper.arw-btm .l-infobubble::before { bottom: 20px; } - /* line 106, ../sass/helpers/_bubbles.scss */ + /* line 102, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper.arw-down { margin-bottom: 10px; } - /* line 108, ../sass/helpers/_bubbles.scss */ + /* line 104, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper.arw-down .l-infobubble::before { left: 50%; top: 100%; @@ -4484,21 +4484,21 @@ input[type="text"] { border-left: 5px solid transparent; border-right: 5px solid transparent; border-top: 7.5px solid #ddd; } - /* line 117, ../sass/helpers/_bubbles.scss */ + /* line 113, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper .arw { z-index: 2; } - /* line 120, ../sass/helpers/_bubbles.scss */ + /* line 116, ../sass/helpers/_bubbles.scss */ .l-infobubble-wrapper.arw-up .arw.arw-down, .l-infobubble-wrapper.arw-down .arw.arw-up { display: none; } -/* line 127, ../sass/helpers/_bubbles.scss */ +/* line 125, ../sass/helpers/_bubbles.scss */ .l-thumbsbubble-wrapper .arw-up { width: 0; height: 0; border-left: 6.66667px solid transparent; border-right: 6.66667px solid transparent; border-bottom: 10px solid #4d4d4d; } -/* line 130, ../sass/helpers/_bubbles.scss */ +/* line 128, ../sass/helpers/_bubbles.scss */ .l-thumbsbubble-wrapper .arw-down { width: 0; height: 0; @@ -4506,7 +4506,7 @@ input[type="text"] { border-right: 6.66667px solid transparent; border-top: 10px solid #4d4d4d; } -/* line 134, ../sass/helpers/_bubbles.scss */ +/* line 133, ../sass/helpers/_bubbles.scss */ .s-infobubble { -moz-border-radius: 2px; -webkit-border-radius: 2px; @@ -4517,22 +4517,29 @@ input[type="text"] { background: #ddd; color: #666; font-size: 0.8rem; } - /* line 141, ../sass/helpers/_bubbles.scss */ + /* line 140, ../sass/helpers/_bubbles.scss */ .s-infobubble .title { color: #333333; font-weight: bold; } /* line 146, ../sass/helpers/_bubbles.scss */ - .s-infobubble tr td { - border-top: 1px solid #c4c4c4; + .s-infobubble table tr td { + border: none; + border-top: 1px solid #c4c4c4 !important; font-size: 0.9em; } - /* line 150, ../sass/helpers/_bubbles.scss */ - .s-infobubble tr:first-child td { + /* line 152, ../sass/helpers/_bubbles.scss */ + .s-infobubble table tr:first-child td { + border-top: none !important; } + /* line 157, ../sass/helpers/_bubbles.scss */ + .s-infobubble:first-child td { border-top: none; } - /* line 154, ../sass/helpers/_bubbles.scss */ + /* line 161, ../sass/helpers/_bubbles.scss */ + .s-infobubble .label { + color: gray; } + /* line 165, ../sass/helpers/_bubbles.scss */ .s-infobubble .value { color: #333333; } -/* line 159, ../sass/helpers/_bubbles.scss */ +/* line 171, ../sass/helpers/_bubbles.scss */ .s-thumbsbubble { background: #4d4d4d; color: #b3b3b3; } diff --git a/platform/commonUI/general/res/sass/helpers/_bubbles.scss b/platform/commonUI/general/res/sass/helpers/_bubbles.scss index 5b174ba6da..10deec9645 100644 --- a/platform/commonUI/general/res/sass/helpers/_bubbles.scss +++ b/platform/commonUI/general/res/sass/helpers/_bubbles.scss @@ -48,19 +48,15 @@ width: 100%; tr { td { - //max-width: 150px; padding: 2px 0; vertical-align: top; - //white-space: nowrap; - //overflow: hidden; - //text-overflow: ellipsis; &.label { padding-right: $interiorMargin * 2; white-space: nowrap; } &.value { - white-space: nowrap; - //width: 90%; + //word-wrap: break-word; // Doesn't work in ? + word-break: break-all; } &.align-wrap { white-space: normal; @@ -118,7 +114,9 @@ z-index: 2; } &.arw-up .arw.arw-down, - &.arw-down .arw.arw-up { display: none; } + &.arw-down .arw.arw-up { + display: none; + } } //************************************************* LOOK AND FEEL @@ -131,6 +129,7 @@ @include triangle('down', $bubbleArwSize, 1.5, $colorThumbsBubbleBg); } } + .s-infobubble { $emFg: darken($colorInfoBubbleFg, 20%); @include border-radius($basicCr); @@ -142,18 +141,31 @@ color: $emFg; font-weight: bold; } - tr { - td { - border-top: 1px solid darken($colorInfoBubbleBg, 10%); - font-size: 0.9em; - } - &:first-child td { - border-top: none; + table { + tr { + td { + border: none; + border-top: 1px solid darken($colorInfoBubbleBg, 10%) !important; + font-size: 0.9em; + } + + &:first-child td { + border-top: none !important; + } } } + &:first-child td { + border-top: none; + } + + .label { + color: lighten($emFg, 30%); + } + .value { color: $emFg; } + } .s-thumbsbubble { From 249a9b2eb26bcba8ca02258ee2d4bf6a9e397108 Mon Sep 17 00:00:00 2001 From: Charles Hacskaylo Date: Wed, 19 Aug 2015 17:52:02 -0700 Subject: [PATCH 81/84] [Frontend] Better sorting indicators added to styles JPL #48 Simplified styles to indicate sort by asc and desc in table th elements; (cherry picked from commit 15a2416) --- .../general/res/css/theme-espresso.css | 217 +++++++++--------- .../general/res/sass/lists/_tabular.scss | 19 +- 2 files changed, 121 insertions(+), 115 deletions(-) diff --git a/platform/commonUI/general/res/css/theme-espresso.css b/platform/commonUI/general/res/css/theme-espresso.css index b6c9a43edc..6089031faf 100644 --- a/platform/commonUI/general/res/css/theme-espresso.css +++ b/platform/commonUI/general/res/css/theme-espresso.css @@ -92,7 +92,7 @@ * this source code distribution or the Licensing information page available * at runtime from the About dialog for additional information. *****************************************************************************/ -/* line 5, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 5, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, @@ -113,38 +113,38 @@ time, mark, audio, video { font-size: 100%; vertical-align: baseline; } -/* line 22, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 22, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ html { line-height: 1; } -/* line 24, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 24, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ ol, ul { list-style: none; } -/* line 26, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 26, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ table { border-collapse: collapse; border-spacing: 0; } -/* line 28, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 28, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ caption, th, td { text-align: left; font-weight: normal; vertical-align: middle; } -/* line 30, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 30, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q, blockquote { quotes: none; } - /* line 103, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ + /* line 103, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ q:before, q:after, blockquote:before, blockquote:after { content: ""; content: none; } -/* line 32, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 32, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ a img { border: none; } -/* line 116, ../../../../../../../.rvm/gems/ruby-2.2.1/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ +/* line 116, ../../../../../../../../../../Library/Ruby/Gems/2.0.0/gems/compass-core-1.0.3/stylesheets/compass/reset/_utilities.scss */ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { display: block; } @@ -172,11 +172,11 @@ article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, /*********************************************** FORM ELEMENTS */ /* @mixin invokeMenu($baseColor: $colorBodyFg) { - $c: $baseColor; - color: $c; - &:hover { - color: lighten($c, $ltGamma); - } + $c: $baseColor; + color: $c; + &:hover { + color: lighten($c, $ltGamma); + } } */ /***************************************************************************** @@ -1049,27 +1049,27 @@ mct-container { /*.s-limit-upr, .s-limit-lwr { - $a: 0.5; - $l: 30%; - white-space: nowrap; - &:before { - display: inline-block; - font-family: symbolsfont; - font-size: 0.85em; - font-style: normal !important; - margin-right: $interiorMarginSm; - vertical-align: middle; - } + $a: 0.5; + $l: 30%; + white-space: nowrap; + &:before { + display: inline-block; + font-family: symbolsfont; + font-size: 0.85em; + font-style: normal !important; + margin-right: $interiorMarginSm; + vertical-align: middle; + } } .s-limit-upr { - &.s-limit-yellow { @include limit($colorLimitYellow, "\0000ed"); } - &.s-limit-red { @include limit($colorLimitRed, "\0000eb"); } + &.s-limit-yellow { @include limit($colorLimitYellow, "\0000ed"); } + &.s-limit-red { @include limit($colorLimitRed, "\0000eb"); } } .s-limit-lwr { - &.s-limit-yellow { @include limit($colorLimitYellow, "\0000ec"); } - &.s-limit-red { @include limit($colorLimitRed, "\0000ee"); } + &.s-limit-yellow { @include limit($colorLimitYellow, "\0000ec"); } + &.s-limit-red { @include limit($colorLimitRed, "\0000ee"); } }*/ /* line 35, ../sass/_limits.scss */ [class*="s-limit"] { @@ -1237,29 +1237,32 @@ table { table .tr .th:first-child { border-left: none; } /* line 85, ../sass/lists/_tabular.scss */ - .tabular tr th.sort .icon-sorting:before, .tabular tr .th.sort .icon-sorting:before, .tabular .tr th.sort .icon-sorting:before, .tabular .tr .th.sort .icon-sorting:before, - table tr th.sort .icon-sorting:before, - table tr .th.sort .icon-sorting:before, - table .tr th.sort .icon-sorting:before, - table .tr .th.sort .icon-sorting:before { - display: inline-block; + .tabular tr th.sort.sort:after, .tabular tr .th.sort.sort:after, .tabular .tr th.sort.sort:after, .tabular .tr .th.sort.sort:after, + table tr th.sort.sort:after, + table tr .th.sort.sort:after, + table .tr th.sort.sort:after, + table .tr .th.sort.sort:after { + color: #49dedb; font-family: symbolsfont; - margin-left: 5px; } - /* line 90, ../sass/lists/_tabular.scss */ - .tabular tr th.sort.asc .icon-sorting:before, .tabular tr .th.sort.asc .icon-sorting:before, .tabular .tr th.sort.asc .icon-sorting:before, .tabular .tr .th.sort.asc .icon-sorting:before, - table tr th.sort.asc .icon-sorting:before, - table tr .th.sort.asc .icon-sorting:before, - table .tr th.sort.asc .icon-sorting:before, - table .tr .th.sort.asc .icon-sorting:before { - content: '0'; } + font-size: 8px; + content: "\ed"; + display: inline-block; + margin-left: 3px; } /* line 93, ../sass/lists/_tabular.scss */ - .tabular tr th.sort.desc .icon-sorting:before, .tabular tr .th.sort.desc .icon-sorting:before, .tabular .tr th.sort.desc .icon-sorting:before, .tabular .tr .th.sort.desc .icon-sorting:before, - table tr th.sort.desc .icon-sorting:before, - table tr .th.sort.desc .icon-sorting:before, - table .tr th.sort.desc .icon-sorting:before, - table .tr .th.sort.desc .icon-sorting:before { - content: '1'; } - /* line 98, ../sass/lists/_tabular.scss */ + .tabular tr th.sort.sort.desc:after, .tabular tr .th.sort.sort.desc:after, .tabular .tr th.sort.sort.desc:after, .tabular .tr .th.sort.sort.desc:after, + table tr th.sort.sort.desc:after, + table tr .th.sort.sort.desc:after, + table .tr th.sort.sort.desc:after, + table .tr .th.sort.sort.desc:after { + content: "\ec"; } + /* line 97, ../sass/lists/_tabular.scss */ + .tabular tr th.sortable, .tabular tr .th.sortable, .tabular .tr th.sortable, .tabular .tr .th.sortable, + table tr th.sortable, + table tr .th.sortable, + table .tr th.sortable, + table .tr .th.sortable { + cursor: pointer; } + /* line 101, ../sass/lists/_tabular.scss */ .tabular tr td, .tabular tr .td, .tabular .tr td, .tabular .tr .td, table tr td, table tr .td, @@ -1271,21 +1274,21 @@ table { padding: 3px 5px; word-wrap: break-word; vertical-align: top; } - /* line 105, ../sass/lists/_tabular.scss */ + /* line 108, ../sass/lists/_tabular.scss */ .tabular tr td.numeric, .tabular tr .td.numeric, .tabular .tr td.numeric, .tabular .tr .td.numeric, table tr td.numeric, table tr .td.numeric, table .tr td.numeric, table .tr .td.numeric { text-align: right; } - /* line 108, ../sass/lists/_tabular.scss */ + /* line 111, ../sass/lists/_tabular.scss */ .tabular tr td.s-cell-type-value, .tabular tr .td.s-cell-type-value, .tabular .tr td.s-cell-type-value, .tabular .tr .td.s-cell-type-value, table tr td.s-cell-type-value, table tr .td.s-cell-type-value, table .tr td.s-cell-type-value, table .tr .td.s-cell-type-value { text-align: right; } - /* line 110, ../sass/lists/_tabular.scss */ + /* line 113, ../sass/lists/_tabular.scss */ .tabular tr td.s-cell-type-value .l-cell-contents, .tabular tr .td.s-cell-type-value .l-cell-contents, .tabular .tr td.s-cell-type-value .l-cell-contents, .tabular .tr .td.s-cell-type-value .l-cell-contents, table tr td.s-cell-type-value .l-cell-contents, table tr .td.s-cell-type-value .l-cell-contents, @@ -1296,23 +1299,23 @@ table { border-radius: 2px; padding-left: 5px; padding-right: 5px; } - /* line 126, ../sass/lists/_tabular.scss */ + /* line 129, ../sass/lists/_tabular.scss */ .tabular.filterable tbody, .tabular.filterable .tbody, table.filterable tbody, table.filterable .tbody { top: 44px; } - /* line 129, ../sass/lists/_tabular.scss */ + /* line 132, ../sass/lists/_tabular.scss */ .tabular.filterable input[type="text"], table.filterable input[type="text"] { -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; width: 100%; } - /* line 135, ../sass/lists/_tabular.scss */ + /* line 138, ../sass/lists/_tabular.scss */ .tabular.fixed-header, table.fixed-header { height: 100%; } - /* line 137, ../sass/lists/_tabular.scss */ + /* line 140, ../sass/lists/_tabular.scss */ .tabular.fixed-header thead, .tabular.fixed-header .thead, .tabular.fixed-header tbody tr, .tabular.fixed-header .tbody .tr, table.fixed-header thead, @@ -1321,12 +1324,12 @@ table { table.fixed-header .tbody .tr { display: table; table-layout: fixed; } - /* line 142, ../sass/lists/_tabular.scss */ + /* line 145, ../sass/lists/_tabular.scss */ .tabular.fixed-header thead, .tabular.fixed-header .thead, table.fixed-header thead, table.fixed-header .thead { width: calc(100% - 10px); } - /* line 144, ../sass/lists/_tabular.scss */ + /* line 147, ../sass/lists/_tabular.scss */ .tabular.fixed-header thead:before, .tabular.fixed-header .thead:before, table.fixed-header thead:before, table.fixed-header .thead:before { @@ -1337,7 +1340,7 @@ table { width: 100%; height: 22px; background: rgba(255, 255, 255, 0.15); } - /* line 154, ../sass/lists/_tabular.scss */ + /* line 157, ../sass/lists/_tabular.scss */ .tabular.fixed-header tbody, .tabular.fixed-header .tbody, table.fixed-header tbody, table.fixed-header .tbody { @@ -1352,7 +1355,7 @@ table { top: 22px; display: block; overflow-y: scroll; } - /* line 162, ../sass/lists/_tabular.scss */ + /* line 165, ../sass/lists/_tabular.scss */ .tabular.t-event-messages td, .tabular.t-event-messages .td, table.t-event-messages td, table.t-event-messages .td { @@ -1772,11 +1775,11 @@ table { /* line 132, ../sass/controls/_buttons.scss */ .icon-btn.pause-play, .s-icon-btn.pause-play { - /* &.paused { - .icon { - @include pulse(500ms); - } - }*/ } + /* &.paused { + .icon { + @include pulse(500ms); + } + }*/ } /* line 138, ../sass/controls/_buttons.scss */ .icon-btn.pause-play .icon:before, .s-icon-btn.pause-play .icon:before { @@ -1899,32 +1902,32 @@ a.l-btn span { * at runtime from the About dialog for additional information. *****************************************************************************/ /*.control { - // UNUSED? - &.view-control { - .icon { - display: inline-block; - margin: -1px 5px 1px 2px; - vertical-align: middle; - &.triangle-down { - margin: 2px 2px -2px 0px; - } - } + // UNUSED? + &.view-control { + .icon { + display: inline-block; + margin: -1px 5px 1px 2px; + vertical-align: middle; + &.triangle-down { + margin: 2px 2px -2px 0px; + } + } - .label { - display: inline-block; - font-size: 11px; - vertical-align: middle; - } + .label { + display: inline-block; + font-size: 11px; + vertical-align: middle; + } - .toggle { - @include border-radius(3px); - display: inline-block; - padding: 1px 6px 4px 4px; - &:hover { - background: rgba(white, 0.1); - } - } - } + .toggle { + @include border-radius(3px); + display: inline-block; + padding: 1px 6px 4px 4px; + &:hover { + background: rgba(white, 0.1); + } + } + } }*/ /* line 51, ../sass/controls/_controls.scss */ .accordion { @@ -2161,23 +2164,23 @@ label.checkbox.custom { border-top: 1px solid #575757; color: #999; display: inline-block; - /* height: $h; - line-height: $h; - &.dropdown { - padding-left: $p; - padding-right: $p; - }*/ - /* &.context-available { - // An element like the invoke-menu triangle; - // Indicates that this element has a dropdown menu available; - // Currently unused - $c: $colorKey; - color: $c; - padding: 0 5px; - &:hover { - color: lighten($c, 10%); - } - }*/ } + /* height: $h; + line-height: $h; + &.dropdown { + padding-left: $p; + padding-right: $p; + }*/ + /* &.context-available { + // An element like the invoke-menu triangle; + // Indicates that this element has a dropdown menu available; + // Currently unused + $c: $colorKey; + color: $c; + padding: 0 5px; + &:hover { + color: lighten($c, 10%); + } + }*/ } /* line 162, ../sass/_mixins.scss */ .btn-menu:not(.disabled):hover { background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgeDE9IjAuNSIgeTE9IjAuMCIgeDI9IjAuNSIgeTI9IjEuMCI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzYzNjM2MyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzU3NTc1NyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); diff --git a/platform/commonUI/general/res/sass/lists/_tabular.scss b/platform/commonUI/general/res/sass/lists/_tabular.scss index 629cac9d1a..0621cad46b 100644 --- a/platform/commonUI/general/res/sass/lists/_tabular.scss +++ b/platform/commonUI/general/res/sass/lists/_tabular.scss @@ -82,18 +82,21 @@ table { border-left: none; } &.sort { - .icon-sorting:before { - display: inline-block; + &.sort:after { + color: $colorIconLink; font-family: symbolsfont; - margin-left: 5px; + font-size: 8px; + content: "\ed"; + display: inline-block; + margin-left: $interiorMarginSm; } - &.asc .icon-sorting:before { - content: '0'; - } - &.desc .icon-sorting:before { - content: '1'; + &.sort.desc:after { + content: "\ec"; } } + &.sortable { + cursor: pointer; + } } td, .td { border-bottom: 1px solid $tabularColorBorder; From 3a050cc5b8e4565725d6fd2bc190dca11781b022 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Mon, 24 Aug 2015 09:03:31 -0700 Subject: [PATCH 82/84] [Style] space after operator --- platform/features/plot/src/elements/PlotPosition.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/features/plot/src/elements/PlotPosition.js b/platform/features/plot/src/elements/PlotPosition.js index 15444e68d5..d8369faf33 100644 --- a/platform/features/plot/src/elements/PlotPosition.js +++ b/platform/features/plot/src/elements/PlotPosition.js @@ -78,7 +78,7 @@ define( * Get the range value corresponding to this pixel position. * @returns {number} the range value */ - PlotPosition.prototype.getRange =function () { + PlotPosition.prototype.getRange = function () { return this.position[1]; }; From 1e332da11b85540fd2f62fe0ef836eea9c0e7372 Mon Sep 17 00:00:00 2001 From: Pete Richards Date: Mon, 24 Aug 2015 09:04:03 -0700 Subject: [PATCH 83/84] [Docs] ElasticSearch is not Couch --- platform/persistence/elastic/bundle.json | 4 ++-- platform/persistence/elastic/src/ElasticIndicator.js | 12 ++++++------ .../elastic/src/ElasticPersistenceProvider.js | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/platform/persistence/elastic/bundle.json b/platform/persistence/elastic/bundle.json index e7dfa1ab9d..8b9ba16fd4 100644 --- a/platform/persistence/elastic/bundle.json +++ b/platform/persistence/elastic/bundle.json @@ -1,6 +1,6 @@ { - "name": "Couch Persistence", - "description": "Adapter to read and write objects using a CouchDB instance.", + "name": "ElasticSearch Persistence", + "description": "Adapter to read and write objects using an ElasticSearch instance.", "extensions": { "components": [ { diff --git a/platform/persistence/elastic/src/ElasticIndicator.js b/platform/persistence/elastic/src/ElasticIndicator.js index 9eb87e70eb..78a29605c1 100644 --- a/platform/persistence/elastic/src/ElasticIndicator.js +++ b/platform/persistence/elastic/src/ElasticIndicator.js @@ -46,15 +46,15 @@ define( }; /** - * Indicator for the current CouchDB connection. Polls CouchDB - * at a regular interval (defined by bundle constants) to ensure - * that the database is available. + * Indicator for the current ElasticSearch connection. Polls + * ElasticSearch at a regular interval (defined by bundle constants) + * to ensure that the database is available. * @constructor * @memberof platform/persistence/elastic * @implements {Indicator} * @param $http Angular's $http service * @param $interval Angular's $interval service - * @param {string} path the URL to poll to check for couch availability + * @param {string} path the URL to poll for elasticsearch availability * @param {number} interval the interval, in milliseconds, to poll at */ function ElasticIndicator($http, $interval, path, interval) { @@ -63,7 +63,7 @@ define( this.state = PENDING; - // Callback if the HTTP request to Couch fails + // Callback if the HTTP request to ElasticSearch fails function handleError() { self.state = DISCONNECTED; } @@ -73,7 +73,7 @@ define( self.state = CONNECTED; } - // Try to connect to CouchDB, and update the indicator. + // Try to connect to ElasticSearch, and update the indicator. function updateIndicator() { $http.get(path).then(handleResponse, handleError); } diff --git a/platform/persistence/elastic/src/ElasticPersistenceProvider.js b/platform/persistence/elastic/src/ElasticPersistenceProvider.js index d70d6aa34f..c7d21ae81d 100644 --- a/platform/persistence/elastic/src/ElasticPersistenceProvider.js +++ b/platform/persistence/elastic/src/ElasticPersistenceProvider.js @@ -109,7 +109,7 @@ define( return this.$q.reject(error); }; - // Get a domain object model out of CouchDB's response + // Get a domain object model out of ElasticSearch's response function getModel(response) { if (response && response[SRC]) { this.revs[response[ID]] = response[REV]; From 6aaa887e658a91166270de0ab066168d2575f6ed Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Mon, 22 Jun 2015 13:34:02 -0700 Subject: [PATCH 84/84] [Imagery] Start off with empty timestamp Show nothing in the timestamp area when there is no data yet available for image telemetry, WTD-1170. --- .../imagery/src/controllers/ImageryController.js | 14 ++++++++++---- .../test/controllers/ImageryControllerSpec.js | 13 +++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/platform/features/imagery/src/controllers/ImageryController.js b/platform/features/imagery/src/controllers/ImageryController.js index 8bd8c36034..5439fc414c 100644 --- a/platform/features/imagery/src/controllers/ImageryController.js +++ b/platform/features/imagery/src/controllers/ImageryController.js @@ -59,6 +59,7 @@ define( releaseSubscription(); self.date = ""; self.time = ""; + self.zone = ""; self.imageUrl = ""; self.handle = domainObject && telemetryHandler.handle( domainObject, @@ -78,11 +79,16 @@ define( ImageryController.prototype.updateValues = function () { var imageObject = this.handle && this.handle.getTelemetryObjects()[0], + timestamp, m; if (imageObject && !this.isPaused) { - m = moment.utc(this.handle.getDomainValue(imageObject)); - this.date = m.format(DATE_FORMAT); - this.time = m.format(TIME_FORMAT); + timestamp = this.handle.getDomainValue(imageObject); + m = timestamp !== undefined ? + moment.utc(timestamp) : + undefined; + this.date = m ? m.format(DATE_FORMAT) : ""; + this.time = m ? m.format(TIME_FORMAT) : ""; + this.zone = m ? "UTC" : ""; this.imageUrl = this.handle.getRangeValue(imageObject); } }; @@ -112,7 +118,7 @@ define( * @returns {string} the time */ ImageryController.prototype.getZone = function () { - return "UTC"; + return this.zone; }; /** diff --git a/platform/features/imagery/test/controllers/ImageryControllerSpec.js b/platform/features/imagery/test/controllers/ImageryControllerSpec.js index 9bb00d6b20..6ae82b3d86 100644 --- a/platform/features/imagery/test/controllers/ImageryControllerSpec.js +++ b/platform/features/imagery/test/controllers/ImageryControllerSpec.js @@ -146,6 +146,19 @@ define( expect(controller.getImageUrl()).toEqual(testUrl); }); + it("initially shows an empty string for date/time", function () { + // Call the subscription listener while domain/range + // values are still undefined + mockHandle.getDomainValue.andReturn(undefined); + mockHandle.getRangeValue.andReturn(undefined); + mockTelemetryHandler.handle.mostRecentCall.args[1](); + + // Should have empty strings for date/time/zone + expect(controller.getTime()).toEqual(""); + expect(controller.getDate()).toEqual(""); + expect(controller.getZone()).toEqual(""); + expect(controller.getImageUrl()).toBeUndefined(); + }); }); } );