From bfdbc71e40f6df78369f22279ba2fa2bc302f6c0 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 28 Jul 2016 15:34:03 -0700 Subject: [PATCH 01/16] [API] Define a properties region --- src/MCT.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MCT.js b/src/MCT.js index 93d8cdb1b1..46aee49a3b 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -138,6 +138,7 @@ define([ MCT.prototype.regions = { main: "MAIN", + properties: "PROPERTIES", toolbar: "TOOLBAR" }; From 1d31fe8d0279c48d5048ad35f3015adc5c0663de Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 28 Jul 2016 15:48:28 -0700 Subject: [PATCH 02/16] [API] Override dialogService in actions An ugly hack to allow dialogs to be shown for Save As and Edit Properties, without requiring form generation. This will permit views to be shown instead in certain cases, https://github.com/nasa/openmct/pull/999#issuecomment-236045158 --- src/adapter/actions/ActionDialogDecorator.js | 20 ++++++++++++++++++++ src/adapter/bundle.js | 7 +++++++ 2 files changed, 27 insertions(+) create mode 100644 src/adapter/actions/ActionDialogDecorator.js diff --git a/src/adapter/actions/ActionDialogDecorator.js b/src/adapter/actions/ActionDialogDecorator.js new file mode 100644 index 0000000000..a586109996 --- /dev/null +++ b/src/adapter/actions/ActionDialogDecorator.js @@ -0,0 +1,20 @@ +define([], function () { + function ActionDialogDecorator(actionService) { + this.actionService = actionService; + } + + ActionDialogDecorator.prototype.getActions = function (context) { + return this.actionService.getActions(context).map(function (action) { + if (action.dialogService) { + action.dialogService = Object.create(action.dialogService); + action.dialogService.getUserInput = function (form, value) { + window.alert("Get user input!"); + return Promise.resolve(value); + } + } + return action; + }); + }; + + return ActionDialogDecorator; +}); diff --git a/src/adapter/bundle.js b/src/adapter/bundle.js index 30c18594ec..265b83a57a 100644 --- a/src/adapter/bundle.js +++ b/src/adapter/bundle.js @@ -1,10 +1,12 @@ define([ 'legacyRegistry', + './actions/ActionDialogDecorator', './directives/MCTView', './services/Instantiate', './capabilities/APICapabilityDecorator' ], function ( legacyRegistry, + ActionDialogDecorator, MCTView, Instantiate, APICapabilityDecorator @@ -41,6 +43,11 @@ define([ depends: [ "$injector" ] + }, + { + type: "decorator", + provides: "actionService", + implementation: ActionDialogDecorator } ] } From 7bf265b47877ff11dadbf34a47a29465547a240e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 28 Jul 2016 15:52:52 -0700 Subject: [PATCH 03/16] [API] Move mct service up --- src/MCT.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/MCT.js b/src/MCT.js index 46aee49a3b..e7ba634f12 100644 --- a/src/MCT.js +++ b/src/MCT.js @@ -21,7 +21,16 @@ define([ ) { function MCT() { EventEmitter.call(this); - this.legacyBundle = { extensions: {} }; + this.legacyBundle = { extensions: { + services: [ + { + key: "mct", + implementation: function () { + return this; + }.bind(this) + } + ] + } }; this.selection = new Selection(); this.on('navigation', this.selection.clear.bind(this.selection)); @@ -86,13 +95,6 @@ define([ region: region, key: viewKey }); - - this.legacyExtension('services', { - key: 'PublicAPI', - implementation: function () { - return this; - }.bind(this) - }); }; MCT.prototype.type = function (key, type) { From 87682607a589d4c63c2b1998bcdf6bdc0520f15f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 28 Jul 2016 15:53:07 -0700 Subject: [PATCH 04/16] [API] Rename dependency in adapter layer --- src/adapter/bundle.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adapter/bundle.js b/src/adapter/bundle.js index 265b83a57a..3616078331 100644 --- a/src/adapter/bundle.js +++ b/src/adapter/bundle.js @@ -19,7 +19,7 @@ define([ implementation: MCTView, depends: [ "newViews[]", - "PublicAPI" + "mct" ] } ], From 62d90a8114d1c53be129aed4e3b881dde32420fd Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 28 Jul 2016 15:57:15 -0700 Subject: [PATCH 05/16] [API] Show dialog via mct --- src/adapter/actions/ActionDialogDecorator.js | 11 +++++++++-- src/adapter/bundle.js | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/adapter/actions/ActionDialogDecorator.js b/src/adapter/actions/ActionDialogDecorator.js index a586109996..44d0fa9a24 100644 --- a/src/adapter/actions/ActionDialogDecorator.js +++ b/src/adapter/actions/ActionDialogDecorator.js @@ -1,14 +1,21 @@ define([], function () { - function ActionDialogDecorator(actionService) { + function ActionDialogDecorator(mct, actionService) { this.actionService = actionService; + this.mct = mct; } ActionDialogDecorator.prototype.getActions = function (context) { + var mct = this.mct; return this.actionService.getActions(context).map(function (action) { if (action.dialogService) { action.dialogService = Object.create(action.dialogService); action.dialogService.getUserInput = function (form, value) { - window.alert("Get user input!"); + mct.dialog({ + show: function (container) { + container.textContent = JSON.stringify(value); + }, + destroy: function () {} + }, form.title); return Promise.resolve(value); } } diff --git a/src/adapter/bundle.js b/src/adapter/bundle.js index 3616078331..9ffd4829fa 100644 --- a/src/adapter/bundle.js +++ b/src/adapter/bundle.js @@ -47,7 +47,8 @@ define([ { type: "decorator", provides: "actionService", - implementation: ActionDialogDecorator + implementation: ActionDialogDecorator, + depends: [ "mct" ] } ] } From 14f30b2489f9ac878b771257a6f86f00dcacd06f Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 28 Jul 2016 16:05:02 -0700 Subject: [PATCH 06/16] [API] Restrict dialog overrides ...to those domain objects which have some view for the properties region registered. --- src/adapter/actions/ActionDialogDecorator.js | 28 +++++++++++++------- src/adapter/bundle.js | 2 +- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/adapter/actions/ActionDialogDecorator.js b/src/adapter/actions/ActionDialogDecorator.js index 44d0fa9a24..d270ee9729 100644 --- a/src/adapter/actions/ActionDialogDecorator.js +++ b/src/adapter/actions/ActionDialogDecorator.js @@ -1,22 +1,30 @@ define([], function () { - function ActionDialogDecorator(mct, actionService) { + function ActionDialogDecorator(mct, newViews, actionService) { this.actionService = actionService; this.mct = mct; + this.propertiesViews = newViews.filter(function (propertiesView) { + return propertiesView.region === mct.regions.properties; + }); } ActionDialogDecorator.prototype.getActions = function (context) { var mct = this.mct; + var definitions = this.propertiesViews; + return this.actionService.getActions(context).map(function (action) { if (action.dialogService) { - action.dialogService = Object.create(action.dialogService); - action.dialogService.getUserInput = function (form, value) { - mct.dialog({ - show: function (container) { - container.textContent = JSON.stringify(value); - }, - destroy: function () {} - }, form.title); - return Promise.resolve(value); + var domainObject = context.domainObject; + + definitions = definitions.filter(function (definition) { + return definition.canView(domainObject); + }); + + if (definitions.length > 0) { + action.dialogService = Object.create(action.dialogService); + action.dialogService.getUserInput = function (form, value) { + mct.dialog(definitions[0].view(domainObject), form.title); + return Promise.resolve(value); + }; } } return action; diff --git a/src/adapter/bundle.js b/src/adapter/bundle.js index 9ffd4829fa..e0ab60c4e9 100644 --- a/src/adapter/bundle.js +++ b/src/adapter/bundle.js @@ -48,7 +48,7 @@ define([ type: "decorator", provides: "actionService", implementation: ActionDialogDecorator, - depends: [ "mct" ] + depends: [ "mct", "newViews[]" ] } ] } From fe2ce91d50c06e5f618a7180787a19ca96bd5cfd Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 28 Jul 2016 16:16:22 -0700 Subject: [PATCH 07/16] [API] Show a custom view in dialog --- src/adapter/actions/ActionDialogDecorator.js | 22 ++++++++++++++------ tutorials/todo/todo.js | 7 +++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/adapter/actions/ActionDialogDecorator.js b/src/adapter/actions/ActionDialogDecorator.js index d270ee9729..99b2679f7b 100644 --- a/src/adapter/actions/ActionDialogDecorator.js +++ b/src/adapter/actions/ActionDialogDecorator.js @@ -1,19 +1,26 @@ -define([], function () { +define([ + '../../api/objects/object-utils' +], function (objectUtils) { function ActionDialogDecorator(mct, newViews, actionService) { this.actionService = actionService; this.mct = mct; - this.propertiesViews = newViews.filter(function (propertiesView) { - return propertiesView.region === mct.regions.properties; + this.definitions = newViews.filter(function (newView) { + return newView.region === mct.regions.properties; + }).map(function (newView) { + return newView.factory; }); } ActionDialogDecorator.prototype.getActions = function (context) { var mct = this.mct; - var definitions = this.propertiesViews; + var definitions = this.definitions; return this.actionService.getActions(context).map(function (action) { if (action.dialogService) { - var domainObject = context.domainObject; + var domainObject = objectUtils.toNewFormat( + context.domainObject.getModel(), + objectUtils.parseKeyString(context.domainObject.getId()) + ); definitions = definitions.filter(function (definition) { return definition.canView(domainObject); @@ -22,7 +29,10 @@ define([], function () { if (definitions.length > 0) { action.dialogService = Object.create(action.dialogService); action.dialogService.getUserInput = function (form, value) { - mct.dialog(definitions[0].view(domainObject), form.title); + mct.dialog( + definitions[0].view(context.domainObject), + form.title + ); return Promise.resolve(value); }; } diff --git a/tutorials/todo/todo.js b/tutorials/todo/todo.js index 75a4bc5d46..8d9495459d 100644 --- a/tutorials/todo/todo.js +++ b/tutorials/todo/todo.js @@ -221,6 +221,13 @@ define([ canView: todoType.check.bind(todoType) }); + mct.view(mct.regions.properties, { + view: function (domainObject) { + return new TodoToolbarView(domainObject); + }, + canView: todoType.check.bind(todoType) + }); + return mct; }; }); From 0656a298daff730690476728b0af1c7e5703408e Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 4 Aug 2016 14:00:39 -0700 Subject: [PATCH 08/16] [API] Remove test usage of properties region --- tutorials/todo/todo.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tutorials/todo/todo.js b/tutorials/todo/todo.js index 8d9495459d..75a4bc5d46 100644 --- a/tutorials/todo/todo.js +++ b/tutorials/todo/todo.js @@ -221,13 +221,6 @@ define([ canView: todoType.check.bind(todoType) }); - mct.view(mct.regions.properties, { - view: function (domainObject) { - return new TodoToolbarView(domainObject); - }, - canView: todoType.check.bind(todoType) - }); - return mct; }; }); From 8295a0bed13c85a260c85e03f7a5b6b8c946f5db Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 11 Aug 2016 15:29:46 -0700 Subject: [PATCH 09/16] [API] Update todo tutorial ...to expect new domain object API (instead of explicitly wrapping it.) --- tutorials/todo/todo.js | 89 ++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 47 deletions(-) diff --git a/tutorials/todo/todo.js b/tutorials/todo/todo.js index 75a4bc5d46..b285b922a7 100644 --- a/tutorials/todo/todo.js +++ b/tutorials/todo/todo.js @@ -48,22 +48,20 @@ define([ var self = this; this.destroy(); - mct.Objects.get(utils.parseKeyString(self.domainObject.getId())).then(function (object) { - self.$els = $(todoTemplate); - self.$buttons = { - all: self.$els.find('.example-todo-button-all'), - incomplete: self.$els.find('.example-todo-button-incomplete'), - complete: self.$els.find('.example-todo-button-complete') - }; + self.$els = $(todoTemplate); + self.$buttons = { + all: self.$els.find('.example-todo-button-all'), + incomplete: self.$els.find('.example-todo-button-incomplete'), + complete: self.$els.find('.example-todo-button-complete') + }; - $(container).empty().append(self.$els); + $(container).empty().append(self.$els); - self.initialize(); - self.objectChanged(object); + self.initialize(); + self.objectChanged(this.domainObject); - mct.selection.on('change', self.render); - }); + mct.selection.on('change', self.render); }; TodoView.prototype.destroy = function () { @@ -148,47 +146,44 @@ define([ var self = this; this.destroy(); - mct.Objects.get(utils.parseKeyString(this.domainObject.getId())).then(function (wrappedObject){ + self.mutableObject = mct.Objects.getMutable(this.domainObject); - self.mutableObject = mct.Objects.getMutable(wrappedObject); + var $els = $(toolbarTemplate); + var $add = $els.find('a.example-add'); + var $remove = $els.find('a.example-remove'); - var $els = $(toolbarTemplate); - var $add = $els.find('a.example-add'); - var $remove = $els.find('a.example-remove'); + $(container).append($els); - $(container).append($els); + $add.on('click', function () { + var $dialog = $(dialogTemplate), + view = { + show: function (container) { + $(container).append($dialog); + }, + destroy: function () {} + }; - $add.on('click', function () { - var $dialog = $(dialogTemplate), - view = { - show: function (container) { - $(container).append($dialog); - }, - destroy: function () {} - }; - - mct.dialog(view, "Add a Task").then(function () { - var description = $dialog.find('input').val(); - var tasks = self.mutableObject.get('tasks'); - tasks.push({ description: description }); - self.mutableObject.set('tasks', tasks); - }); + mct.dialog(view, "Add a Task").then(function () { + var description = $dialog.find('input').val(); + var tasks = self.mutableObject.get('tasks'); + tasks.push({ description: description }); + self.mutableObject.set('tasks', tasks); }); - $remove.on('click', function () { - var index = mct.selection.selected()[0].index; - if (index !== undefined) { - var tasks = self.mutableObject.get('tasks').filter(function (t, i) { - return i !== index; - }); - self.mutableObject.set("tasks", tasks); - self.mutableObject.set("selected", undefined); - mct.selection.clear(); - } - }); - self.$remove = $remove; - self.handleSelectionChange(); - mct.selection.on('change', self.handleSelectionChange); }); + $remove.on('click', function () { + var index = mct.selection.selected()[0].index; + if (index !== undefined) { + var tasks = self.mutableObject.get('tasks').filter(function (t, i) { + return i !== index; + }); + self.mutableObject.set("tasks", tasks); + self.mutableObject.set("selected", undefined); + mct.selection.clear(); + } + }); + self.$remove = $remove; + self.handleSelectionChange(); + mct.selection.on('change', self.handleSelectionChange); }; TodoToolbarView.prototype.handleSelectionChange = function () { From 8861644f2de09a0de26ce1fbf834f81b48237c61 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 11 Aug 2016 16:02:04 -0700 Subject: [PATCH 10/16] [API] Adjust Dialog API ...to allow OK button to be enabled/disabled. --- src/ui/Dialog.js | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/src/ui/Dialog.js b/src/ui/Dialog.js index 9f462fb444..c8371cb67e 100644 --- a/src/ui/Dialog.js +++ b/src/ui/Dialog.js @@ -2,9 +2,15 @@ define(['text!./dialog.html', 'zepto'], function (dialogTemplate, $) { function Dialog(view, title) { this.view = view; this.title = title; + this.showing = false; + this.enabledState = true; } Dialog.prototype.show = function () { + if (this.showing) { + throw new Error("Dialog already showing."); + } + var $body = $('body'); var $dialog = $(dialogTemplate); var $contents = $dialog.find('.contents .editor'); @@ -13,31 +19,45 @@ define(['text!./dialog.html', 'zepto'], function (dialogTemplate, $) { var $ok = $dialog.find('.ok'); var $cancel = $dialog.find('.cancel'); - var view = this.view; - - function dismiss() { - $dialog.remove(); - view.destroy(); - } - if (this.title) { $dialog.find('.title').text(this.title); } $body.append($dialog); this.view.show($contents[0]); + this.$dialog = $dialog; + this.$ok = $ok; + this.showing = true; + + [$ok, $cancel, $close].forEach(function ($button) { + $button.on('click', this.hide.bind(this)); + }.bind(this)); return new Promise(function (resolve, reject) { $ok.on('click', resolve); - $ok.on('click', dismiss); - $cancel.on('click', reject); - $cancel.on('click', dismiss); - $close.on('click', reject); - $close.on('click', dismiss); }); }; + Dialog.prototype.hide = function () { + if (!this.showing) { + return; + } + this.$dialog.remove(); + this.view.destroy(); + this.showing = false; + }; + + Dialog.prototype.enabled = function (state) { + if (state !== undefined) { + this.enabledState = state; + if (this.showing) { + this.$ok.toggleClass('disabled', !state); + } + } + return this.enabledState; + }; + return Dialog; }); From 93872ce0744f46acc37e95cfa6cef95ca19e36a4 Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Thu, 11 Aug 2016 16:04:26 -0700 Subject: [PATCH 11/16] [API] Expose Dialog as constructor ...and use it that way from todo plugin --- index.html | 4 +++- src/MCT.js | 6 ------ src/api/api.js | 9 ++++++--- src/{ => api}/ui/Dialog.js | 0 src/{ => api}/ui/dialog.html | 0 tutorials/todo/todo.js | 2 +- 6 files changed, 10 insertions(+), 11 deletions(-) rename src/{ => api}/ui/Dialog.js (100%) rename src/{ => api}/ui/dialog.html (100%) diff --git a/index.html b/index.html index 454d712480..7cf44f9b16 100644 --- a/index.html +++ b/index.html @@ -31,10 +31,12 @@