mirror of
https://github.com/nasa/openmct.git
synced 2024-12-19 21:27:52 +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',
|
||||
'./src/MCT',
|
||||
|
||||
'./src/adapter/bundle',
|
||||
|
||||
'./platform/framework/bundle',
|
||||
'./platform/core/bundle',
|
||||
'./platform/representation/bundle',
|
||||
|
57
src/MCT.js
57
src/MCT.js
@ -1,11 +1,13 @@
|
||||
define([
|
||||
'EventEmitter',
|
||||
'legacyRegistry',
|
||||
'uuid',
|
||||
'./api/api',
|
||||
'./api/objects/bundle'
|
||||
], function (
|
||||
EventEmitter,
|
||||
legacyRegistry,
|
||||
uuid,
|
||||
api
|
||||
) {
|
||||
function MCT() {
|
||||
@ -18,6 +20,45 @@ define([
|
||||
Object.keys(api).forEach(function (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) {
|
||||
var legacyDef = type.toLegacyDefinition();
|
||||
@ -25,6 +66,8 @@ define([
|
||||
this.legacyBundle.extensions.types =
|
||||
this.legacyBundle.extensions.types || [];
|
||||
this.legacyBundle.extensions.types.push(legacyDef);
|
||||
|
||||
type.key = key;
|
||||
};
|
||||
|
||||
MCT.prototype.start = function () {
|
||||
@ -32,5 +75,19 @@ define([
|
||||
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;
|
||||
});
|
||||
|
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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([
|
||||
'./Type',
|
||||
'./View',
|
||||
'./objects/ObjectAPI'
|
||||
], function (
|
||||
Type,
|
||||
View,
|
||||
ObjectAPI
|
||||
) {
|
||||
return {
|
||||
Type: Type,
|
||||
View: View,
|
||||
Objects: ObjectAPI
|
||||
};
|
||||
});
|
||||
|
@ -9,51 +9,11 @@ define([
|
||||
"name": "To-do Plugin",
|
||||
"description": "Allows creating and editing to-do lists.",
|
||||
"extensions": {
|
||||
"views": [
|
||||
"stylesheets": [
|
||||
{
|
||||
"key": "example.todo",
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
"stylesheetUrl": "css/todo.css"
|
||||
}
|
||||
],
|
||||
"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) {
|
||||
var todoType = new mct.Type({
|
||||
metadata: {
|
||||
@ -7,12 +14,96 @@ define(function () {
|
||||
description: "A list of things that need to be done."
|
||||
},
|
||||
initialize: function (model) {
|
||||
model.tasks = [];
|
||||
model.tasks = [
|
||||
{ description: "This is a task." }
|
||||
];
|
||||
},
|
||||
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.view(mct.regions.main, function (domainObject) {
|
||||
return todoType.check(domainObject) && new TodoView(domainObject);
|
||||
});
|
||||
|
||||
return mct;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user