mirror of
https://github.com/nasa/openmct.git
synced 2024-12-20 05:37:53 +00:00
Merge pull request #1028 from nasa/api-view
[API Prototype] Support imperative view registration
This commit is contained in:
commit
14a56ea17e
2
main.js
2
main.js
@ -65,6 +65,8 @@ define([
|
|||||||
'legacyRegistry',
|
'legacyRegistry',
|
||||||
'./src/MCT',
|
'./src/MCT',
|
||||||
|
|
||||||
|
'./src/adapter/bundle',
|
||||||
|
|
||||||
'./platform/framework/bundle',
|
'./platform/framework/bundle',
|
||||||
'./platform/core/bundle',
|
'./platform/core/bundle',
|
||||||
'./platform/representation/bundle',
|
'./platform/representation/bundle',
|
||||||
|
57
src/MCT.js
57
src/MCT.js
@ -1,11 +1,13 @@
|
|||||||
define([
|
define([
|
||||||
'EventEmitter',
|
'EventEmitter',
|
||||||
'legacyRegistry',
|
'legacyRegistry',
|
||||||
|
'uuid',
|
||||||
'./api/api',
|
'./api/api',
|
||||||
'./api/objects/bundle'
|
'./api/objects/bundle'
|
||||||
], function (
|
], function (
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
legacyRegistry,
|
legacyRegistry,
|
||||||
|
uuid,
|
||||||
api
|
api
|
||||||
) {
|
) {
|
||||||
function MCT() {
|
function MCT() {
|
||||||
@ -18,6 +20,45 @@ define([
|
|||||||
Object.keys(api).forEach(function (k) {
|
Object.keys(api).forEach(function (k) {
|
||||||
MCT.prototype[k] = api[k];
|
MCT.prototype[k] = api[k];
|
||||||
});
|
});
|
||||||
|
MCT.prototype.MCT = MCT;
|
||||||
|
|
||||||
|
MCT.prototype.view = function (region, factory) {
|
||||||
|
var viewKey = region + uuid();
|
||||||
|
var adaptedViewKey = "adapted-view-" + viewKey;
|
||||||
|
|
||||||
|
this.legacyBundle.extensions.views =
|
||||||
|
this.legacyBundle.extensions.views || [];
|
||||||
|
this.legacyBundle.extensions.views.push({
|
||||||
|
name: "A view",
|
||||||
|
key: adaptedViewKey,
|
||||||
|
template: '<mct-view key="\'' +
|
||||||
|
viewKey +
|
||||||
|
'\'" ' +
|
||||||
|
'mct-object="domainObject">' +
|
||||||
|
'</mct-view>'
|
||||||
|
});
|
||||||
|
|
||||||
|
this.legacyBundle.extensions.policies =
|
||||||
|
this.legacyBundle.extensions.policies || [];
|
||||||
|
this.legacyBundle.extensions.policies.push({
|
||||||
|
category: "view",
|
||||||
|
implementation: function Policy() {
|
||||||
|
this.allow = function (view, domainObject) {
|
||||||
|
if (view.key === adaptedViewKey) {
|
||||||
|
return !!factory(domainObject);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.legacyBundle.extensions.newViews =
|
||||||
|
this.legacyBundle.extensions.newViews || [];
|
||||||
|
this.legacyBundle.extensions.newViews.push({
|
||||||
|
factory: factory,
|
||||||
|
key: viewKey
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
MCT.prototype.type = function (key, type) {
|
MCT.prototype.type = function (key, type) {
|
||||||
var legacyDef = type.toLegacyDefinition();
|
var legacyDef = type.toLegacyDefinition();
|
||||||
@ -25,6 +66,8 @@ define([
|
|||||||
this.legacyBundle.extensions.types =
|
this.legacyBundle.extensions.types =
|
||||||
this.legacyBundle.extensions.types || [];
|
this.legacyBundle.extensions.types || [];
|
||||||
this.legacyBundle.extensions.types.push(legacyDef);
|
this.legacyBundle.extensions.types.push(legacyDef);
|
||||||
|
|
||||||
|
type.key = key;
|
||||||
};
|
};
|
||||||
|
|
||||||
MCT.prototype.start = function () {
|
MCT.prototype.start = function () {
|
||||||
@ -32,5 +75,19 @@ define([
|
|||||||
this.emit('start');
|
this.emit('start');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
MCT.prototype.regions = {
|
||||||
|
main: "MAIN"
|
||||||
|
};
|
||||||
|
|
||||||
|
MCT.prototype.verbs = {
|
||||||
|
mutate: function (domainObject, mutator) {
|
||||||
|
return domainObject.useCapability('mutation', mutator)
|
||||||
|
.then(function () {
|
||||||
|
var persistence = domainObject.getCapability('persistence');
|
||||||
|
return persistence.persist();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return MCT;
|
return MCT;
|
||||||
});
|
});
|
||||||
|
16
src/adapter/bundle.js
Normal file
16
src/adapter/bundle.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
define([
|
||||||
|
'legacyRegistry',
|
||||||
|
'./directives/MCTView'
|
||||||
|
], function (legacyRegistry, MCTView) {
|
||||||
|
legacyRegistry.register('src/adapter', {
|
||||||
|
"extensions": {
|
||||||
|
"directives": [
|
||||||
|
{
|
||||||
|
key: "mctView",
|
||||||
|
implementation: MCTView,
|
||||||
|
depends: ["newViews[]"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
49
src/adapter/directives/MCTView.js
Normal file
49
src/adapter/directives/MCTView.js
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
define(['angular'], function (angular) {
|
||||||
|
function MCTView(newViews) {
|
||||||
|
var factories = {};
|
||||||
|
|
||||||
|
newViews.forEach(function (newView) {
|
||||||
|
factories[newView.key] = newView.factory;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
link: function (scope, element, attrs) {
|
||||||
|
var key = undefined;
|
||||||
|
var mctObject = undefined;
|
||||||
|
|
||||||
|
function maybeShow() {
|
||||||
|
if (!factories[key]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!mctObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var view = factories[key](mctObject);
|
||||||
|
view.show(element[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setKey(k) {
|
||||||
|
key = k;
|
||||||
|
maybeShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
function setObject(obj) {
|
||||||
|
mctObject = obj;
|
||||||
|
maybeShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.$watch('key', setKey);
|
||||||
|
scope.$watch('mctObject', setObject);
|
||||||
|
|
||||||
|
},
|
||||||
|
scope: {
|
||||||
|
key: "=",
|
||||||
|
mctObject: "="
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return MCTView;
|
||||||
|
});
|
@ -17,6 +17,16 @@ define(function () {
|
|||||||
this.definition = definition;
|
this.definition = definition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a domain object is an instance of this type.
|
||||||
|
* @param domainObject
|
||||||
|
* @returns {boolean} true if the domain object is of this type
|
||||||
|
*/
|
||||||
|
Type.prototype.check = function (domainObject) {
|
||||||
|
// Depends on assignment from MCT.
|
||||||
|
return domainObject.getModel().type === this.key;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a definition for this type that can be registered using the
|
* Get a definition for this type that can be registered using the
|
||||||
* legacy bundle format.
|
* legacy bundle format.
|
||||||
|
24
src/api/View.js
Normal file
24
src/api/View.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
define(function () {
|
||||||
|
function View() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show this view in the specified container. If this view is already
|
||||||
|
* showing elsewhere, it will be removed from that location.
|
||||||
|
*
|
||||||
|
* @param {HTMLElement} container the element to populate
|
||||||
|
*/
|
||||||
|
View.prototype.show = function (container) {
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release any resources associated with this view.
|
||||||
|
*
|
||||||
|
* Subclasses should override this method to release any resources
|
||||||
|
* they obtained during a `show` call.
|
||||||
|
*/
|
||||||
|
View.prototype.destroy = function () {
|
||||||
|
};
|
||||||
|
|
||||||
|
return View;
|
||||||
|
});
|
@ -1,12 +1,15 @@
|
|||||||
define([
|
define([
|
||||||
'./Type',
|
'./Type',
|
||||||
|
'./View',
|
||||||
'./objects/ObjectAPI'
|
'./objects/ObjectAPI'
|
||||||
], function (
|
], function (
|
||||||
Type,
|
Type,
|
||||||
|
View,
|
||||||
ObjectAPI
|
ObjectAPI
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
Type: Type,
|
Type: Type,
|
||||||
|
View: View,
|
||||||
Objects: ObjectAPI
|
Objects: ObjectAPI
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -9,51 +9,11 @@ define([
|
|||||||
"name": "To-do Plugin",
|
"name": "To-do Plugin",
|
||||||
"description": "Allows creating and editing to-do lists.",
|
"description": "Allows creating and editing to-do lists.",
|
||||||
"extensions": {
|
"extensions": {
|
||||||
"views": [
|
"stylesheets": [
|
||||||
{
|
{
|
||||||
"key": "example.todo",
|
"stylesheetUrl": "css/todo.css"
|
||||||
"type": "example.todo",
|
|
||||||
"glyph": "2",
|
|
||||||
"name": "List",
|
|
||||||
"templateUrl": "templates/todo.html",
|
|
||||||
"editable": true,
|
|
||||||
"toolbar": {
|
|
||||||
"sections": [
|
|
||||||
{
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"text": "Add Task",
|
|
||||||
"glyph": "+",
|
|
||||||
"method": "addTask",
|
|
||||||
"control": "button"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"glyph": "Z",
|
|
||||||
"method": "removeTask",
|
|
||||||
"control": "button"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"controllers": [
|
}
|
||||||
{
|
});
|
||||||
"key": "TodoController",
|
|
||||||
"implementation": TodoController,
|
|
||||||
"depends": [ "$scope", "dialogService" ]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"stylesheets": [
|
|
||||||
{
|
|
||||||
"stylesheetUrl": "css/todo.css"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
5
tutorials/todo/todo-task.html
Normal file
5
tutorials/todo/todo-task.html
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<li>
|
||||||
|
<input type="checkbox" class="example-task-checked">
|
||||||
|
<span class="example-task-description">
|
||||||
|
</span>
|
||||||
|
</li>
|
14
tutorials/todo/todo.html
Normal file
14
tutorials/todo/todo.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<div class="example-todo">
|
||||||
|
<div class="example-button-group">
|
||||||
|
<a class="example-todo-button-all">All</a>
|
||||||
|
<a class="example-todo-button-incomplete">Incomplete</a>
|
||||||
|
<a class="example-todo-button-complete">Complete</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul class="example-todo-task-list">
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="example-message">
|
||||||
|
There are no tasks to show.
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,4 +1,11 @@
|
|||||||
define(function () {
|
define([
|
||||||
|
"text!./todo.html",
|
||||||
|
"text!./todo-task.html",
|
||||||
|
"zepto"
|
||||||
|
], function (todoTemplate, taskTemplate, $) {
|
||||||
|
/**
|
||||||
|
* @param {mct.MCT} mct
|
||||||
|
*/
|
||||||
return function todoPlugin(mct) {
|
return function todoPlugin(mct) {
|
||||||
var todoType = new mct.Type({
|
var todoType = new mct.Type({
|
||||||
metadata: {
|
metadata: {
|
||||||
@ -7,12 +14,96 @@ define(function () {
|
|||||||
description: "A list of things that need to be done."
|
description: "A list of things that need to be done."
|
||||||
},
|
},
|
||||||
initialize: function (model) {
|
initialize: function (model) {
|
||||||
model.tasks = [];
|
model.tasks = [
|
||||||
|
{ description: "This is a task." }
|
||||||
|
];
|
||||||
},
|
},
|
||||||
creatable: true
|
creatable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function TodoView(domainObject) {
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.filterValue = "all";
|
||||||
|
}
|
||||||
|
|
||||||
|
TodoView.prototype.show = function (container) {
|
||||||
|
this.$els = $(todoTemplate);
|
||||||
|
this.$buttons = {
|
||||||
|
all: this.$els.find('.example-todo-button-all'),
|
||||||
|
incomplete: this.$els.find('.example-todo-button-incomplete'),
|
||||||
|
complete: this.$els.find('.example-todo-button-complete')
|
||||||
|
};
|
||||||
|
|
||||||
|
$(container).empty().append(this.$els);
|
||||||
|
|
||||||
|
this.initialize();
|
||||||
|
this.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
TodoView.prototype.destroy = function () {
|
||||||
|
};
|
||||||
|
|
||||||
|
TodoView.prototype.setFilter = function (value) {
|
||||||
|
this.filterValue = value;
|
||||||
|
this.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
TodoView.prototype.initialize = function () {
|
||||||
|
Object.keys(this.$buttons).forEach(function (k) {
|
||||||
|
this.$buttons[k].on('click', this.setFilter.bind(this, k));
|
||||||
|
}, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
TodoView.prototype.render = function () {
|
||||||
|
var $els = this.$els;
|
||||||
|
var domainObject = this.domainObject;
|
||||||
|
var tasks = domainObject.getModel().tasks;
|
||||||
|
var $message = $els.find('.example-message');
|
||||||
|
var $list = $els.find('.example-todo-task-list');
|
||||||
|
var $buttons = this.$buttons;
|
||||||
|
var filters = {
|
||||||
|
all: function () {
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
incomplete: function (task) {
|
||||||
|
return !task.completed;
|
||||||
|
},
|
||||||
|
complete: function (task) {
|
||||||
|
return task.completed;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var filterValue = this.filterValue;
|
||||||
|
|
||||||
|
Object.keys($buttons).forEach(function (k) {
|
||||||
|
$buttons[k].toggleClass('selected', filterValue === k);
|
||||||
|
});
|
||||||
|
tasks = tasks.filter(filters[filterValue]);
|
||||||
|
|
||||||
|
$list.empty();
|
||||||
|
tasks.forEach(function (task, index) {
|
||||||
|
var $taskEls = $(taskTemplate);
|
||||||
|
var $checkbox = $taskEls.find('.example-task-checked');
|
||||||
|
$checkbox.prop('checked', task.completed);
|
||||||
|
$taskEls.find('.example-task-description')
|
||||||
|
.text(task.description);
|
||||||
|
|
||||||
|
$checkbox.on('change', function () {
|
||||||
|
var checked = !!$checkbox.prop('checked');
|
||||||
|
mct.verbs.mutate(domainObject, function (model) {
|
||||||
|
model.tasks[index].completed = checked;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$list.append($taskEls);
|
||||||
|
});
|
||||||
|
|
||||||
|
$message.toggle(tasks.length < 1);
|
||||||
|
};
|
||||||
|
|
||||||
mct.type('example.todo', todoType);
|
mct.type('example.todo', todoType);
|
||||||
|
mct.view(mct.regions.main, function (domainObject) {
|
||||||
|
return todoType.check(domainObject) && new TodoView(domainObject);
|
||||||
|
});
|
||||||
|
|
||||||
return mct;
|
return mct;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user