diff --git a/index.html b/index.html
index d8297d3d4a..685c9c20d8 100644
--- a/index.html
+++ b/index.html
@@ -35,8 +35,8 @@
'./example/imagery/bundle',
'./example/eventGenerator/bundle',
'./example/generator/bundle'
- ], function (TodoPlugin) {
- mct.install(TodoPlugin);
+ ], function (todoPlugin) {
+ mct.install(todoPlugin);
mct.run();
})
});
diff --git a/src/MCT.js b/src/MCT.js
index 8d44db17a0..18c46acb5c 100644
--- a/src/MCT.js
+++ b/src/MCT.js
@@ -4,7 +4,6 @@ define([
'uuid',
'./api/api',
'text!./adapter/templates/edit-object-replacement.html',
- './ui/Dialog',
'./Selection',
'./api/objects/object-utils'
], function (
@@ -13,13 +12,21 @@ define([
uuid,
api,
editObjectTemplate,
- Dialog,
Selection,
objectUtils
) {
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));
@@ -94,13 +101,6 @@ define([
region: region,
key: viewKey
});
-
- this.legacyExtension('services', {
- key: 'PublicAPI',
- implementation: function () {
- return this;
- }.bind(this)
- });
};
MCT.prototype.type = function (key, type) {
@@ -117,10 +117,6 @@ define([
});
};
- MCT.prototype.dialog = function (view, title) {
- return new Dialog(view, title).show();
- };
-
MCT.prototype.start = function () {
this.legacyExtension('runs', {
depends: ['navigationService'],
@@ -147,6 +143,7 @@ define([
MCT.prototype.regions = {
main: "MAIN",
+ properties: "PROPERTIES",
toolbar: "TOOLBAR"
};
diff --git a/src/adapter/actions/ActionDialogDecorator.js b/src/adapter/actions/ActionDialogDecorator.js
new file mode 100644
index 0000000000..60720085af
--- /dev/null
+++ b/src/adapter/actions/ActionDialogDecorator.js
@@ -0,0 +1,44 @@
+define([
+ '../../api/objects/object-utils'
+], function (objectUtils) {
+ function ActionDialogDecorator(mct, newViews, actionService) {
+ this.actionService = actionService;
+ this.mct = mct;
+ 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.definitions;
+
+ return this.actionService.getActions(context).map(function (action) {
+ if (action.dialogService) {
+ var domainObject = objectUtils.toNewFormat(
+ context.domainObject.getModel(),
+ objectUtils.parseKeyString(context.domainObject.getId())
+ );
+
+ 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) {
+ return new mct.Dialog(
+ definitions[0].view(context.domainObject),
+ form.title
+ ).show();
+ };
+ }
+ }
+ return action;
+ });
+ };
+
+ return ActionDialogDecorator;
+});
diff --git a/src/adapter/bundle.js b/src/adapter/bundle.js
index 30c18594ec..fcd9a3d380 100644
--- a/src/adapter/bundle.js
+++ b/src/adapter/bundle.js
@@ -1,13 +1,17 @@
define([
'legacyRegistry',
+ './actions/ActionDialogDecorator',
'./directives/MCTView',
'./services/Instantiate',
- './capabilities/APICapabilityDecorator'
+ './capabilities/APICapabilityDecorator',
+ './policies/AdapterCompositionPolicy'
], function (
legacyRegistry,
+ ActionDialogDecorator,
MCTView,
Instantiate,
- APICapabilityDecorator
+ APICapabilityDecorator,
+ AdapterCompositionPolicy
) {
legacyRegistry.register('src/adapter', {
"extensions": {
@@ -17,7 +21,7 @@ define([
implementation: MCTView,
depends: [
"newViews[]",
- "PublicAPI"
+ "mct"
]
}
],
@@ -41,6 +45,19 @@ define([
depends: [
"$injector"
]
+ },
+ {
+ type: "decorator",
+ provides: "actionService",
+ implementation: ActionDialogDecorator,
+ depends: [ "mct", "newViews[]" ]
+ }
+ ],
+ policies: [
+ {
+ category: "composition",
+ implementation: AdapterCompositionPolicy,
+ depends: [ "mct" ]
}
]
}
diff --git a/src/adapter/policies/AdapterCompositionPolicy.js b/src/adapter/policies/AdapterCompositionPolicy.js
new file mode 100644
index 0000000000..4cad9ce674
--- /dev/null
+++ b/src/adapter/policies/AdapterCompositionPolicy.js
@@ -0,0 +1,26 @@
+define([], function () {
+ function AdapterCompositionPolicy(mct) {
+ this.mct = mct;
+ }
+
+ AdapterCompositionPolicy.prototype.allow = function (
+ containerType,
+ childType
+ ) {
+ var containerObject = containerType.getInitialModel();
+ var childObject = childType.getInitialModel();
+
+ containerObject.type = containerType.getKey();
+ childObject.type = childType.getKey();
+
+ var composition = this.mct.Composition(containerObject);
+
+ if (composition) {
+ return composition.canContain(childObject);
+ }
+
+ return true;
+ };
+
+ return AdapterCompositionPolicy;
+});
diff --git a/src/api/api.js b/src/api/api.js
index 4c221c3f13..911a52669f 100644
--- a/src/api/api.js
+++ b/src/api/api.js
@@ -3,19 +3,22 @@ define([
'./TimeConductor',
'./View',
'./objects/ObjectAPI',
- './composition/CompositionAPI'
+ './composition/CompositionAPI',
+ './ui/Dialog'
], function (
Type,
TimeConductor,
View,
ObjectAPI,
- CompositionAPI
+ CompositionAPI,
+ Dialog
) {
return {
Type: Type,
TimeConductor: new TimeConductor(),
View: View,
Objects: ObjectAPI,
- Composition: CompositionAPI
+ Composition: CompositionAPI,
+ Dialog: Dialog
};
});
diff --git a/src/api/composition/CompositionCollection.js b/src/api/composition/CompositionCollection.js
index 9ab216e2e3..591085a629 100644
--- a/src/api/composition/CompositionCollection.js
+++ b/src/api/composition/CompositionCollection.js
@@ -52,6 +52,9 @@ define([
if (!this._children) {
throw new Error("Must load composition before you can add!");
}
+ if (!this.canContain(child)) {
+ throw new Error("This object cannot contain that object.");
+ }
if (this.contains(child)) {
if (skipMutate) {
return; // don't add twice, don't error.
@@ -94,6 +97,10 @@ define([
}
};
+ CompositionCollection.prototype.canContain = function (domainObject) {
+ return this.provider.canContain(this.domainObject, domainObject);
+ };
+
CompositionCollection.prototype.destroy = function () {
if (this.provider.off) {
this.provider.off(
diff --git a/src/api/composition/DefaultCompositionProvider.js b/src/api/composition/DefaultCompositionProvider.js
index d5cfb610cb..d935bf7a54 100644
--- a/src/api/composition/DefaultCompositionProvider.js
+++ b/src/api/composition/DefaultCompositionProvider.js
@@ -59,6 +59,10 @@ define([
);
};
+ DefaultCompositionProvider.prototype.canContain = function (domainObject, child) {
+ return true;
+ };
+
DefaultCompositionProvider.prototype.remove = function (domainObject, child) {
// TODO: this needs to be synchronized via mutation
var index = domainObject.composition.indexOf(child);
diff --git a/src/ui/Dialog.js b/src/api/ui/Dialog.js
similarity index 50%
rename from src/ui/Dialog.js
rename to src/api/ui/Dialog.js
index 9f462fb444..c8371cb67e 100644
--- a/src/ui/Dialog.js
+++ b/src/api/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;
});
diff --git a/src/ui/dialog.html b/src/api/ui/dialog.html
similarity index 100%
rename from src/ui/dialog.html
rename to src/api/ui/dialog.html
diff --git a/tutorials/todo/todo.js b/tutorials/todo/todo.js
index 4b3be4cfbe..9077683223 100644
--- a/tutorials/todo/todo.js
+++ b/tutorials/todo/todo.js
@@ -31,8 +31,27 @@ define([
this.setTaskStatus = this.setTaskStatus.bind(this);
this.selectTask = this.selectTask.bind(this);
+<<<<<<< HEAD
this.mutableObject = mct.Objects.getMutable(domainObject);
this.mutableObject.on('tasks', this.updateTasks.bind(this));
+=======
+ //If anything on object changes, re-render view
+ this.mutableObject.on("*", this.objectChanged);
+ };
+
+ TodoView.prototype.show = function (container) {
+ var self = this;
+ this.destroy();
+
+ 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);
+>>>>>>> origin/api-tutorials
this.$el = $(todoTemplate);
this.$emptyMessage = this.$el.find('.example-no-tasks');
@@ -41,6 +60,7 @@ define([
this.$el.on('change', 'li', this.setTaskStatus.bind(this));
this.$el.on('click', '.example-task-description', this.selectTask.bind(this));
+<<<<<<< HEAD
this.updateSelection = this.updateSelection.bind(this);
mct.selection.on('change', this.updateSelection);
}
@@ -48,6 +68,12 @@ define([
TodoView.prototype.show = function (container) {
$(container).empty().append(this.$el);
this.render();
+=======
+ self.initialize();
+ self.objectChanged(this.domainObject);
+
+ mct.selection.on('change', self.render);
+>>>>>>> origin/api-tutorials
};
TodoView.prototype.destroy = function () {
@@ -166,19 +192,58 @@ define([
};
TodoToolbarView.prototype.show = function (container) {
- $(container).empty().append(this.$el);
+ var self = this;
+ this.destroy();
+ this.$els = $(toolbarTemplate);
this.render();
+ $(container).append(this.$els);
};
TodoToolbarView.prototype.render = function () {
- this.$remove.toggle(this.selection >= 0);
+ var self = this;
+ var $els = this.$els;
+
+ self.mutableObject = mct.Objects.getMutable(this.domainObject);
+
+ var $add = $els.find('a.example-add');
+ var $remove = $els.find('a.example-remove');
+
+ $add.on('click', function () {
+ var $dialog = $(dialogTemplate),
+ view = {
+ show: function (container) {
+ $(container).append($dialog);
+ },
+ destroy: function () {}
+ };
+
+ new mct.Dialog(view, "Add a Task").show().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);
};
- TodoToolbarView.prototype.handleSelectionChange = function (selection) {
- if (selection && selection.length) {
- this.selection = selection[0].index;
- } else {
- this.selection = -1;
+ TodoToolbarView.prototype.handleSelectionChange = function () {
+ var selected = mct.selection.selected();
+ if (this.$remove) {
+ this.$remove.toggle(selected.length > 0);
}
this.render();
};