diff --git a/.gitignore b/.gitignore
index f9b5e3c120..b89c0e745f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,7 +13,7 @@ log.txt
## Build
/dist
-montage.dist.js
+montage.min.js
## jsdoc
/doc
diff --git a/README.md b/README.md
index 1b280f94f6..45e3011353 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
# MontageJS
+[](https://www.npmjs.com/package/montage)
+
[](http://travis-ci.org/montagejs/montage)
[](https://github.com/montagejs/montage)
diff --git a/composer/composer.js b/composer/composer.js
index a0b7e55f3c..e962d2b703 100644
--- a/composer/composer.js
+++ b/composer/composer.js
@@ -2,7 +2,8 @@
* @module montage/composer/composer
* @requires montage/core/target
*/
-var Target = require("../core/target").Target;
+var Target = require("../core/target").Target,
+ defaultEventManager = require("../core/event/event-manager").defaultEventManager;
/**
* The `Composer` helps to keep event normalization and calculation out of
@@ -69,6 +70,19 @@ exports.Composer = Target.specialize( /** @lends Composer# */ {
}
},
+ _shawdowRoot: {
+ value: null
+ },
+
+ shawdowRoot: {
+ get: function () {
+ if (!this._shawdowRoot) {
+ this._shawdowRoot = defaultEventManager.shawdowRootFromNode(this.element);
+ }
+ return this._shawdowRoot;
+ }
+ },
+
/**
* This property controls when the component will call this composer's
diff --git a/composer/press-composer.js b/composer/press-composer.js
index 9d53ef5c98..5500c2a99b 100644
--- a/composer/press-composer.js
+++ b/composer/press-composer.js
@@ -693,17 +693,35 @@ var PressComposer = exports.PressComposer = Composer.specialize(/** @lends Press
_addEventListeners: {
value: function () {
if (window.PointerEvent) {
+ if (this.shawdowRoot) {
+ this.shawdowRoot.addEventListener("pointerup", this, false);
+ this.shawdowRoot.addEventListener("pointermove", this, false);
+ this.shawdowRoot.addEventListener("pointercancel", this, false);
+ }
+
document.addEventListener("pointerup", this, false);
document.addEventListener("pointermove", this, false);
document.addEventListener("pointercancel", this, false);
} else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
+ if (this.shawdowRoot) {
+ this.shawdowRoot.addEventListener("MSPointerUp", this, false);
+ this.shawdowRoot.addEventListener("MSPointerMove", this, false);
+ this.shawdowRoot.addEventListener("MSPointerCancel", this, false);
+ }
+
document.addEventListener("MSPointerUp", this, false);
document.addEventListener("MSPointerMove", this, false);
document.addEventListener("MSPointerCancel", this, false);
} else {
if (this._observedPointer === "mouse") {
+ if (this.shawdowRoot) {
+ this.shawdowRoot.addEventListener("mouseup", this, false);
+ this.shawdowRoot.addEventListener("mousemove", this, false);
+ this.shawdowRoot.addEventListener("dragstart", this, false);
+ }
+
document.addEventListener("mouseup", this, false);
document.addEventListener("mousemove", this, false);
@@ -713,6 +731,12 @@ var PressComposer = exports.PressComposer = Composer.specialize(/** @lends Press
this._element.addEventListener("dragstart", this, false);
} else {
+ if (this.shawdowRoot) {
+ this.shawdowRoot.addEventListener("touchend", this, false);
+ this.shawdowRoot.addEventListener("touchcancel", this, false);
+ this.shawdowRoot.addEventListener("touchmove", this, false);
+ }
+
document.addEventListener("touchend", this, false);
document.addEventListener("touchcancel", this, false);
document.addEventListener("touchmove", this, false);
@@ -721,6 +745,11 @@ var PressComposer = exports.PressComposer = Composer.specialize(/** @lends Press
var wheelEventName = typeof window.onwheel !== "undefined" || typeof window.WheelEvent !== "undefined" ?
"wheel" : "mousewheel";
+
+ if (this.shawdowRoot) {
+ this.shawdowRoot.addEventListener(wheelEventName, this, true);
+ this.shawdowRoot.addEventListener("scroll", this, true);
+ }
document.addEventListener(wheelEventName, this, true);
document.addEventListener("scroll", this, true);
@@ -730,17 +759,35 @@ var PressComposer = exports.PressComposer = Composer.specialize(/** @lends Press
_removeEventListeners: {
value: function () {
if (window.PointerEvent) {
+ if (this.shawdowRoot) {
+ this.shawdowRoot.removeEventListener("pointerup", this, false);
+ this.shawdowRoot.removeEventListener("pointermove", this, false);
+ this.shawdowRoot.removeEventListener("pointercancel", this, false);
+ }
+
document.removeEventListener("pointerup", this, false);
document.removeEventListener("pointermove", this, false);
document.removeEventListener("pointercancel", this, false);
} else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
+ if (this.shawdowRoot) {
+ this.shawdowRoot.removeEventListener("MSPointerUp", this, false);
+ this.shawdowRoot.removeEventListener("MSPointerMove", this, false);
+ this.shawdowRoot.removeEventListener("MSPointerCancel", this, false);
+ }
+
document.removeEventListener("MSPointerUp", this, false);
document.removeEventListener("MSPointerMove", this, false);
document.removeEventListener("MSPointerCancel", this, false);
} else {
if (this._observedPointer === "mouse") {
+ if (this.shawdowRoot) {
+ this.shawdowRoot.removeEventListener("mouseup", this, false);
+ this.shawdowRoot.removeEventListener("mousemove", this, false);
+ this.shawdowRoot.removeEventListener("dragstart", this, false);
+ }
+
document.removeEventListener("mouseup", this, false);
document.removeEventListener("mousemove", this, false);
@@ -748,8 +795,15 @@ var PressComposer = exports.PressComposer = Composer.specialize(/** @lends Press
// no mouse events are fired
// http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#initiate-the-drag-and-drop-operation
this._element.removeEventListener("dragstart", this, false);
+
} else {
+ if (this.shawdowRoot) {
+ this.shawdowRoot.removeEventListener("touchend", this, false);
+ this.shawdowRoot.removeEventListener("touchcancel", this, false);
+ this.shawdowRoot.removeEventListener("touchmove", this, false);
+ }
+
document.removeEventListener("touchend", this, false);
document.removeEventListener("touchcancel", this, false);
document.removeEventListener("touchmove", this, false);
@@ -758,6 +812,11 @@ var PressComposer = exports.PressComposer = Composer.specialize(/** @lends Press
var wheelEventName = typeof window.onwheel !== "undefined" || typeof window.WheelEvent !== "undefined" ?
"wheel" : "mousewheel";
+
+ if (this.shawdowRoot) {
+ this.shawdowRoot.removeEventListener(wheelEventName, this, true);
+ this.shawdowRoot.removeEventListener("scroll", this, true);
+ }
document.removeEventListener(wheelEventName, this, true);
document.removeEventListener("scroll", this, true);
diff --git a/composer/rotation-composer.js b/composer/rotation-composer.js
new file mode 100644
index 0000000000..f9d3ab8a56
--- /dev/null
+++ b/composer/rotation-composer.js
@@ -0,0 +1,214 @@
+/**
+ * @module ./rotation-composer.reel
+ * @requires montage/composer/composer
+ */
+var Composer = require("./composer").Composer,
+ TranslateComposer = require("./translate-composer").TranslateComposer;
+
+/**
+ * @class RotationComposer
+ * @extends Composer
+ */
+exports.RotationComposer = Composer.specialize(/** @lends RotationComposer# */ {
+
+ /**
+ Dispatched when a rotation is started
+
+ @event rotationStart
+ @memberof RotationComposer
+ @param {RotationEvent} event
+ */
+
+ /**
+ Dispatched when a rotation changes
+
+ @event rotation
+ @memberof RotationComposer
+ @param {RotationEvent} event
+ */
+
+
+ /**
+ Unit for dispatched angles. Options: radians and degrees
+ Radians are the default as it is the standard in angular measures
+ To think about: should it accept "deg" as degrees to be equivalent to CSS notation?
+ */
+ _unit: {
+ value: "radians"
+ },
+
+ unit: {
+ get: function () {
+ return this._unit;
+ },
+ set: function (value) {
+ if (value === "degrees") {
+ this._unit = "degrees";
+ } else {
+ this._unit = "radians";
+ }
+ }
+ },
+
+ constructor: {
+ value: function RotationComposer() {
+ this.super();
+ this._translateComposer = new TranslateComposer();
+ this._translateComposer.hasMomentum = false;
+ this._translateComposer.hasBouncing = false;
+ }
+ },
+
+ // Load/unload
+
+ load: {
+ value: function() {
+ this.component.addComposerForElement(this._translateComposer, this.element);
+ this._translateComposer.load();
+ this._translateComposer.addEventListener("translateStart", this, false);
+ this._translateComposer.addEventListener("translateEnd", this, false);
+ this._translateComposer.addEventListener("translate", this, false);
+ }
+ },
+
+ unload: {
+ value: function() {
+ }
+ },
+
+ handleTranslateStart: {
+ value: function() {
+ var start = this._translateComposer.pointerStartEventPosition,
+ deltaX = start.pageX - this.center.pageX,
+ deltaY = start.pageY - this.center.pageY;
+
+ this._translateComposer.translateX = start.pageX;
+ this._translateComposer.translateY = start.pageY;
+ this._previousAngle = Math.atan2(deltaY, deltaX);
+ this._deltaAngle = 0;
+ this._dispatchRotateStart();
+ }
+ },
+
+ handleTranslateEnd: {
+ value: function() {
+ this._dispatchRotateEnd();
+ }
+ },
+
+ handleTranslate: {
+ value: function(event) {
+ var deltaX = event.translateX - this.center.pageX,
+ deltaY = event.translateY - this.center.pageY,
+ currentAngle = Math.atan2(deltaY, deltaX),
+ deltaAngle = currentAngle - this._previousAngle;
+
+ if (deltaAngle > Math.PI) {
+ deltaAngle -= Math.PI * 2;
+ } else {
+ if (deltaAngle < -Math.PI) {
+ deltaAngle += Math.PI * 2;
+ }
+ }
+ this.angleInRadians += deltaAngle;
+ this._deltaAngle = deltaAngle;
+ this._previousAngle = currentAngle;
+ this._dispatchRotate();
+ }
+ },
+
+ angleInRadians: {
+ value: 0
+ },
+
+ _deltaAngle: {
+ value: 0
+ },
+
+ _dispatchRotateStart: {
+ value: function() {
+ var event = document.createEvent("CustomEvent");
+
+ event.initCustomEvent("rotateStart", true, true, null);
+ event.unit = this._unit;
+ if (this._unit === "radians") {
+ event.rotation = this.angleInRadians;
+ event.deltaRotation = this._deltaAngle;
+ } else {
+ event.rotation = (this.angleInRadians * 180) / Math.PI;
+ event.deltaRotation = (this._deltaAngle * 180) / Math.PI;
+ }
+ this.dispatchEvent(event);
+ }
+ },
+
+ _dispatchRotate: {
+ value: function() {
+ var event = document.createEvent("CustomEvent");
+
+ event.initCustomEvent("rotate", true, true, null);
+ event.unit = this._unit;
+ if (this._unit === "radians") {
+ event.rotation = this.angleInRadians;
+ event.deltaRotation = this._deltaAngle;
+ } else {
+ event.rotation = (this.angleInRadians * 180) / Math.PI;
+ event.deltaRotation = (this._deltaAngle * 180) / Math.PI;
+ }
+ this.dispatchEvent(event);
+ }
+ },
+
+ _dispatchRotateEnd: {
+ value: function() {
+ var event = document.createEvent("CustomEvent");
+
+ event.initCustomEvent("rotateEnd", true, true, null);
+ event.unit = this._unit;
+ event.deltaRotation = 0;
+ if (this._unit === "radians") {
+ event.rotation = this.angleInRadians;
+ } else {
+ event.rotation = (this.angleInRadians * 180) / Math.PI;
+ }
+ this.dispatchEvent(event);
+ }
+ },
+
+ // To review: I would call this axisCoordinates or similar
+ center: {
+ value: null
+ },
+
+ _start: {
+ value: null
+ },
+
+ _translateComposer: {
+ value: null
+ },
+
+ animateMomentum: {
+ get: function () {
+ return this._translateComposer.animateMomentum;
+ },
+ set: function (value) {
+ this._translateComposer.animateMomentum = !!value;
+ }
+ },
+
+ /**
+ * Whether to keep translating after the user has releases the cursor.
+ * @type {boolean}
+ * @default true
+ */
+ hasMomentum: {
+ get: function () {
+ return this._translateComposer.hasMomentum;
+ },
+ set: function (value) {
+ this._translateComposer.hasMomentum = !!value;
+ }
+ }
+
+});
diff --git a/core/converter/bytes-converter.meta b/core/converter/bytes-converter.mjson
similarity index 58%
rename from core/converter/bytes-converter.meta
rename to core/converter/bytes-converter.mjson
index e6ba2ecbbe..a7d344f285 100644
--- a/core/converter/bytes-converter.meta
+++ b/core/converter/bytes-converter.mjson
@@ -1,34 +1,25 @@
{
"bytesConverter_decimals": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "decimals",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
"helpKey": ""
}
},
- "converter_blueprint_reference": {
- "prototype": "core/meta/blueprint-reference",
- "values": {
- "valueReference": {
- "blueprintName": "Converter",
- "prototypeName": "Converter",
- "blueprintModule": {
- "%": "core/converter/converter.meta"
- }
- }
- }
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-object-descriptor",
"values": {
"name": "BytesConverter",
"customPrototype": false,
"parent": {
- "@": "converter_blueprint_reference"
+ "@": "converter_descriptor"
},
"propertyDescriptors": [
{
@@ -43,8 +34,8 @@
]
},
"propertyValidationRules": {},
- "blueprintModule": {
- "%": "core/converter/bytes-converter.meta"
+ "objectDescriptorModule": {
+ "%": "core/converter/bytes-converter.mjson"
},
"exportName": "BytesConverter",
"module": {
diff --git a/core/converter/camel-case-converter.js b/core/converter/camel-case-converter.js
new file mode 100644
index 0000000000..8cfde06bd0
--- /dev/null
+++ b/core/converter/camel-case-converter.js
@@ -0,0 +1,45 @@
+/**
+ * @module montage/core/converter/camel-case-converter
+ * @requires montage/core/converter/converter
+ */
+var Converter = require("./converter").Converter,
+ camelCase = require('lodash.camelcase'),
+ singleton;
+
+/**
+ * Converts string to camel case.
+ *
+ * @class CamelCaseConverter
+ * @extends Converter
+ */
+var CamelCaseConverter = exports.CamelCaseConverter = Converter.specialize({
+
+ constructor: {
+ value: function () {
+ if (this.constructor === CamelCaseConverter) {
+ if (!singleton) {
+ singleton = this;
+ }
+
+ return singleton;
+ }
+
+ return this;
+ }
+ },
+
+ convert: {
+ value: camelCase
+ }
+
+});
+
+Object.defineProperty(exports, 'singleton', {
+ get: function () {
+ if (!singleton) {
+ singleton = new CamelCaseConverter();
+ }
+
+ return singleton;
+ }
+});
diff --git a/core/converter/camel-case-converter.mjson b/core/converter/camel-case-converter.mjson
new file mode 100644
index 0000000000..ecd4e690b8
--- /dev/null
+++ b/core/converter/camel-case-converter.mjson
@@ -0,0 +1,25 @@
+{
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
+ },
+ "root": {
+ "prototype": "core/meta/module-object-descriptor",
+ "values": {
+ "name": "CamelCaseConverter",
+ "customPrototype": false,
+ "parent": {
+ "@": "converter_descriptor"
+ },
+ "propertyDescriptors": [],
+ "propertyDescriptorGroups": {},
+ "propertyValidationRules": {},
+ "objectDescriptorModule": {
+ "%": "core/converter/camel-case-converter.mjson"
+ },
+ "exportName": "CamelCaseConverter",
+ "module": {
+ "%": "core/converter/camel-case-converter"
+ }
+ }
+ }
+}
diff --git a/core/converter/converter.js b/core/converter/converter.js
index e1e139f032..245a943fae 100644
--- a/core/converter/converter.js
+++ b/core/converter/converter.js
@@ -5,7 +5,10 @@
* @module montage/core/converter/converter
* @requires montage/core/core
*/
-var Montage = require("../core").Montage;
+var MontageModule = require("../core"),
+ Montage = MontageModule.Montage,
+ objectDescriptorModuleIdDescriptor = MontageModule._objectDescriptorModuleIdDescriptor,
+ objectDescriptorDescriptor = MontageModule._objectDescriptorDescriptor;
/**
* @const {string}
@@ -105,9 +108,9 @@ var Converter = exports.Converter = Montage.specialize( /** @lends Converter# */
}, {
- blueprintModuleId: require("../core")._blueprintModuleIdDescriptor,
+ objectDescriptorModuleId: objectDescriptorModuleIdDescriptor,
- blueprint: require("../core")._blueprintDescriptor
+ objectDescriptor: objectDescriptorDescriptor
});
diff --git a/core/converter/converter.meta b/core/converter/converter.mjson
similarity index 79%
rename from core/converter/converter.meta
rename to core/converter/converter.mjson
index b4e3c34f60..b094991011 100644
--- a/core/converter/converter.meta
+++ b/core/converter/converter.mjson
@@ -1,9 +1,9 @@
{
"converter_allowPartialConversion": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "allowPartialConversion",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"readOnly": true,
@@ -12,7 +12,7 @@
}
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-object-descriptor",
"values": {
"name": "Converter",
"customPrototype": false,
@@ -29,8 +29,8 @@
]
},
"propertyValidationRules": {},
- "blueprintModule": {
- "%": "core/converter/converter.meta"
+ "objectDescriptorModule": {
+ "%": "core/converter/converter.mjson"
},
"exportName": "Converter",
"module": {
diff --git a/core/converter/currency-converter.meta b/core/converter/currency-converter.mjson
similarity index 64%
rename from core/converter/currency-converter.meta
rename to core/converter/currency-converter.mjson
index 08618cfa1d..6973e3ace5 100644
--- a/core/converter/currency-converter.meta
+++ b/core/converter/currency-converter.mjson
@@ -1,32 +1,23 @@
{
"currenyConverter_currency": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "currency",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "string",
"helpKey": ""
}
},
- "number_converter_blueprint_reference": {
- "prototype": "core/meta/blueprint-reference",
- "values": {
- "valueReference": {
- "blueprintName": "NumberConverter",
- "prototypeName": "NumberConverter",
- "blueprintModule": {
- "%": "core/converter/number-converter.meta"
- }
- }
- }
+ "number_converter_descriptor": {
+ "object": "core/converter/number-converter.mjson"
},
"currencyConverter_showCurrencyBeforeNumber": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "showCurrencyBeforeNumber",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -34,12 +25,12 @@
}
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-object-descriptor",
"values": {
"name": "CurrencyConverter",
"customPrototype": false,
"parent": {
- "@": "number_converter_blueprint_reference"
+ "@": "number_converter_descriptor"
},
"propertyDescriptors": [
{
@@ -60,8 +51,8 @@
]
},
"propertyValidationRules": {},
- "blueprintModule": {
- "%": "core/converter/currency-converter.meta"
+ "objectDescriptorModule": {
+ "%": "core/converter/currency-converter.mjson"
},
"exportName": "CurrencyConverter",
"module": {
diff --git a/core/converter/date-converter.meta b/core/converter/date-converter.mjson
similarity index 64%
rename from core/converter/date-converter.meta
rename to core/converter/date-converter.mjson
index 02559c8aac..e80dd259f8 100644
--- a/core/converter/date-converter.meta
+++ b/core/converter/date-converter.mjson
@@ -1,9 +1,9 @@
{
"dateConverter_validator": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "validator",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "object",
@@ -11,35 +11,26 @@
}
},
"dateConverter_pattern": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "pattern",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "string",
"helpKey": ""
}
},
- "converter_blueprint_reference": {
- "prototype": "core/meta/blueprint-reference",
- "values": {
- "valueReference": {
- "blueprintName": "Converter",
- "prototypeName": "Converter",
- "blueprintModule": {
- "%": "core/converter/converter.meta"
- }
- }
- }
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-object-descriptor",
"values": {
"name": "DateConverter",
"customPrototype": false,
"parent": {
- "@": "converter_blueprint_reference"
+ "@": "converter_descriptor"
},
"propertyDescriptors": [
{
@@ -60,8 +51,8 @@
]
},
"propertyValidationRules": {},
- "blueprintModule": {
- "%": "core/converter/date-converter.meta"
+ "objectDescriptorModule": {
+ "%": "core/converter/date-converter.mjson"
},
"exportName": "DateConverter",
"module": {
diff --git a/core/converter/expression-converter.meta b/core/converter/expression-converter.mjson
similarity index 72%
rename from core/converter/expression-converter.meta
rename to core/converter/expression-converter.mjson
index a18233e33a..ae8943cb7d 100644
--- a/core/converter/expression-converter.meta
+++ b/core/converter/expression-converter.mjson
@@ -1,15 +1,6 @@
{
- "converter_object-descriptor_reference": {
- "prototype": "core/meta/object-descriptor-reference",
- "values": {
- "valueReference": {
- "blueprintName": "Converter",
- "prototypeName": "Converter",
- "blueprintModule": {
- "%": "core/converter/converter.meta"
- }
- }
- }
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
},
"convertExpression": {
"prototype": "core/meta/property-descriptor",
@@ -39,7 +30,7 @@
"name": "ExpressionConverter",
"customPrototype": false,
"parent": {
- "@": "converter_object-descriptor_reference"
+ "@": "converter_descriptor"
},
"propertyDescriptors": [
{
@@ -52,7 +43,7 @@
"propertyDescriptorGroups": {},
"propertyValidationRules": {},
"objectDescriptorModule": {
- "%": "core/converter/expression-converter.meta"
+ "%": "core/converter/expression-converter.mjson"
},
"exportName": "ExpressionConverter",
"module": {
diff --git a/core/converter/invert-converter.js b/core/converter/invert-converter.js
index ee4a588763..1aa811cbae 100644
--- a/core/converter/invert-converter.js
+++ b/core/converter/invert-converter.js
@@ -2,7 +2,10 @@
* @module montage/core/converter/invert-converter
* @requires montage/core/converter/converter
*/
-var Converter = require("./converter").Converter;
+var Converter = require("./converter").Converter,
+ deprecate = require("../deprecate"),
+ shouldMuteWarning = false,
+ singleton;
/**
* Inverts the value of a boolean value.
@@ -10,7 +13,29 @@ var Converter = require("./converter").Converter;
* @class InvertConverter
* @extends Converter
*/
-var InvertConverter = exports.InvertConverter = Converter.specialize( {
+var InvertConverter = exports.InvertConverter = Converter.specialize({
+
+ constructor: {
+ value: function () {
+ if (this.constructor === InvertConverter) {
+ if (!singleton) {
+ singleton = this;
+ }
+
+ if (!shouldMuteWarning) {
+ deprecate.deprecationWarning(
+ "Instantiating InvertConverter is deprecated," +
+ " use its singleton instead"
+ );
+ }
+
+ return singleton;
+ }
+
+ return this;
+ }
+ },
+
convert: {
value: function (v) {
return !v;
@@ -23,3 +48,15 @@ var InvertConverter = exports.InvertConverter = Converter.specialize( {
}
}
});
+
+Object.defineProperty(exports, 'singleton', {
+ get: function () {
+ if (!singleton) {
+ shouldMuteWarning = true;
+ singleton = new InvertConverter();
+ shouldMuteWarning = false;
+ }
+
+ return singleton;
+ }
+});
diff --git a/core/converter/invert-converter.meta b/core/converter/invert-converter.meta
deleted file mode 100644
index 70f3401b26..0000000000
--- a/core/converter/invert-converter.meta
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "converter_blueprint_reference": {
- "prototype": "core/meta/blueprint-reference",
- "values": {
- "valueReference": {
- "blueprintName": "Converter",
- "prototypeName": "Converter",
- "blueprintModule": {
- "%": "core/converter/converter.meta"
- }
- }
- }
- },
- "root": {
- "prototype": "core/meta/module-blueprint",
- "values": {
- "name": "InvertConverter",
- "customPrototype": false,
- "parent": {
- "@": "converter_blueprint_reference"
- },
- "propertyDescriptors": [],
- "propertyDescriptorGroups": {},
- "propertyValidationRules": {},
- "blueprintModule": {
- "%": "core/converter/inverter-converter.meta"
- },
- "exportName": "InvertConverter",
- "module": {
- "%": "core/converter/invert-converter"
- }
- }
- }
-}
diff --git a/core/converter/invert-converter.mjson b/core/converter/invert-converter.mjson
new file mode 100644
index 0000000000..a62f59c59f
--- /dev/null
+++ b/core/converter/invert-converter.mjson
@@ -0,0 +1,25 @@
+{
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
+ },
+ "root": {
+ "prototype": "core/meta/module-object-descriptor",
+ "values": {
+ "name": "InvertConverter",
+ "customPrototype": false,
+ "parent": {
+ "@": "converter_descriptor"
+ },
+ "propertyDescriptors": [],
+ "propertyDescriptorGroups": {},
+ "propertyValidationRules": {},
+ "objectDescriptorModule": {
+ "%": "core/converter/inverter-converter.mjson"
+ },
+ "exportName": "InvertConverter",
+ "module": {
+ "%": "core/converter/invert-converter"
+ }
+ }
+ }
+}
diff --git a/core/converter/kebab-case-converter.js b/core/converter/kebab-case-converter.js
new file mode 100644
index 0000000000..a418784567
--- /dev/null
+++ b/core/converter/kebab-case-converter.js
@@ -0,0 +1,44 @@
+/**
+ * @module montage/core/converter/kebab-case-converter
+ * @requires montage/core/converter/converter
+ */
+var Converter = require("./converter").Converter,
+ kebabCase = require('lodash.kebabcase'),
+ singleton;
+
+/**
+ * Converts string to kebab case.
+ *
+ * @class KebabCaseConverter
+ * @extends Converter
+ */
+var KebabCaseConverter = exports.KebabCaseConverter = Converter.specialize({
+
+ constructor: {
+ value: function () {
+ if (this.constructor === KebabCaseConverter) {
+ if (!singleton) {
+ singleton = this;
+ }
+
+ return singleton;
+ }
+
+ return this;
+ }
+ },
+
+ convert: {
+ value: kebabCase
+ }
+});
+
+Object.defineProperty(exports, 'singleton', {
+ get: function () {
+ if (!singleton) {
+ singleton = new KebabCaseConverter();
+ }
+
+ return singleton;
+ }
+});
diff --git a/core/converter/kebab-case-converter.mjson b/core/converter/kebab-case-converter.mjson
new file mode 100644
index 0000000000..5b077b3188
--- /dev/null
+++ b/core/converter/kebab-case-converter.mjson
@@ -0,0 +1,25 @@
+{
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
+ },
+ "root": {
+ "prototype": "core/meta/module-object-descriptor",
+ "values": {
+ "name": "KebabCaseConverter",
+ "customPrototype": false,
+ "parent": {
+ "@": "converter_descriptor"
+ },
+ "propertyDescriptors": [],
+ "propertyDescriptorGroups": {},
+ "propertyValidationRules": {},
+ "objectDescriptorModule": {
+ "%": "core/converter/kebab-case-converter.mjson"
+ },
+ "exportName": "KebabCaseConverter",
+ "module": {
+ "%": "core/converter/kebab-case-converter"
+ }
+ }
+ }
+}
diff --git a/core/converter/lower-case-converter.js b/core/converter/lower-case-converter.js
index edbfe1feb0..43ca920c24 100644
--- a/core/converter/lower-case-converter.js
+++ b/core/converter/lower-case-converter.js
@@ -2,13 +2,37 @@
* @module montage/core/converter/lower-case-converter
* @requires montage/core/converter/converter
*/
-var Converter = require("./converter").Converter;
+var Converter = require("./converter").Converter,
+ deprecate = require("../deprecate"),
+ shouldMuteWarning = false,
+ singleton;
/**
* @class LowerCaseConverter
* @classdesc Converts a string to lowercase.
*/
-exports.LowerCaseConverter = Converter.specialize( /** @lends LowerCaseConverter# */{
+var LowerCaseConverter = exports.LowerCaseConverter = Converter.specialize({
+
+ constructor: {
+ value: function () {
+ if (this.constructor === LowerCaseConverter) {
+ if (!singleton) {
+ singleton = this;
+ }
+
+ if (!shouldMuteWarning) {
+ deprecate.deprecationWarning(
+ "Instantiating LowerCaseConverter is deprecated," +
+ " use its singleton instead"
+ );
+ }
+
+ return singleton;
+ }
+
+ return this;
+ }
+ },
_convert: {
value: function (v) {
@@ -39,3 +63,14 @@ exports.LowerCaseConverter = Converter.specialize( /** @lends LowerCaseConverter
});
+Object.defineProperty(exports, 'singleton', {
+ get: function () {
+ if (!singleton) {
+ shouldMuteWarning = true;
+ singleton = new LowerCaseConverter();
+ shouldMuteWarning = false;
+ }
+
+ return singleton;
+ }
+});
diff --git a/core/converter/lower-case-converter.meta b/core/converter/lower-case-converter.meta
deleted file mode 100644
index 911f55ae4d..0000000000
--- a/core/converter/lower-case-converter.meta
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "converter_blueprint_reference": {
- "prototype": "core/meta/blueprint-reference",
- "values": {
- "valueReference": {
- "blueprintName": "Converter",
- "prototypeName": "Converter",
- "blueprintModule": {
- "%": "core/converter/converter.meta"
- }
- }
- }
- },
- "root": {
- "prototype": "core/meta/module-blueprint",
- "values": {
- "name": "LowerCaseConverter",
- "customPrototype": false,
- "parent": {
- "@": "converter_blueprint_reference"
- },
- "propertyDescriptors": [],
- "propertyDescriptorGroups": {},
- "propertyValidationRules": {},
- "blueprintModule": {
- "%": "core/converter/lower-case-converter.meta"
- },
- "exportName": "LowerCaseConverter",
- "module": {
- "%": "core/converter/lower-case-converter"
- }
- }
- }
-}
diff --git a/core/converter/lower-case-converter.mjson b/core/converter/lower-case-converter.mjson
new file mode 100644
index 0000000000..2fcc94263e
--- /dev/null
+++ b/core/converter/lower-case-converter.mjson
@@ -0,0 +1,25 @@
+{
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
+ },
+ "root": {
+ "prototype": "core/meta/module-object-descriptor",
+ "values": {
+ "name": "LowerCaseConverter",
+ "customPrototype": false,
+ "parent": {
+ "@": "converter_descriptor"
+ },
+ "propertyDescriptors": [],
+ "propertyDescriptorGroups": {},
+ "propertyValidationRules": {},
+ "objectDescriptorModule": {
+ "%": "core/converter/lower-case-converter.mjson"
+ },
+ "exportName": "LowerCaseConverter",
+ "module": {
+ "%": "core/converter/lower-case-converter"
+ }
+ }
+ }
+}
diff --git a/core/converter/new-line-to-br-converter.js b/core/converter/new-line-to-br-converter.js
index 54b59e8a35..871d67f622 100644
--- a/core/converter/new-line-to-br-converter.js
+++ b/core/converter/new-line-to-br-converter.js
@@ -2,7 +2,10 @@
* @module montage/core/converter/new-line-to-br-converter
* @requires montage/core/converter/converter
*/
-var Converter = require("./converter").Converter;
+var Converter = require("./converter").Converter,
+ deprecate = require("../deprecate"),
+ shouldMuteWarning = false,
+ singleton;
/**
* Replaces all new line characters with a HTML <br>
@@ -19,7 +22,28 @@ var newLineToBr = function (str) {
* @class NewLineToBrConverter
* @classdesc Converts a newline to a <br> tag.
*/
-exports.NewLineToBrConverter = Converter.specialize( /** @lends NewLineToBrConverter# */{
+var NewLineToBrConverter = exports.NewLineToBrConverter = Converter.specialize({
+
+ constructor: {
+ value: function () {
+ if (this.constructor === NewLineToBrConverter) {
+ if (!singleton) {
+ singleton = this;
+ }
+
+ if (!shouldMuteWarning) {
+ deprecate.deprecationWarning(
+ "Instantiating NewLineToBrConverter is deprecated," +
+ " use its singleton instead"
+ );
+ }
+
+ return singleton;
+ }
+
+ return this;
+ }
+ },
_convert: {
value: function (v) {
@@ -50,3 +74,14 @@ exports.NewLineToBrConverter = Converter.specialize( /** @lends NewLineToBrConve
});
+Object.defineProperty(exports, 'singleton', {
+ get: function () {
+ if (!singleton) {
+ shouldMuteWarning = true;
+ singleton = new NewLineToBrConverter();
+ shouldMuteWarning = false;
+ }
+
+ return singleton;
+ }
+});
diff --git a/core/converter/new-line-to-br-converter.meta b/core/converter/new-line-to-br-converter.meta
deleted file mode 100644
index dc0212a045..0000000000
--- a/core/converter/new-line-to-br-converter.meta
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "converter_blueprint_reference": {
- "prototype": "core/meta/blueprint-reference",
- "values": {
- "valueReference": {
- "blueprintName": "Converter",
- "prototypeName": "Converter",
- "blueprintModule": {
- "%": "core/converter/converter.meta"
- }
- }
- }
- },
- "root": {
- "prototype": "core/meta/module-blueprint",
- "values": {
- "name": "NewLineToBrConverter",
- "customPrototype": false,
- "parent": {
- "@": "converter_blueprint_reference"
- },
- "propertyDescriptors": [],
- "propertyDescriptorGroups": {},
- "propertyValidationRules": {},
- "blueprintModule": {
- "%": "core/converter/new-line-to-br-converter.meta"
- },
- "exportName": "NewLineToBrConverter",
- "module": {
- "%": "core/converter/new-line-to-br-converter"
- }
- }
- }
-}
diff --git a/core/converter/new-line-to-br-converter.mjson b/core/converter/new-line-to-br-converter.mjson
new file mode 100644
index 0000000000..44ca8e5111
--- /dev/null
+++ b/core/converter/new-line-to-br-converter.mjson
@@ -0,0 +1,25 @@
+{
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
+ },
+ "root": {
+ "prototype": "core/meta/module-object-descriptor",
+ "values": {
+ "name": "NewLineToBrConverter",
+ "customPrototype": false,
+ "parent": {
+ "@": "converter_descriptor"
+ },
+ "propertyDescriptors": [],
+ "propertyDescriptorGroups": {},
+ "propertyValidationRules": {},
+ "objectDescriptorModule": {
+ "%": "core/converter/new-line-to-br-converter.mjson"
+ },
+ "exportName": "NewLineToBrConverter",
+ "module": {
+ "%": "core/converter/new-line-to-br-converter"
+ }
+ }
+ }
+}
diff --git a/core/converter/number-converter.meta b/core/converter/number-converter.mjson
similarity index 72%
rename from core/converter/number-converter.meta
rename to core/converter/number-converter.mjson
index 9e82e7de19..6e373adf33 100644
--- a/core/converter/number-converter.meta
+++ b/core/converter/number-converter.mjson
@@ -1,9 +1,9 @@
{
"numberConverter_shorten": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "shorten",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -11,10 +11,10 @@
}
},
"numberConverter_decimals": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "decimals",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -22,10 +22,10 @@
}
},
"numberConverter_round": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "round",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -33,10 +33,10 @@
}
},
"numberConverter_forceDecimals": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "forceDecimals",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -44,10 +44,10 @@
}
},
"numberConverter_allowFloat": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "allowFloat",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -55,35 +55,26 @@
}
},
"numberConverter_allowNegative": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "allowNegative",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
"helpKey": ""
}
},
- "converter_blueprint_reference": {
- "prototype": "core/meta/blueprint-reference",
- "values": {
- "valueReference": {
- "blueprintName": "Converter",
- "prototypeName": "Converter",
- "blueprintModule": {
- "%": "core/converter/converter.meta"
- }
- }
- }
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-object-descriptor",
"values": {
"name": "NumberConverter",
"customPrototype": false,
"parent": {
- "@": "converter_blueprint_reference"
+ "@": "converter_descriptor"
},
"propertyDescriptors": [
{
@@ -105,7 +96,7 @@
"@": "numberConverter_allowNegative"
}
],
- "propertyBlueprintGroups": {
+ "propertyDescriptorGroups": {
"numberConverter": [
{
"@": "numberConverter_shorten"
@@ -128,8 +119,8 @@
]
},
"propertyValidationRules": {},
- "blueprintModule": {
- "%": "core/converter/number-converter.meta"
+ "objectDescriptorModule": {
+ "%": "core/converter/number-converter.mjson"
},
"exportName": "NumberConverter",
"module": {
diff --git a/core/converter/number-to-nearest-integer-converter.js b/core/converter/number-to-nearest-integer-converter.js
new file mode 100644
index 0000000000..2bbff703f8
--- /dev/null
+++ b/core/converter/number-to-nearest-integer-converter.js
@@ -0,0 +1,52 @@
+/**
+ * @module montage/core/converter/number-to-nearest-integer-converter
+ * @requires montage/core/converter/converter
+ */
+var Converter = require("./converter").Converter,
+ singleton;
+
+/**
+ * Converts a number to an integer
+ * @class NumberToNearestIntegerConverter
+ * @extends Converter
+ */
+var NumberToNearestIntegerConverter = exports.NumberToNearestIntegerConverter = Converter.specialize({
+
+ constructor: {
+ value: function () {
+ if (this.constructor === NumberToNearestIntegerConverter) {
+ if (!singleton) {
+ singleton = this;
+ }
+
+ return singleton;
+ }
+
+ return this;
+ }
+ },
+
+ convert: {
+ value: function(value) {
+ return Math.round(value);
+ }
+ },
+
+ revert: {
+ value: function(value) {
+ return Math.round(value);
+ }
+ }
+
+
+});
+
+Object.defineProperty(exports, 'singleton', {
+ get: function () {
+ if (!singleton) {
+ singleton = new NumberToNearestIntegerConverter();
+ }
+
+ return singleton;
+ }
+});
diff --git a/core/converter/number-to-nearest-integer-converter.mjson b/core/converter/number-to-nearest-integer-converter.mjson
new file mode 100644
index 0000000000..b929b68a7b
--- /dev/null
+++ b/core/converter/number-to-nearest-integer-converter.mjson
@@ -0,0 +1,25 @@
+{
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
+ },
+ "root": {
+ "prototype": "core/meta/module-object-descriptor",
+ "values": {
+ "name": "NumberToNearestIntegerConverter",
+ "customPrototype": false,
+ "parent": {
+ "@": "converter_descriptor"
+ },
+ "propertyDescriptors": [],
+ "propertyDescriptorGroups": {},
+ "propertyValidationRules": {},
+ "objectDescriptorModule": {
+ "%": "core/converter/number-to-nearest-integer-converter.mjson"
+ },
+ "exportName": "NumberToNearestIntegerConverter",
+ "module": {
+ "%": "core/converter/number-to-nearest-integer-converter"
+ }
+ }
+ }
+}
diff --git a/core/converter/pipeline-converter.js b/core/converter/pipeline-converter.js
index 6283da5e66..eb0c6fa063 100644
--- a/core/converter/pipeline-converter.js
+++ b/core/converter/pipeline-converter.js
@@ -33,27 +33,31 @@ exports.PipelineConverter = Converter.specialize({
convert: {
value: function (value) {
- return this._convertWithNextConverter(value, this.converters.slice());
+ return this._convertWithConverterAtIndex(value, 0);
}
},
- _convertWithNextConverter: {
- value: function (input, converters) {
+ _convertWithConverterAtIndex: {
+ value: function (input, index) {
var self = this,
- converter = converters.shift(),
+ converter = this.converters[index],
output = converter.convert(input),
- isFinalOutput = converters.length === 0,
+ isFinalOutput = index === (this.converters.length - 1),
isPromise = this._isThenable(output),
result;
+ index++;
+
+
+
if (isFinalOutput) {
result = isPromise ? output : Promise.resolve(output);
} else if (isPromise) {
result = output.then(function (value) {
- return self._convertWithNextConverter(value, converters);
+ return self._convertWithConverterAtIndex(value, index);
});
} else {
- result = this._convertWithNextConverter(output, converters);
+ result = this._convertWithConverterAtIndex(output, index);
}
return result;
@@ -69,27 +73,29 @@ exports.PipelineConverter = Converter.specialize({
revert: {
value: function (value) {
- return this._revertWithNextConverter(value, this.converters.slice());
+ return this._revertWithConverterAtIndex(value, this.converters.length - 1);
}
},
- _revertWithNextConverter: {
- value: function (input, converters) {
+ _revertWithConverterAtIndex: {
+ value: function (input, index) {
var self = this,
- converter = converters.pop(),
+ converter = this.converters[index],
output = converter.revert(input),
- isFinalOutput = converters.length === 0,
+ isFinalOutput = index === 0,
isPromise = this._isThenable(output),
result;
+ index--;
+
if (isFinalOutput) {
result = isPromise ? output : Promise.resolve(output);
} else if (isPromise) {
result = output.then(function (value) {
- return self._revertWithNextConverter(value, converters);
+ return self._revertWithConverterAtIndex(value, index);
});
} else {
- result = this._revertWithNextConverter(output, converters);
+ result = this._revertWithConverterAtIndex(output, index);
}
return result;
diff --git a/core/converter/snake-case-converter.js b/core/converter/snake-case-converter.js
new file mode 100644
index 0000000000..291558d386
--- /dev/null
+++ b/core/converter/snake-case-converter.js
@@ -0,0 +1,44 @@
+/**
+ * @module montage/core/converter/snake-case-converter
+ * @requires montage/core/converter/converter
+ */
+var Converter = require("./converter").Converter,
+ snakeCase = require('lodash.snakecase'),
+ singleton;
+
+/**
+ * Converts string to snake case.
+ *
+ * @class SnakeCaseConverter
+ * @extends Converter
+ */
+var SnakeCaseConverter = exports.SnakeCaseConverter = Converter.specialize({
+
+ constructor: {
+ value: function () {
+ if (this.constructor === SnakeCaseConverter) {
+ if (!singleton) {
+ singleton = this;
+ }
+
+ return singleton;
+ }
+
+ return this;
+ }
+ },
+
+ convert: {
+ value: snakeCase
+ }
+});
+
+Object.defineProperty(exports, 'singleton', {
+ get: function () {
+ if (!singleton) {
+ singleton = new SnakeCaseConverter();
+ }
+
+ return singleton;
+ }
+});
diff --git a/core/converter/snake-case-converter.mjson b/core/converter/snake-case-converter.mjson
new file mode 100644
index 0000000000..6e9cdb0410
--- /dev/null
+++ b/core/converter/snake-case-converter.mjson
@@ -0,0 +1,25 @@
+{
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
+ },
+ "root": {
+ "prototype": "core/meta/module-object-descriptor",
+ "values": {
+ "name": "SnakeCaseConverter",
+ "customPrototype": false,
+ "parent": {
+ "@": "converter_descriptor"
+ },
+ "propertyDescriptors": [],
+ "propertyDescriptorGroups": {},
+ "propertyValidationRules": {},
+ "objectDescriptorModule": {
+ "%": "core/converter/snake-case-converter.mjson"
+ },
+ "exportName": "SnakeCaseConverter",
+ "module": {
+ "%": "core/converter/snake-case-converter"
+ }
+ }
+ }
+}
diff --git a/core/converter/trim-converter.js b/core/converter/trim-converter.js
index cc4c01b099..2e0868ad61 100644
--- a/core/converter/trim-converter.js
+++ b/core/converter/trim-converter.js
@@ -2,23 +2,11 @@
* @module montage/core/converter/trim-converter
* @requires montage/core/converter/converter
*/
-var Converter = require("./converter").Converter;
-
-
-/**
- * Trims a string of any leading or trailing white space.
- * @memberof module:montage/core/converter#
- * @function
- * @param {string} str String to be trimmed.
- * @returns {string} The trimmed string.
- */
-var trim = exports.trim = function (str) {
- // from Google Closure library
- // Since IE doesn't include non-breaking-space (0xa0) in their \s character
- // class (as required by section 7.2 of the ECMAScript spec), we explicitly
- // include it in the regexp to enforce consistent cross-browser behavior.
- return str.replace(/^[\s\xa0]+|[\s\xa0]+$/g, '');
-};
+var Converter = require("./converter").Converter,
+ trim = require('lodash.trim'),
+ deprecate = require("../deprecate"),
+ shouldMuteWarning = false,
+ singleton;
/**
* @class TrimConverter
@@ -32,7 +20,28 @@ var trim = exports.trim = function (str) {
* console.log("After trim: " + trimConverter.convert(str));
* // After trim: Hello World
*/
-exports.TrimConverter = Converter.specialize( /** @lends TrimConverter# */ {
+var TrimConverter = exports.TrimConverter = Converter.specialize({
+
+ constructor: {
+ value: function () {
+ if (this.constructor === TrimConverter) {
+ if (!singleton) {
+ singleton = this;
+ }
+
+ if (!shouldMuteWarning) {
+ deprecate.deprecationWarning(
+ "Instantiating TrimConverter is deprecated," +
+ " use its singleton instead"
+ );
+ }
+
+ return singleton;
+ }
+
+ return this;
+ }
+ },
_convert: {
value: function (v) {
@@ -64,3 +73,14 @@ exports.TrimConverter = Converter.specialize( /** @lends TrimConverter# */ {
});
+Object.defineProperty(exports, 'singleton', {
+ get: function () {
+ if (!singleton) {
+ shouldMuteWarning = true;
+ singleton = new TrimConverter();
+ shouldMuteWarning = false;
+ }
+
+ return singleton;
+ }
+});
diff --git a/core/converter/trim-converter.meta b/core/converter/trim-converter.meta
deleted file mode 100644
index bbeaad42d4..0000000000
--- a/core/converter/trim-converter.meta
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "converter_blueprint_reference": {
- "prototype": "core/meta/blueprint-reference",
- "values": {
- "valueReference": {
- "blueprintName": "Converter",
- "prototypeName": "Converter",
- "blueprintModule": {
- "%": "core/converter/converter.meta"
- }
- }
- }
- },
- "root": {
- "prototype": "core/meta/module-blueprint",
- "values": {
- "name": "TrimConverter",
- "customPrototype": false,
- "parent": {
- "@": "converter_blueprint_reference"
- },
- "propertyDescriptors": [],
- "propertyBlueprintGroups": {},
- "propertyValidationRules": {},
- "blueprintModule": {
- "%": "core/converter/trim-converter.meta"
- },
- "exportName": "TrimConverter",
- "module": {
- "%": "core/converter/trim-converter"
- }
- }
- }
-}
diff --git a/core/converter/trim-converter.mjson b/core/converter/trim-converter.mjson
new file mode 100644
index 0000000000..9052b42fdc
--- /dev/null
+++ b/core/converter/trim-converter.mjson
@@ -0,0 +1,25 @@
+{
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
+ },
+ "root": {
+ "prototype": "core/meta/module-object-descriptor",
+ "values": {
+ "name": "TrimConverter",
+ "customPrototype": false,
+ "parent": {
+ "@": "converter_descriptor"
+ },
+ "propertyDescriptors": [],
+ "propertyDescriptorGroups": {},
+ "propertyValidationRules": {},
+ "objectDescriptorModule": {
+ "%": "core/converter/trim-converter.mjson"
+ },
+ "exportName": "TrimConverter",
+ "module": {
+ "%": "core/converter/trim-converter"
+ }
+ }
+ }
+}
diff --git a/core/converter/upper-case-converter.js b/core/converter/upper-case-converter.js
index cff18e03a5..9e4f6bf704 100644
--- a/core/converter/upper-case-converter.js
+++ b/core/converter/upper-case-converter.js
@@ -2,13 +2,37 @@
* @module montage/core/converter/upper-case-converter
* @requires montage/core/converter/converter
*/
-var Converter = require("./converter").Converter;
+var Converter = require("./converter").Converter,
+ deprecate = require("../deprecate"),
+ shouldMuteWarning = false,
+ singleton;
/**
* @class UpperCaseConverter
* @classdesc Converts a string to upper-case.
*/
-exports.UpperCaseConverter = Converter.specialize( /** @lends UpperCaseConverter# */ {
+var UpperCaseConverter = exports.UpperCaseConverter = Converter.specialize({
+
+ constructor: {
+ value: function () {
+ if (this.constructor === UpperCaseConverter) {
+ if (!singleton) {
+ singleton = this;
+ }
+
+ if (!shouldMuteWarning) {
+ deprecate.deprecationWarning(
+ "Instantiating UpperCaseConverter is deprecated," +
+ " use its singleton instead"
+ );
+ }
+
+ return singleton;
+ }
+
+ return this;
+ }
+ },
_convert: {
value: function (v) {
@@ -41,3 +65,14 @@ exports.UpperCaseConverter = Converter.specialize( /** @lends UpperCaseConverter
});
+Object.defineProperty(exports, 'singleton', {
+ get: function () {
+ if (!singleton) {
+ shouldMuteWarning = true;
+ singleton = new UpperCaseConverter();
+ shouldMuteWarning = false;
+ }
+
+ return singleton;
+ }
+});
diff --git a/core/converter/upper-case-converter.meta b/core/converter/upper-case-converter.meta
deleted file mode 100644
index 53a71e4fcc..0000000000
--- a/core/converter/upper-case-converter.meta
+++ /dev/null
@@ -1,34 +0,0 @@
-{
- "converter_blueprint_reference": {
- "prototype": "core/meta/blueprint-reference",
- "values": {
- "valueReference": {
- "blueprintName": "Converter",
- "prototypeName": "Converter",
- "blueprintModule": {
- "%": "core/converter/converter.meta"
- }
- }
- }
- },
- "root": {
- "prototype": "core/meta/module-blueprint",
- "values": {
- "name": "UpperCaseConverter",
- "customPrototype": false,
- "parent": {
- "@": "converter_blueprint_reference"
- },
- "propertyDescriptors": [],
- "propertyDescriptorGroups": {},
- "propertyValidationRules": {},
- "blueprintModule": {
- "%": "core/converter/upper-case-converter.meta"
- },
- "exportName": "UpperCaseConverter",
- "module": {
- "%": "core/converter/upper-case-converter"
- }
- }
- }
-}
diff --git a/core/converter/upper-case-converter.mjson b/core/converter/upper-case-converter.mjson
new file mode 100644
index 0000000000..1788689f48
--- /dev/null
+++ b/core/converter/upper-case-converter.mjson
@@ -0,0 +1,25 @@
+{
+ "converter_descriptor": {
+ "object": "core/converter/converter.mjson"
+ },
+ "root": {
+ "prototype": "core/meta/module-object-descriptor",
+ "values": {
+ "name": "UpperCaseConverter",
+ "customPrototype": false,
+ "parent": {
+ "@": "converter_descriptor"
+ },
+ "propertyDescriptors": [],
+ "propertyDescriptorGroups": {},
+ "propertyValidationRules": {},
+ "objectDescriptorModule": {
+ "%": "core/converter/upper-case-converter.mjson"
+ },
+ "exportName": "UpperCaseConverter",
+ "module": {
+ "%": "core/converter/upper-case-converter"
+ }
+ }
+ }
+}
diff --git a/core/core.js b/core/core.js
index 04cfce882d..20c2118ab9 100644
--- a/core/core.js
+++ b/core/core.js
@@ -11,6 +11,7 @@ require("./extras/element");
require("./extras/function");
require("./extras/regexp");
require("./extras/string");
+require("proxy-polyfill/proxy.min");
var Map = require("collections/map");
@@ -1610,10 +1611,6 @@ var pathPropertyDescriptors = {
Montage.defineProperties(Montage, pathPropertyDescriptors);
Montage.defineProperties(Montage.prototype, pathPropertyDescriptors);
-// has to come last since serializer and deserializer depend on logger, which
-// in turn depends on montage running to completion
-require("./serialization/bindings");
-
/*
* Defines the module Id for object descriptors. This is externalized so that it can be subclassed.
* Note This is a class method beware...
@@ -1727,3 +1724,7 @@ exports._objectDescriptorDescriptor = {
* @deprecated use exports._objectDescriptorDescriptor
*/
exports._blueprintDescriptor = exports._objectDescriptorDescriptor;
+
+// has to come last since serializer and deserializer depend on logger, which
+// in turn depends on montage running to completion
+require("./serialization/bindings");
diff --git a/core/event/action-event-listener.js b/core/event/action-event-listener.js
index 4a3217c618..8133718a59 100644
--- a/core/event/action-event-listener.js
+++ b/core/event/action-event-listener.js
@@ -82,6 +82,8 @@ var ActionEventListener = exports.ActionEventListener = Montage.specialize( /**
}
}, {
+ objectDescriptorModuleId: require("../core")._objectDescriptorModuleIdDescriptor,
+ objectDescriptor: require("../core")._objectDescriptorDescriptor,
blueprintModuleId: require("../core")._blueprintModuleIdDescriptor,
blueprint: require("../core")._blueprintDescriptor
});
diff --git a/core/event/action-event-listener.meta b/core/event/action-event-listener.meta
index 3664130a2e..ea0f08e42e 100644
--- a/core/event/action-event-listener.meta
+++ b/core/event/action-event-listener.meta
@@ -1,26 +1,26 @@
{
"actionEventListener_handler": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "handler",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "object"
}
},
"actionEventListener_action": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "action",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "string"
}
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-descriptor",
"values": {
"name": "ActionEventListener",
"customPrototype": false,
@@ -32,7 +32,7 @@
"@": "actionEventListener_action"
}
],
- "propertyBlueprintGroups": {
+ "propertyDescriptorGroups": {
"actionEventListener": [
{
"@": "actionEventListener_handler"
@@ -42,7 +42,7 @@
}
]
},
- "blueprintModule": {
+ "objectDescriptorModule": {
"%": "core/event/action-event-listener.meta"
},
"exportName": "ActionEventListener",
diff --git a/core/event/event-manager.js b/core/event/event-manager.js
index e017a8e964..56d8e812e0 100644
--- a/core/event/event-manager.js
+++ b/core/event/event-manager.js
@@ -1,4 +1,4 @@
-/*global Window, Document, Element, Event, Components, Touch */
+/*global Window, Document, Element, Event, Components, Touch, MontageElement */
/**
* @author Lea Verou
@@ -560,6 +560,15 @@ var EventManager = exports.EventManager = Montage.specialize(/** @lends EventMan
aWindow.document.nativeAddEventListener = aWindow.document.addEventListener;
aWindow.XMLHttpRequest.prototype.nativeAddEventListener = aWindow.XMLHttpRequest.prototype.addEventListener;
+
+ if (aWindow.DocumentFragment) {
+ aWindow.DocumentFragment.prototype.nativeAddEventListener = aWindow.DocumentFragment.prototype.addEventListener;
+ }
+
+ if (aWindow.ShadowRoot) {
+ aWindow.ShadowRoot.prototype.nativeAddEventListener = aWindow.ShadowRoot.prototype.addEventListener;
+ }
+
if (aWindow.Worker) {
aWindow.Worker.prototype.nativeAddEventListener = aWindow.Worker.prototype.addEventListener;
}
@@ -575,6 +584,15 @@ var EventManager = exports.EventManager = Montage.specialize(/** @lends EventMan
aWindow.document.nativeRemoveEventListener = aWindow.document.removeEventListener;
aWindow.XMLHttpRequest.prototype.nativeRemoveEventListener = aWindow.XMLHttpRequest.prototype.removeEventListener;
+
+ if (aWindow.DocumentFragment) {
+ aWindow.DocumentFragment.prototype.nativeRemoveEventListener = aWindow.DocumentFragment.prototype.removeEventListener;
+ }
+
+ if (aWindow.ShadowRoot) {
+ aWindow.ShadowRoot.prototype.nativeRemoveEventListener = aWindow.ShadowRoot.prototype.removeEventListener;
+ }
+
if (aWindow.Worker) {
aWindow.Worker.prototype.nativeRemoveEventListener = aWindow.Worker.prototype.removeEventListener;
}
@@ -1167,12 +1185,27 @@ var EventManager = exports.EventManager = Montage.specialize(/** @lends EventMan
if (bubbles) {
// TODO why on the document and not the window?
- return /* isWindow*/target.screen ? target.document : target.ownerDocument;
+ var shadowRoot;
+ return /* isWindow*/target.screen ? target.document :
+ (shadowRoot = this.shawdowRootFromNode(target)) ?
+ shadowRoot : target.ownerDocument;
} else {
return target;
}
}
+ }
+ },
+ shawdowRootFromNode: {
+ value: function isInShadow(node) {
+ if (window.ShadowRoot) {
+ while (node) {
+ if (node.toString() === "[object ShadowRoot]") {
+ return node;
+ }
+ node = node.parentNode;
+ }
+ }
}
},
@@ -1183,6 +1216,16 @@ var EventManager = exports.EventManager = Montage.specialize(/** @lends EventMan
// Individual Event Registration
+ _scrollBlockingEvents: {
+ value: [
+ 'wheel',
+ 'mousewheel',
+ 'touchstart',
+ 'touchmove',
+ 'scroll'
+ ]
+ },
+
/**
* @private
*/
@@ -1198,7 +1241,12 @@ var EventManager = exports.EventManager = Montage.specialize(/** @lends EventMan
}
this._observedTarget_byEventType_[eventType].set(listenerTarget,this);
- listenerTarget.nativeAddEventListener(eventType, this, true);
+ var isScrollBlocking = this._scrollBlockingEvents.indexOf(eventType) !== -1,
+ eventOpts = isScrollBlocking ? {
+ passive: true
+ } : true;
+
+ listenerTarget.nativeAddEventListener(eventType, this, eventOpts);
}
// console.log("started listening: ", eventType, listenerTarget)
}
@@ -1262,43 +1310,50 @@ var EventManager = exports.EventManager = Montage.specialize(/** @lends EventMan
}
};
}
+
+ this.registerTargetForActivation(aWindow);
+
+ if (this.application) {
+
+ var applicationLevelEvents = this.registeredEventListenersOnTarget_(this.application),
+ eventType;
+ for (eventType in applicationLevelEvents) {
+ if (applicationLevelEvents.hasOwnProperty(eventType)) {
+ this._observeTarget_forEventType_(aWindow, eventType);
+ }
+ }
+ }
+ }
+ },
+
+ registerTargetForActivation: {
+ value: function (target) {
+ var _document = target instanceof Window ? target.document : target;
// The EventManager needs to handle "gateway/pointer/activation events" that we
// haven't let children listen for yet
// when the EM handles them eventually it will need to allow
// all components from the event target to the window to prepareForActivationEvents
// before finding event handlers that were registered for these events
- if (aWindow.PointerEvent) {
- aWindow.nativeAddEventListener("pointerdown", this._activationHandler, true);
- aWindow.document.nativeAddEventListener("pointerenter", this._activationHandler, true);
+ if (window.PointerEvent) {
+ target.nativeAddEventListener("pointerdown", this._activationHandler, true);
+ _document.nativeAddEventListener("pointerenter", this._activationHandler, true);
- } else if (aWindow.MSPointerEvent && aWindow.navigator.msPointerEnabled) {
- aWindow.nativeAddEventListener("MSPointerDown", this._activationHandler, true);
+ } else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
+ target.nativeAddEventListener("MSPointerDown", this._activationHandler, true);
// IE10 has no support for pointerenter or pointerleave events.
- aWindow.document.nativeAddEventListener("mouseenter", this._activationHandler, true);
+ _document.nativeAddEventListener("mouseenter", this._activationHandler, true);
} else {
- aWindow.nativeAddEventListener("touchstart", this._activationHandler, true);
- aWindow.nativeAddEventListener("mousedown", this._activationHandler, true);
+ target.nativeAddEventListener("touchstart", this._activationHandler, true);
+ target.nativeAddEventListener("mousedown", this._activationHandler, true);
// mouseenter events are not dispatched from window under Chrome and Safari.
- aWindow.document.nativeAddEventListener("mouseenter", this._activationHandler, true);
- }
-
- aWindow.nativeAddEventListener("focus", this._activationHandler, true);
-
- if (this.application) {
-
- var applicationLevelEvents = this.registeredEventListenersOnTarget_(this.application),
- eventType;
-
- for (eventType in applicationLevelEvents) {
- if (applicationLevelEvents.hasOwnProperty(eventType)) {
- this._observeTarget_forEventType_(aWindow, eventType);
- }
- }
+ _document.nativeAddEventListener("mouseenter", this._activationHandler, true);
}
+ target.nativeAddEventListener("focus", this._activationHandler, true);
}
+
},
/**
@@ -2347,10 +2402,10 @@ var EventManager = exports.EventManager = Montage.specialize(/** @lends EventMan
break;
}
}
-
return identifier;
}
},
+
/**
* @function
@@ -2373,6 +2428,7 @@ var EventManager = exports.EventManager = Montage.specialize(/** @lends EventMan
}
},
+
// Event Handling
/**
* @property
@@ -2412,7 +2468,8 @@ var EventManager = exports.EventManager = Montage.specialize(/** @lends EventMan
handleEvent: {
enumerable: false,
value: function (event) {
- if (event instanceof UIEvent && !this._shouldDispatchEvent(event)) {
+ if ((window.MontageElement && event.target instanceof MontageElement) ||
+ (event instanceof UIEvent && !this._shouldDispatchEvent(event))) {
return void 0;
}
diff --git a/core/extras/dom.js b/core/extras/dom.js
index 2f8f9bc648..e3aa5f8830 100644
--- a/core/extras/dom.js
+++ b/core/extras/dom.js
@@ -184,4 +184,17 @@ if (typeof Node !== "undefined") {
}
}
};
-}
\ No newline at end of file
+}
+
+// Extend DOMTokenList.prototype
+if (typeof DOMTokenList !== "undefined") {
+ var DOMTokenListPrototype = window.DOMTokenList.prototype;
+
+ if (typeof DOMTokenListPrototype.has === 'undefined') {
+ Object.defineProperty(DOMTokenListPrototype, 'has', {
+ value: function (key) {
+ return this.contains(key);
+ }
+ });
+ }
+}
diff --git a/core/extras/element.js b/core/extras/element.js
index ddddbd038f..d5b742db0f 100644
--- a/core/extras/element.js
+++ b/core/extras/element.js
@@ -7,4 +7,10 @@ if (typeof Element !== "undefined" && !Element.isElement) {
writable: true,
configurable: true
});
+
+ Object.defineProperty(Element.prototype, "nativeSetAttribute", {
+ value: Element.prototype.setAttribute,
+ writable: true,
+ configurable: true
+ });
}
diff --git a/core/media-controller.js b/core/media-controller.js
index f3b4b3d48c..f3fdfd5340 100644
--- a/core/media-controller.js
+++ b/core/media-controller.js
@@ -616,9 +616,12 @@ var MediaController = exports.MediaController = Target.specialize(/** @lends Med
}
}, {
-
blueprintModuleId:require("./core")._blueprintModuleIdDescriptor,
- blueprint:require("./core")._blueprintDescriptor
+ blueprint:require("./core")._blueprintDescriptor,
+
+ objectDescriptorModuleId:require("./core")._objectDescriptorModuleIdDescriptor,
+
+ objectDescriptor:require("./core")._objectDescriptorDescriptor
});
diff --git a/core/media-controller.meta b/core/media-controller.meta
index b41c363450..c31dfd6058 100644
--- a/core/media-controller.meta
+++ b/core/media-controller.meta
@@ -1,9 +1,9 @@
{
"mediaController_status": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "status",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -12,10 +12,10 @@
},
"mediaController_STOPPED": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "STOPPED",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -24,10 +24,10 @@
},
"mediaController_PLAYING": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "PLAYING",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -36,10 +36,10 @@
},
"mediaController_PAUSED": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "PAUSED",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -48,10 +48,10 @@
},
"mediaController_EMPTY": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "EMPTY",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -60,10 +60,10 @@
},
"mediaController_mediaController": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "mediaController",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "object",
@@ -72,10 +72,10 @@
},
"mediaController_position": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "position",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -84,10 +84,10 @@
},
"mediaController_duration": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "duration",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -96,10 +96,10 @@
},
"mediaController_autoplay": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "autoplay",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -108,10 +108,10 @@
},
"mediaController_playbackRate": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "playbackRate",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -120,10 +120,10 @@
},
"mediaController_currentTime": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "currentTime",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -132,10 +132,10 @@
},
"mediaController_volume": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "volume",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "number",
@@ -144,10 +144,10 @@
},
"mediaController_mute": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "mute",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -156,14 +156,14 @@
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-object-descriptor",
"values": {
"name": "MediaController",
"exportName": "MediaController",
"module": {
"%": "core/media-controller"
},
- "blueprintModule": {
+ "objectDescriptorModule": {
"%": "core/media-controller.meta"
},
"prototypeName": "MediaController",
diff --git a/core/meta/association-blueprint.meta b/core/meta/association-blueprint.meta
index d814674918..3e769ef46d 100644
--- a/core/meta/association-blueprint.meta
+++ b/core/meta/association-blueprint.meta
@@ -14,16 +14,7 @@
}
},
"property_blueprint_reference": {
- "prototype": "core/meta/blueprint-reference",
- "values": {
- "valueReference": {
- "blueprintName": "PropertyBlueprint",
- "prototypeName": "PropertyBlueprint",
- "blueprintModule": {
- "%": "core/meta/property-blueprint.meta"
- }
- }
- }
+ "object": "core/meta/property-blueprint.meta"
},
"root": {
"prototype": "core/meta/module-blueprint",
diff --git a/core/meta/derived-descriptor.mjson b/core/meta/derived-descriptor.mjson
index da2b8c6627..1d37966f7c 100644
--- a/core/meta/derived-descriptor.mjson
+++ b/core/meta/derived-descriptor.mjson
@@ -48,16 +48,7 @@
}
},
"property_descriptor_reference": {
- "prototype": "core/meta/object-descriptor-reference",
- "values": {
- "valueReference": {
- "objectDescriptorName": "PropertyDescriptor",
- "prototypeName": "PropertyDescriptor",
- "objectDescriptorModule": {
- "%": "core/meta/property-descriptor.mjson"
- }
- }
- }
+ "object": "core/meta/property-descriptor.mjson"
},
"root": {
"prototype": "core/meta/module-object-descriptor",
diff --git a/core/meta/event-descriptor.mjson b/core/meta/event-descriptor.mjson
index f1b84c40d8..b5bd53b6f5 100644
--- a/core/meta/event-descriptor.mjson
+++ b/core/meta/event-descriptor.mjson
@@ -1,15 +1,6 @@
{
"owner_reference": {
- "prototype": "core/meta/object-descriptor-reference",
- "values": {
- "valueReference": {
- "objectDescriptorName": "ObjectDescriptor",
- "prototypeName": "ObjectDescriptor",
- "objectDescriptorModule": {
- "%": "core/meta/object-descriptor.mjson"
- }
- }
- }
+ "object": "core/meta/object-descriptor.mjson"
},
"name": {
"prototype": "core/meta/property-descriptor",
diff --git a/core/meta/model.js b/core/meta/model.js
index 674fbf5585..6ac88f0cbc 100644
--- a/core/meta/model.js
+++ b/core/meta/model.js
@@ -370,7 +370,6 @@ var Model = exports.Model = Montage.specialize( /** @lends Model.prototype # */
if (_group === null) {
_group = new ModelGroup();
_group.name = application ? application.name : "";
- //console.log("Default ModelGroup name is ", _group.name);
}
return _group;
}
diff --git a/core/meta/model.mjson b/core/meta/model.mjson
index 22bce97d12..ccc387953f 100644
--- a/core/meta/model.mjson
+++ b/core/meta/model.mjson
@@ -1,15 +1,6 @@
{
"object_descriptor_reference": {
- "prototype": "core/meta/object-descriptor-reference",
- "values": {
- "valueReference": {
- "objectDescriptorName": "ObjectDescriptor",
- "prototypeName": "ObjectDescriptor",
- "objectDescriptorModule": {
- "%": "core/meta/object-descriptor.mjson"
- }
- }
- }
+ "object": "core/meta/object-descriptor"
},
"model_objectDescriptors": {
"prototype": "core/meta/property-descriptor",
diff --git a/core/meta/object-descriptor-reference.mjson b/core/meta/object-descriptor-reference.mjson
index fd416f4f12..8d12976782 100644
--- a/core/meta/object-descriptor-reference.mjson
+++ b/core/meta/object-descriptor-reference.mjson
@@ -23,7 +23,7 @@
"@": "value_target_object_descriptor"
}
],
- "propertyBlueprintGroups": {
+ "propertyDescriptorGroups": {
"associations": [
{
"@": "value_target_object_descriptor"
diff --git a/core/meta/object-descriptor.js b/core/meta/object-descriptor.js
index a6219d5967..d8099b6635 100644
--- a/core/meta/object-descriptor.js
+++ b/core/meta/object-descriptor.js
@@ -2,7 +2,6 @@ var Montage = require("../core").Montage,
DerivedDescriptor = require("./derived-descriptor").DerivedDescriptor,
EventDescriptor = require("./event-descriptor").EventDescriptor,
ModelModule = require("./model"),
- ObjectDescriptorReference = require("./object-descriptor-reference").ObjectDescriptorReference,
Promise = require("../promise").Promise,
PropertyDescriptor = require("./property-descriptor").PropertyDescriptor,
PropertyValidationRule = require("./validation-rule").PropertyValidationRule,
@@ -59,8 +58,8 @@ var ObjectDescriptor = exports.ObjectDescriptor = Montage.specialize( /** @lends
if (this.objectDescriptorInstanceModule) {
serializer.setProperty("objectDescriptorModule", this.objectDescriptorInstanceModule);
}
- if (this._parentReference) {
- serializer.setProperty("parent", this._parentReference);
+ if (this._parent) {
+ serializer.setProperty("parent", this._parent);
}
this._setPropertyWithDefaults(serializer, "customPrototype", this.customPrototype);
@@ -85,14 +84,20 @@ var ObjectDescriptor = exports.ObjectDescriptor = Montage.specialize( /** @lends
deserializeSelf: {
value:function (deserializer) {
- var value, model;
+ var value, model, parentReference;
this._name = deserializer.getProperty("name");
value = deserializer.getProperty("model") || deserializer.getProperty("binder");
if (value) {
this._model = value;
}
this.objectDescriptorInstanceModule = deserializer.getProperty("objectDescriptorModule") || deserializer.getProperty("blueprintModule");
- this._parentReference = deserializer.getProperty("parent");
+ parentReference = deserializer.getProperty("parent");
+ if (parentReference && parentReference.promise && parentReference.valueFromReference) {
+ deprecate.deprecationWarningOnce("parent reference via ObjectDescriptorReference", "direct reference with object syntax");
+ this._parentReference = parentReference;
+ } else {
+ this._parent = parentReference;
+ }
this.customPrototype = this._getPropertyWithDefaults(deserializer, "customPrototype");
//
@@ -317,7 +322,7 @@ var ObjectDescriptor = exports.ObjectDescriptor = Montage.specialize( /** @lends
/**
* Blueprint parent
- * @returns {?ObjectDescriptorReference}
+ * @type {?ObjectDescriptor}
*/
parent: {
serializable: false,
@@ -325,13 +330,7 @@ var ObjectDescriptor = exports.ObjectDescriptor = Montage.specialize( /** @lends
return this._parent;
},
set: function (objectDescriptor) {
- if (objectDescriptor) {
- this._parentReference = new ObjectDescriptorReference().initWithValue(objectDescriptor);
- this._parent = objectDescriptor;
- } else {
- this._parentReference = null;
- this._parent = null;
- }
+ this._parent = objectDescriptor;
}
},
@@ -573,7 +572,7 @@ var ObjectDescriptor = exports.ObjectDescriptor = Montage.specialize( /** @lends
name;
for (name in this._propertyDescriptorGroups) {
if (this._propertyDescriptorGroups.hasOwnProperty(name)) {
- groups.push(name);
+ groups.push(name);
}
}
if (this.parent) {
@@ -782,7 +781,7 @@ var ObjectDescriptor = exports.ObjectDescriptor = Montage.specialize( /** @lends
}
this._eventPropertyDescriptorsTable[name] = eventDescriptor;
}
-
+
// TODO: Come back after creating event property descriptor
if (eventDescriptor === exports.UnknownEventDescriptor) {
eventDescriptor = null;
@@ -812,7 +811,7 @@ var ObjectDescriptor = exports.ObjectDescriptor = Montage.specialize( /** @lends
propertyValidationRules = [];
for (propertyName in this._propertyValidationRules) {
if (this._propertyValidationRules.hasOwnProperty(propertyName)) {
- propertyValidationRules.push(this._propertyValidationRules[propertyName]);
+ propertyValidationRules.push(this._propertyValidationRules[propertyName]);
}
}
if (this.parent) {
@@ -886,7 +885,7 @@ var ObjectDescriptor = exports.ObjectDescriptor = Montage.specialize( /** @lends
rule = this._propertyValidationRules[name];
if (rule.evaluateRule(objectInstance)) {
messages.push(rule.messageKey);
- }
+ }
}
}
return messages;
diff --git a/core/meta/object-descriptor.mjson b/core/meta/object-descriptor.mjson
index b9c9f902a5..addc79bd7b 100644
--- a/core/meta/object-descriptor.mjson
+++ b/core/meta/object-descriptor.mjson
@@ -1,39 +1,12 @@
{
"model_reference": {
- "prototype": "core/meta/model-reference",
- "values": {
- "valueReference": {
- "objectDescriptorName": "Model",
- "prototypeName": "Model",
- "objectDescriptorModule": {
- "%": "core/meta/model.mjson"
- }
- }
- }
+ "object": "core/meta/model.mjson"
},
"property_descriptor_reference": {
- "prototype": "core/meta/object-descriptor-reference",
- "values": {
- "valueReference": {
- "objectDescriptorName": "PropertyDescriptor",
- "prototypeName": "PropertyDescriptor",
- "objectDescriptorModule": {
- "%": "core/meta/property-descriptor.mjson"
- }
- }
- }
+ "object": "core/meta/property-descriptor.mjson"
},
"property_validation_rules_reference": {
- "prototype": "core/meta/object-descriptor-reference",
- "values": {
- "valueReference": {
- "objectDescriptorName": "PropertyValidationRule",
- "prototypeName": "PropertyValidationRule",
- "objectDescriptorModule": {
- "%": "core/meta/validation-rule.mjson"
- }
- }
- }
+ "object": "core/meta/validation-rule.mjson"
},
"name": {
"prototype": "core/meta/property-descriptor",
diff --git a/core/meta/property-descriptor.js b/core/meta/property-descriptor.js
index ba7152929a..12361d4001 100644
--- a/core/meta/property-descriptor.js
+++ b/core/meta/property-descriptor.js
@@ -1,5 +1,5 @@
var Montage = require("../core").Montage,
- ObjectDescriptorReference = require("./object-descriptor-reference").ObjectDescriptorReference,
+ Promise = require("../promise").Promise,
deprecate = require("../deprecate"),
logger = require("../logger").logger("objectDescriptor");
@@ -321,11 +321,17 @@ exports.PropertyDescriptor = Montage.specialize( /** @lends PropertyDescriptor#
valueDescriptor: {
serializable: false,
get: function () {
- return this._valueDescriptorReference && this._valueDescriptorReference.promise(this.require);
+ // TODO: Needed for backwards compatibility with ObjectDescriptorReference.
+ // Remove eventually, this can become completely sync
+ if (typeof this._valueDescriptorReference.promise === "function") {
+ deprecate.deprecationWarningOnce("valueDescriptor reference via ObjectDescriptorReference", "direct reference via object syntax");
+ return this._valueDescriptorReference.promise(this.require);
+ } else {
+ return Promise.resolve(this._valueDescriptorReference);
+ }
},
set: function (descriptor) {
-
- this._valueDescriptorReference = new ObjectDescriptorReference().initWithValue(descriptor);
+ this._valueDescriptorReference = descriptor;
}
},
diff --git a/core/meta/property-descriptor.mjson b/core/meta/property-descriptor.mjson
index f495717e71..329b506ca0 100644
--- a/core/meta/property-descriptor.mjson
+++ b/core/meta/property-descriptor.mjson
@@ -1,15 +1,6 @@
{
"owner_reference": {
- "prototype": "core/meta/object-descriptor-reference",
- "values": {
- "valueReference": {
- "objectDescriptorName": "ObjectDescriptor",
- "prototypeName": "ObjectDescriptor",
- "objectDescriptorModule": {
- "%": "core/meta/object-descriptor.mjson"
- }
- }
- }
+ "object": "core/meta/object-descriptor.mjson"
},
"property_name": {
"prototype": "core/meta/property-descriptor",
diff --git a/core/meta/validation-rule.mjson b/core/meta/validation-rule.mjson
index eff1297052..26ab1db061 100644
--- a/core/meta/validation-rule.mjson
+++ b/core/meta/validation-rule.mjson
@@ -1,15 +1,6 @@
{
"owner_reference": {
- "prototype": "core/meta/object-descriptor-reference",
- "values": {
- "valueReference": {
- "objectDescriptorName": "ObjectDescriptor",
- "prototypeName": "ObjectDescriptor",
- "objectDescriptorModule": {
- "%": "core/meta/object-descriptor.mjson"
- }
- }
- }
+ "object": "core/meta/object-descriptor.mjson"
},
"validation_rule_object_descriptor_name": {
"prototype": "core/meta/property-descriptor",
diff --git a/core/object-controller.js b/core/object-controller.js
index 9e08b7494e..9347476f85 100644
--- a/core/object-controller.js
+++ b/core/object-controller.js
@@ -53,6 +53,10 @@ exports.ObjectController = Montage.specialize( /** @lends ObjectController# */ {
value: null
},
+ objectDescriptorModuleId:require("./core")._objectDescriptorModuleIdDescriptor,
+
+ objectDescriptor:require("./core")._objectDescriptorDescriptor,
+
blueprintModuleId:require("./core")._blueprintModuleIdDescriptor,
blueprint:require("./core")._blueprintDescriptor
diff --git a/core/promise-controller.js b/core/promise-controller.js
index d819f792fa..ba92d85a79 100644
--- a/core/promise-controller.js
+++ b/core/promise-controller.js
@@ -166,6 +166,10 @@ exports.PromiseController = Montage.specialize( {
}, /** @lends PromiseController. */ {
+ objectDescriptorModuleId:require("./core")._objectDescriptorModuleIdDescriptor,
+
+ objectDescriptor:require("./core")._objectDescriptorDescriptor,
+
blueprintModuleId:require("./core")._blueprintModuleIdDescriptor,
blueprint:require("./core")._blueprintDescriptor
diff --git a/core/promise-controller.meta b/core/promise-controller.meta
index c6ac5db5aa..85c015298e 100644
--- a/core/promise-controller.meta
+++ b/core/promise-controller.meta
@@ -1,9 +1,9 @@
{
"promiseController_promise": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "promise",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "object",
@@ -11,10 +11,10 @@
}
},
"promiseController_value": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "value",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "object",
@@ -22,10 +22,10 @@
}
},
"promiseController_error": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "error",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "object",
@@ -33,10 +33,10 @@
}
},
"promiseController_pending": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "pending",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -44,10 +44,10 @@
}
},
"promiseController_fulfilled": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "fulfilled",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -55,10 +55,10 @@
}
},
"promiseController_rejected": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "rejected",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -66,7 +66,7 @@
}
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-object-descriptor",
"values": {
"name": "PromiseController",
"customPrototype": false,
@@ -113,7 +113,7 @@
]
},
"propertyValidationRules": {},
- "blueprintModule": {
+ "objectDescriptorModule": {
"%": "core/promise-controller.meta"
},
"exportName": "PromiseController",
diff --git a/core/radio-button-controller.js b/core/radio-button-controller.js
index 6daa3be32d..fa2dc09a75 100644
--- a/core/radio-button-controller.js
+++ b/core/radio-button-controller.js
@@ -142,6 +142,10 @@ exports.RadioButtonController = Montage.specialize(/** @lends RadioButtonControl
}, /** @lends RadioButtonController. */ {
+ objectDescriptorModuleId:require("./core")._objectDescriptorModuleIdDescriptor,
+
+ objectDescriptor:require("./core")._objectDescriptorDescriptor,
+
blueprintModuleId:require("./core")._blueprintModuleIdDescriptor,
blueprint:require("./core")._blueprintDescriptor
diff --git a/core/radio-button-controller.meta b/core/radio-button-controller.meta
index 7bbe73f29a..618634c639 100644
--- a/core/radio-button-controller.meta
+++ b/core/radio-button-controller.meta
@@ -1,38 +1,38 @@
{
- "blueprint_radio_button_controller_value": {
- "prototype": "core/meta/property-blueprint",
+ "objectDescriptor_radio_button_controller_value": {
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "value",
- "blueprint": { "@": "root" },
+ "objectDescriptor": { "@": "root" },
"valueType": "object",
"helpKey": ""
}
},
- "blueprint_radio_button_controller_contentController": {
- "prototype": "core/meta/property-blueprint",
+ "objectDescriptor_radio_button_controller_contentController": {
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "contentController",
- "blueprint": { "@": "root" },
+ "objectDescriptor": { "@": "root" },
"valueType": "object",
"helpKey": ""
}
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-object-descriptor",
"values": {
"name": "RadioButtonController",
"propertyDescriptors": [
- { "@": "blueprint_radio_button_controller_value" },
- { "@": "blueprint_radio_button_controller_contentController" }
+ { "@": "objectDescriptor_radio_button_controller_value" },
+ { "@": "objectDescriptor_radio_button_controller_contentController" }
],
"propertyDescriptorGroups": {
"Selection": [
- { "@": "blueprint_radio_button_controller_value" },
- { "@": "blueprint_radio_button_controller_contentController" }
+ { "@": "objectDescriptor_radio_button_controller_value" },
+ { "@": "objectDescriptor_radio_button_controller_contentController" }
]
},
"propertyValidationRules": {},
- "blueprintModule": { "%": "core/radio-button-controller.meta" },
+ "objectDescriptorModule": { "%": "core/radio-button-controller.meta" },
"exportName": "RadioButtonController",
"module": { "%": "core/radio-button-controller" }
}
diff --git a/core/range-controller.js b/core/range-controller.js
index e764ff7253..d1eca2c6fc 100644
--- a/core/range-controller.js
+++ b/core/range-controller.js
@@ -840,7 +840,11 @@ var RangeController = exports.RangeController = Montage.specialize( /** @lends R
}
}
-}, /** @lends RangeController */ {
+}, /** @lends RangeController. */ {
+
+ objectDescriptorModuleId:require("./core")._objectDescriptorModuleIdDescriptor,
+
+ objectDescriptor:require("./core")._objectDescriptorDescriptor,
blueprintModuleId:require("./core")._blueprintModuleIdDescriptor,
diff --git a/core/range-controller.meta b/core/range-controller.meta
index a77315849d..2e7fda17d7 100644
--- a/core/range-controller.meta
+++ b/core/range-controller.meta
@@ -1,9 +1,9 @@
{
"rangeController_content": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "content",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"cardinality": -1,
@@ -12,10 +12,10 @@
}
},
"rangeController_organizedContent": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "organizedContent",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"cardinality": -1,
@@ -24,10 +24,10 @@
}
},
"rangeController_sortPath": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "sortPath",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "string",
@@ -35,10 +35,10 @@
}
},
"rangeController_reversed": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "reversed",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -46,10 +46,10 @@
}
},
"rangeController_filterPath": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "filterPath",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "string",
@@ -57,10 +57,10 @@
}
},
"rangeController_selectAddedContent": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "selectAddedContent",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -68,10 +68,10 @@
}
},
"rangeController_deselectInvisibleContent": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "deselectInvisibleContent",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -79,10 +79,10 @@
}
},
"rangeController_clearSelectionOnOrderChange": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "clearSelectionOnOrderChange",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -90,10 +90,10 @@
}
},
"rangeController_avoidsEmptySelection": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "avoidsEmptySelection",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -101,10 +101,10 @@
}
},
"rangeController_multiSelect": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "multiSelect",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -112,7 +112,7 @@
}
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-object-descriptor",
"values": {
"name": "RangeController",
"customPrototype": false,
@@ -183,7 +183,7 @@
]
},
"propertyValidationRules": {},
- "blueprintModule": {
+ "objectDescriptorModule": {
"%": "core/range-controller.meta"
},
"exportName": "RangeController",
diff --git a/core/serialization/bindings.js b/core/serialization/bindings.js
index dca146577a..c8cd6e68f7 100644
--- a/core/serialization/bindings.js
+++ b/core/serialization/bindings.js
@@ -87,8 +87,14 @@ var deserializeObjectBindings = exports.deserializeObjectBindings = function (de
descriptor = bindings[targetPath];
if (typeof descriptor !== "object") {
- throw new Error("Binding descriptor must be an object, not " + typeof descriptor);
- // TODO isolate the source document and produce a more useful error
+ if (targetPath.indexOf('.') === -1) {
+ throw new Error("Binding descriptor must be an object, not " + typeof descriptor);
+ // TODO isolate the source document and produce a more useful error
+ } else {
+ descriptor = {
+ "=" : "" + descriptor
+ };
+ }
}
if (ONE_ASSIGNMENT in descriptor) {
diff --git a/core/serialization/deserializer/montage-deserializer.js b/core/serialization/deserializer/montage-deserializer.js
index 5d1f8319cb..836863a922 100644
--- a/core/serialization/deserializer/montage-deserializer.js
+++ b/core/serialization/deserializer/montage-deserializer.js
@@ -1,6 +1,7 @@
var Montage = require("../../core").Montage,
MontageInterpreter = require("./montage-interpreter").MontageInterpreter,
MontageReviver = require("./montage-reviver").MontageReviver,
+ Map = require("collections/map").Map,
deprecate = require("../../deprecate");
var MontageDeserializer = exports.MontageDeserializer = Montage.specialize({
@@ -26,18 +27,23 @@ var MontageDeserializer = exports.MontageDeserializer = Montage.specialize({
},
init: {
- value: function (serializationString, _require, objectRequires) {
+ value: function (serializationString, _require, objectRequires, locationId, moduleContexts) {
this._serializationString = serializationString;
- this._interpreter = new MontageInterpreter().init(_require, objectRequires);
+ moduleContexts = moduleContexts || new Map();
+ this._interpreter = new MontageInterpreter().init(_require,
+ new MontageReviver().init(_require, objectRequires, locationId, moduleContexts));
return this;
}
},
initWithObject: {
- value: function (serialization, _require, objectRequires) {
+ value: function (serialization, _require, objectRequires, locationId, moduleContexts) {
this._serializationString = JSON.stringify(serialization);
- this._interpreter = new MontageInterpreter().init(_require, objectRequires);
+ moduleContexts = moduleContexts || new Map();
+ this._interpreter = new MontageInterpreter().init(_require,
+ new MontageReviver().init(_require, objectRequires, locationId, moduleContexts));
+
return this;
}
},
diff --git a/core/serialization/deserializer/montage-interpreter.js b/core/serialization/deserializer/montage-interpreter.js
index de214a51e5..82018efcc4 100644
--- a/core/serialization/deserializer/montage-interpreter.js
+++ b/core/serialization/deserializer/montage-interpreter.js
@@ -10,13 +10,12 @@ var MontageInterpreter = Montage.specialize({
_reviver: {value: null},
init: {
- value: function (_require, objectRequires) {
+ value: function (_require, reviver) {
if (typeof _require !== "function") {
throw new Error("Function 'require' missing.");
}
- this._reviver = new MontageReviver()
- .init(_require, objectRequires);
+ this._reviver = reviver;
this._require = _require;
return this;
@@ -248,12 +247,14 @@ var MontageContext = Montage.specialize({
if (values.hasOwnProperty(key)) {
value = values[key];
- if (typeof value === "object" && value &&
+ if ((typeof value === "object" && value &&
Object.keys(value).length === 1 &&
- (ONE_WAY in value || TWO_WAY in value || ONE_ASSIGNMENT in value)) {
+ (ONE_WAY in value || TWO_WAY in value || ONE_ASSIGNMENT in value)) ||
+ key.indexOf('.') > -1
+ ) {
bindings[key] = value;
delete values[key];
- }
+ }
}
}
diff --git a/core/serialization/deserializer/montage-reviver.js b/core/serialization/deserializer/montage-reviver.js
index c3e459a8a1..2f0d11c1c8 100644
--- a/core/serialization/deserializer/montage-reviver.js
+++ b/core/serialization/deserializer/montage-reviver.js
@@ -1,4 +1,4 @@
-/* global console */
+/*global console, Proxy */
var Montage = require("../../core").Montage,
ValuesDeserializer = require("./values-deserializer").ValuesDeserializer,
SelfDeserializer = require("./self-deserializer").SelfDeserializer,
@@ -7,12 +7,17 @@ var Montage = require("../../core").Montage,
Alias = require("../alias").Alias, Bindings = require("../bindings"),
Promise = require("../../promise").Promise,
deprecate = require("../../deprecate"),
+ camelCaseConverter = require('../../converter/camel-case-converter').singleton,
+ kebabCaseConverter = require('../../converter/kebab-case-converter').singleton,
ONE_ASSIGNMENT = "=",
ONE_WAY = "<-",
TWO_WAY = "<->";
require("../../shim/string");
+var PROXY_ELEMENT_MAP = new WeakMap();
+var DATA_ATTRIBUTES_MAP = new Map();
+
var ModuleLoader = Montage.specialize( {
_require: {value: null},
_objectRequires: {value: null},
@@ -93,12 +98,18 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
* @param {Object} objectRequires A dictionary indexed by object label with
* the require object to use for a specific object of the
* serialization.
+ * @param {?Map} moduleContexts A map indexed by module ID with the
+ * MontageContext to use for a specific external object
+ * reference. Used to prevent circular references from creating
+ * an infinite loop.
*/
init: {
- value: function (_require, objectRequires) {
+ value: function (_require, objectRequires, locationId, moduleContexts) {
this.moduleLoader = new ModuleLoader()
.init(_require, objectRequires);
this._require = _require;
+ this._locationId = locationId;
+ this._moduleContexts = moduleContexts;
return this;
}
},
@@ -139,6 +150,158 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
}
},
+ setProxyForDatasetOnElement: {
+ value: function (element, montageObjectDesc) {
+ var originalDataset = element.dataset;
+
+ if (Object.getPrototypeOf(originalDataset) !== null) {
+ var datasetAttributes = Object.keys(originalDataset),
+ targetObject = Object.create(null), self = this,
+ datasetAttribute, propertyNames;
+
+ if (Proxy.prototype) { // The native Proxy has no prototype property.
+ // Workaround for Proxy polyfill https://github.com/GoogleChrome/proxy-polyfill
+ // the properties of a proxy must be known at creation time.
+ // TODO: remove when we drop the support of IE11.
+ if (montageObjectDesc.values) {
+ propertyNames = Object.keys(montageObjectDesc.values);
+ } else { // deprecated
+ propertyNames = Object.keys(montageObjectDesc.properties)
+ .concat(Object.keys(montageObjectDesc.bindings));
+ }
+
+ datasetAttributes = datasetAttributes.concat(
+ propertyNames.filter(function (propertyName) {
+ return propertyName.startsWith("dataset.");
+ })
+ );
+
+ for (var i = 0, length = datasetAttributes.length; i < length; i++) {
+ datasetAttribute = datasetAttributes[i];
+ if (originalDataset[datasetAttribute]) {
+ targetObject[datasetAttribute] =
+ originalDataset[datasetAttribute];
+ } else {
+ targetObject[datasetAttribute.replace(/^dataset\./, '')] = void 0;
+ }
+ }
+ }
+
+ Object.defineProperty(element, "dataset", {
+ value: new Proxy(targetObject, {
+ set: function (target, propertyName, value) {
+ target[propertyName] = value;
+ originalDataset[propertyName] = value;
+ element.nativeSetAttribute(
+ DATA_ATTRIBUTES_MAP.get(propertyName) ||
+ (DATA_ATTRIBUTES_MAP.set(
+ propertyName,
+ 'data-' +
+ kebabCaseConverter.convert(propertyName)
+ )).get(propertyName),
+ value
+ );
+ return true;
+ },
+ get: function (target, propertyName) {
+ return target[propertyName];
+ }
+ })
+ });
+ }
+ }
+ },
+
+ setProxyOnElement: {
+ value: function (element, montageObjectDesc) {
+ if (!PROXY_ELEMENT_MAP.has(element)) {
+ var targetObject = Object.create(null);
+
+ if (Proxy.prototype) { // The native Proxy has no prototype property.
+ // Workaround for Proxy polyfill https://github.com/GoogleChrome/proxy-polyfill
+ // the properties of a proxy must be known at creation time.
+ // TODO: remove when we drop the support of IE11.
+ var propertyNames, propertyName;
+
+ for (propertyName in element) {
+ if (element.hasOwnProperty(propertyName)) {
+ targetObject[propertyName] = void 0;
+ }
+ }
+
+ if (montageObjectDesc.values) {
+ propertyNames = Object.keys(montageObjectDesc.values);
+ } else { // deprecated
+ propertyNames = Object.keys(montageObjectDesc.properties)
+ .concat(Object.keys(montageObjectDesc.bindings));
+ }
+
+ for (var i = 0, length = propertyNames.length; i < length; i++) {
+ propertyName = propertyNames[i];
+ if (!(propertyName in element) && propertyName.indexOf('.') === -1) {
+ targetObject[propertyName] = void 0;
+ }
+ }
+ }
+
+ PROXY_ELEMENT_MAP.set(element, new Proxy(targetObject, {
+ set: function (target, propertyName, value) {
+ if (!(propertyName in Object.getPrototypeOf(element))) {
+ if (Object.getOwnPropertyDescriptor(element, propertyName) === void 0) {
+ Object.defineProperty(element, propertyName, {
+ set: function (value) {
+ target[propertyName] = value;
+
+ if (value === null || value === void 0) {
+ element.removeAttribute(propertyName);
+ } else {
+ element.nativeSetAttribute(propertyName, value);
+ }
+ },
+ get: function () {
+ return target[propertyName];
+ }
+ });
+ }
+ }
+
+ if (target[propertyName] !== value) {
+ element[propertyName] = value;
+ }
+
+ return true;
+ },
+ get: function (target, propertyName) {
+ return target[propertyName] || element[propertyName];
+ }
+ }));
+ }
+
+ return PROXY_ELEMENT_MAP.get(element);
+ }
+ },
+
+ wrapSetAttributeForElement: {
+ value: function (element) {
+ if (element.setAttribute === element.nativeSetAttribute) {
+ var proxyElement = PROXY_ELEMENT_MAP.get(element),
+ self = this;
+
+ element.setAttribute = function (key, value) {
+ var propertyName;
+ if (key.startsWith('data-')) {
+ propertyName = camelCaseConverter.convert(key.replace('data-', ''));
+ proxyElement.dataset[propertyName] = value;
+ } else {
+ propertyName = camelCaseConverter.convert(key);
+ proxyElement[propertyName] = value;
+ }
+ element.nativeSetAttribute(key, value);
+ };
+ }
+ }
+ },
+
reviveRootObject: {
value: function (value, context, label) {
var error,
@@ -170,19 +333,29 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
return object;
}
- var revivedValue = this.reviveValue(value.value, context, label);
+ var revivedValue = this.reviveValue(value.value, context, label),
+ valueType = this.getTypeOf(value.value);
- if (this.getTypeOf(value.value) === "Element") {
+ if (valueType === "Element") {
if (!Promise.is(revivedValue)) {
- var montageObjectDesc = this.reviveObjectLiteral(value, context);
- context.setBindingsToDeserialize(revivedValue, montageObjectDesc);
+ var proxyElement = this.setProxyOnElement(revivedValue, value);
+ this.setProxyForDatasetOnElement(revivedValue, value);
+ this.wrapSetAttributeForElement(revivedValue);
+ context.setBindingsToDeserialize(proxyElement, value);
this.deserializeMontageObjectValues(
- revivedValue,
- montageObjectDesc.values || montageObjectDesc.properties, //deprecated
+ proxyElement,
+ value.values || value.properties, //deprecated
context
);
- context.setUnitsToDeserialize(revivedValue, montageObjectDesc, MontageReviver._unitNames);
}
+ } else if (valueType === "object") {
+ context.setBindingsToDeserialize(revivedValue, value);
+ this.deserializeMontageObjectValues(
+ revivedValue,
+ value.values || value.properties, //deprecated
+ context
+ );
+ context.setUnitsToDeserialize(revivedValue, value, MontageReviver._unitNames);
}
return revivedValue;
@@ -288,8 +461,8 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
moduleId = value.prototype || value.object,
object;
- if (moduleId && moduleId.endsWith(".mjson")) {
- return this.getMjsonObject(value, module, moduleId)
+ if (moduleId && (moduleId.endsWith(".mjson") || moduleId.endsWith(".meta"))) {
+ return this.getMjsonObject(value, module, moduleId, context)
.then(function (object) {
context.setObjectLabel(object, label);
return self.instantiateMjsonObject(value, object, objectName, context, label);
@@ -303,17 +476,29 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
},
getMjsonObject: {
- value: function (serialization, json, moduleId) {
- var self = this;
- return MontageReviver.getMontageDeserializer().then(function (MontageDeserializer) {
- // TODO: MontageDeserializer needs an API to pass in an object
- // instead of the stringified version of the object
- var deserializer = new MontageDeserializer().init(
- JSON.stringify(json),
- MontageDeserializer.getModuleRequire(self._require, moduleId)
- );
- return deserializer.deserializeObject();
- }).then(function (object) {
+ value: function (serialization, json, moduleId, context) {
+ var self = this,
+ mjsonObjectPromise;
+ if (moduleId && this._moduleContexts.has(moduleId)) {
+ // We have a circular reference. If we wanted to forbid circular
+ // references this is where we would throw an error.
+ mjsonObjectPromise = Promise.resolve(this._moduleContexts.get(moduleId)._objects.root);
+ } else {
+ if (this._locationId && !this._moduleContexts.has(this._locationId)) {
+ this._moduleContexts.set(this._locationId, context);
+ }
+ mjsonObjectPromise = MontageReviver.getMontageDeserializer().then(function (MontageDeserializer) {
+ var deserializer = new MontageDeserializer().initWithObject(
+ json,
+ MontageDeserializer.getModuleRequire(self._require, moduleId),
+ void 0,
+ moduleId,
+ self._moduleContexts
+ );
+ return deserializer.deserializeObject();
+ });
+ }
+ return mjsonObjectPromise.then(function (object) {
if ("prototype" in serialization) {
return Object.create(object);
} else {
@@ -645,6 +830,11 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
for (var propertyName in value) {
if (value.hasOwnProperty(propertyName)) {
+ if (value[propertyName] === value) {
+ // catch object property that point to its parent
+ return value;
+ }
+
item = this.reviveValue(value[propertyName], context);
if (Promise.is(item)) {
@@ -881,6 +1071,11 @@ var MontageReviver = exports.MontageReviver = Montage.specialize(/** @lends Mont
});
+MontageReviver.findProxyForElement = function (element) {
+ return PROXY_ELEMENT_MAP.get(element);
+};
+
if (typeof exports !== "undefined") {
+
exports.MontageReviver = MontageReviver;
}
diff --git a/core/template.js b/core/template.js
index 859ec5bd59..8514053056 100644
--- a/core/template.js
+++ b/core/template.js
@@ -304,19 +304,19 @@ var Template = Montage.specialize( /** @lends Template# */ {
return this._instantiateObjects(templateObjects, fragment)
.then(function (objects) {
- var resources;
+ var resources = self.getResources();
- part.objects = objects;
- self._invokeDelegates(part, instances);
- part.stopActingAsTopComponent();
-
- resources = self.getResources();
if (!resources.resourcesLoaded() && resources.hasResources()) {
// Start preloading the resources as soon as possible, no
// need to wait for them as the draw cycle will take care
// of that when loading the stylesheets into the document.
resources.loadResources(targetDocument);
}
+
+ part.objects = objects;
+ self._invokeDelegates(part, instances);
+ part.stopActingAsTopComponent();
+
return part;
});
}
diff --git a/core/tree-controller.meta b/core/tree-controller.meta
index b2a5903da1..d81d0f9fa0 100644
--- a/core/tree-controller.meta
+++ b/core/tree-controller.meta
@@ -1,9 +1,9 @@
{
"treeController_content": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "content",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"cardinality": -1,
@@ -12,10 +12,10 @@
}
},
"treeController_childrenPath": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "childrenPath",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "string",
@@ -23,10 +23,10 @@
}
},
"treeController_initiallyExpanded": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "initiallyExpanded",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -34,10 +34,10 @@
}
},
"treeController_noneExpanded": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "noneExpanded",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -45,10 +45,10 @@
}
},
"treeController_allExpanded": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "allExpanded",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "boolean",
@@ -56,10 +56,10 @@
}
},
"treeController_root": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "root",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"valueType": "object",
@@ -69,7 +69,7 @@
}
},
"root": {
- "prototype": "core/meta/module-blueprint",
+ "prototype": "core/meta/module-object-descriptor",
"values": {
"name": "TreeController",
"customPrototype": false,
@@ -116,7 +116,7 @@
]
},
"propertyValidationRules": {},
- "blueprintModule": {
+ "objectDescriptorModule": {
"%": "core/tree-controller.meta"
},
"exportName": "TreeController",
@@ -126,10 +126,10 @@
}
},
"treeControllerNode_content": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "content",
- "blueprint": {
+ "objectDescriptor": {
"@": "root"
},
"cardinality": -1,
@@ -138,10 +138,10 @@
}
},
"treeControllerNode_expanded": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "expanded",
- "blueprint": {
+ "objectDescriptor": {
"@": "treeControllerNode"
},
"valueType": "boolean",
@@ -149,10 +149,10 @@
}
},
"treeControllerNode_depth": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "depth",
- "blueprint": {
+ "objectDescriptor": {
"@": "treeControllerNode"
},
"valueType": "number",
@@ -160,10 +160,10 @@
}
},
"treeControllerNode_index": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "index",
- "blueprint": {
+ "objectDescriptor": {
"@": "treeControllerNode"
},
"valueType": "number",
@@ -171,10 +171,10 @@
}
},
"treeControllerNode_isFinal": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "isFinal",
- "blueprint": {
+ "objectDescriptor": {
"@": "treeControllerNode"
},
"valueType": "boolean",
@@ -182,10 +182,10 @@
}
},
"treeControllerNode_parent": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "parent",
- "blueprint": {
+ "objectDescriptor": {
"@": "treeControllerNode"
},
"valueType": "object",
@@ -195,10 +195,10 @@
}
},
"treeControllerNode_children": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "children",
- "blueprint": {
+ "objectDescriptor": {
"@": "treeControllerNode"
},
"cardinality": -1,
@@ -209,10 +209,10 @@
}
},
"treeControllerNode_junctions": {
- "prototype": "core/meta/property-blueprint",
+ "prototype": "core/meta/property-descriptor",
"values": {
"name": "junctions",
- "blueprint": {
+ "objectDescriptor": {
"@": "treeControllerNode"
},
"valueType": "object",
@@ -220,10 +220,10 @@
}
},
"treeControllerNode": {
- "prototype": "core/meta/blueprint",
+ "prototype": "core/meta/object-descriptor",
"values": {
"name": "TreeControllerNode",
- "blueprintModuleId": "core/tree-controller.meta",
+ "objectDescriptorModuleId": "core/tree-controller.meta",
"prototypeName": "TreeControllerNode",
"customPrototype": false,
"propertyDescriptors": [
diff --git a/core/websocket.js b/core/websocket.js
index 7e3c652ec1..ba5585d7a0 100644
--- a/core/websocket.js
+++ b/core/websocket.js
@@ -22,7 +22,6 @@ exports.WebSocket = Target.specialize({
this._protocols = protocols;
this._messageQueue = [];
this._webSocket = null;
- this._isMessagePending = false;
this._isReconnecting = false;
this._connect();
return this;
@@ -41,47 +40,48 @@ exports.WebSocket = Target.specialize({
_webSocket: {
value: undefined
},
- _isMessagePending: {
- value: undefined
- },
reconnectionInterval: {
value: 100
},
+
_connect: {
value: function () {
- this._webSocket = new _WebSocket(this._url,this._protocols);
- this._webSocket.addEventListener("error", this, false);
- this._webSocket.addEventListener("open", this, false);
+ this._webSocket = new _WebSocket(this._url, this._protocols);
+ this._webSocket.addEventListener("error", this, false);
+ this._webSocket.addEventListener("open", this, false);
}
},
+
send: {
value: function send(data) {
this._messageQueue.push(data);
this._sendNextMessage();
}
},
+
_sendNextMessage: {
value: function () {
- if (!this._isMessagePending && this._messageQueue.length) {
- if (this._webSocket) {
- this._isMessagePending = true;
- if ((this._webSocket.readyState !== exports.WebSocket.CLOSING) && (this._webSocket.readyState !== exports.WebSocket.CLOSED)) {
+ if (this._messageQueue.length) {
+ switch (this.readyState) {
+ case WebSocket.CONNECTING:
+ break;
+ case WebSocket.CLOSING:
+ case WebSocket.CLOSED:
+ this._reconnect();
+ break;
+ case WebSocket.OPEN:
try {
this._webSocket.send(this._messageQueue[0]);
+ this._messageQueue.shift();
} catch (e) {
- this._isMessagePending = false;
this._reconnect();
}
- } else {
- this._isMessagePending = false;
- this._reconnect();
- }
- } else {
- this._reconnect();
+ break;
}
}
}
},
+
_reconnect: {
value: function () {
var self;
@@ -90,7 +90,6 @@ exports.WebSocket = Target.specialize({
if (!this._isReconnecting) {
self = this;
this._webSocket = null;
- this._isMessagePending = false;
this._isReconnecting = true;
setTimeout(function () {
self._connect();
@@ -117,8 +116,6 @@ exports.WebSocket = Target.specialize({
this._sendNextMessage();
break;
case "message":
- this._isMessagePending = false;
- this._messageQueue.shift();
this.dispatchEvent(event);
this._sendNextMessage();
break;
@@ -161,7 +158,7 @@ exports.WebSocket = Target.specialize({
},
readyState: {
get: function () {
- return this._webSocket.readyState;
+ return this._webSocket ? this._webSocket.readyState : WebSocket.CLOSED;
}
},
diff --git a/montage.js b/montage.js
index 92cdd26d41..6ffd8d3392 100644
--- a/montage.js
+++ b/montage.js
@@ -1,4 +1,4 @@
-/* global define, exports, require, process, window, document, bootstrap*/
+/* global define, exports, require, process, window, document, bootstrap, Reflect, customElements*/
(function (root, factory) {
if (typeof bootstrap === 'function') {
// Montage. Register module.
@@ -442,6 +442,212 @@
return platform.loadPackage(dependency, config, packageDescription);
};
+ exports.initMontageCustomElement = function () {
+ if (typeof window.customElements === 'undefined' || typeof window.Reflect === 'undefined') {
+ return void 0;
+ }
+
+ function makeCustomElementConstructor(superConstructor) {
+ var constructor = function () {
+ return Reflect.construct(
+ HTMLElement, [], constructor
+ );
+ };
+ Object.setPrototypeOf(
+ constructor.prototype, (superConstructor || HTMLElement).prototype
+ );
+ Object.setPrototypeOf(constructor, superConstructor || HTMLElement);
+ return constructor;
+ }
+
+ var MontageElement = makeCustomElementConstructor();
+
+ function defineMontageElement(name, options) {
+ if (!customElements.get(name)) {
+ var customElementConstructor = makeCustomElementConstructor(MontageElement);
+ customElementConstructor.componentConstructor = options.constructor;
+ customElementConstructor.observedAttributes = options.observedAttributes;
+ customElements.define(name, customElementConstructor);
+ }
+ }
+
+ MontageElement.pendingCustomElements = new Map();
+
+ MontageElement.define = function (name, constructor, options) {
+ if (options && typeof options === 'object') {
+ options.constructor = constructor;
+ } else {
+ options = { constructor: constructor };
+ }
+
+ if (this.require) {
+ defineMontageElement(name, options);
+ } else {
+ this.pendingCustomElements.set(name, options);
+ }
+ };
+
+ MontageElement.ready = function (require, application, reviver) {
+ MontageElement.prototype.findProxyForElement = reviver.findProxyForElement;
+ this.application = application;
+ this.require = require;
+
+ this.pendingCustomElements.forEach(function (constructor, name) {
+ defineMontageElement(name, constructor);
+ });
+
+ this.pendingCustomElements.clear();
+ };
+
+ Object.defineProperties(MontageElement.prototype, {
+
+ require: {
+ get: function () {
+ return MontageElement.require;
+ },
+ configurable: false
+ },
+
+ application: {
+ get: function () {
+ return MontageElement.application;
+ },
+ configurable: false
+ },
+
+ componentConstructor: {
+ get: function () {
+ return this.constructor.componentConstructor;
+ },
+ configurable: false
+ },
+
+ observedAttributes: {
+ get: function () {
+ return this.constructor.observedAttributes;
+ },
+ configurable: false
+ }
+ });
+
+ MontageElement.prototype.connectedCallback = function () {
+ if (!this._instance) {
+ var self = this,
+ component = this.instantiateComponent();
+
+ return this.findParentComponent().then(function (parentComponent) {
+ self._instance = component;
+ parentComponent.addChildComponent(component);
+ component._canDrawOutsideDocument = true;
+ component.needsDraw = true;
+ });
+ }
+ };
+
+ MontageElement.prototype.disconnectedCallback = function () {
+ //TODO
+ };
+
+ MontageElement.prototype.findParentComponent = function () {
+ var eventManager = this.application.eventManager,
+ anElement = this,
+ parentComponent,
+ aParentNode,
+ candidate;
+
+ while ((aParentNode = anElement.parentNode) !== null &&
+ !(candidate = eventManager.eventHandlerForElement(aParentNode))) {
+ anElement = aParentNode;
+ }
+
+ return Promise.resolve(candidate) || this.getRootComponent();
+ };
+
+ MontageElement.prototype.getRootComponent = function () {
+ if (!MontageElement.rootComponentPromise) {
+ MontageElement.rootComponentPromise = this.require.async("montage/ui/component")
+ .then(function (exports) {
+ return exports.__root__;
+ });
+ }
+
+ return MontageElement.rootComponentPromise;
+ };
+
+ MontageElement.prototype.instantiateComponent = function () {
+ var component = new this.componentConstructor();
+ this.bootstrapComponent(component);
+ component.element = document.createElement("div");
+ return component;
+ };
+
+ MontageElement.prototype.bootstrapComponent = function (component) {
+ var shadowRoot = this.attachShadow({ mode: 'open' }),
+ mainEnterDocument = component.enterDocument,
+ mainTemplateDidLoad = component.templateDidLoad,
+ proxyElement = this.findProxyForElement(this);
+
+ if (proxyElement) {
+ var observedAttributes = this.observedAttributes,
+ observedAttribute,
+ self = this,
+ length;
+
+ if (observedAttributes && (length = observedAttributes.length)) {
+ for (var i = 0; i < length; i++) {
+ observedAttribute = observedAttributes[i];
+ component.defineBinding(observedAttribute, {
+ "<->": "" + observedAttribute, source: proxyElement
+ });
+ }
+ }
+ }
+
+ this.application.eventManager.registerTargetForActivation(shadowRoot);
+
+ component.templateDidLoad = function () {
+ var resources = component.getResources();
+
+ if (resources) {
+ self.injectResourcesWithinCustomElement(
+ resources.styles,
+ shadowRoot
+ );
+
+ self.injectResourcesWithinCustomElement(
+ resources.scripts,
+ shadowRoot
+ );
+ }
+
+ this.templateDidLoad = mainTemplateDidLoad;
+
+ if (typeof this.templateDidLoad === "function") {
+ this.templateDidLoad();
+ }
+ };
+
+ component.enterDocument = function (firstTime) {
+ shadowRoot.appendChild(this.element);
+ this.enterDocument = mainEnterDocument;
+
+ if (typeof this.enterDocument === "function") {
+ this.enterDocument(firstTime);
+ }
+ };
+ };
+
+ MontageElement.prototype.injectResourcesWithinCustomElement = function (resources, shadowRoot) {
+ if (resources && resources.length) {
+ for (var i = 0, length = resources.length; i < length; i++) {
+ shadowRoot.appendChild(resources[i]);
+ }
+ }
+ };
+
+ global.MontageElement = MontageElement;
+ };
+
/**
* Initializes Montage and creates the application singleton if
* necessary.
@@ -690,6 +896,7 @@
} else {
global.__MONTAGE_LOADED__ = true;
exports.initMontage();
+ exports.initMontageCustomElement();
}
} else {
// may cause additional exports to be injected:
diff --git a/package.json b/package.json
index 562d1b4cd0..ed70ea0597 100644
--- a/package.json
+++ b/package.json
@@ -54,7 +54,12 @@
"htmlparser2": "~3.0.5",
"jshint": "^2.9.5",
"mr": "montagejs/mr#commonjs",
- "q-io": "^1.13.3"
+ "q-io": "^1.13.3",
+ "lodash.kebabcase": "^4.1.1",
+ "lodash.camelcase": "^4.3.0",
+ "lodash.trim": "^4.5.1",
+ "lodash.snakecase": "^4.1.1",
+ "proxy-polyfill": "~0.1.7"
},
"devDependencies": {
"concurrently": "^3.4.0",
@@ -86,7 +91,7 @@
"test:karma-chrome": "karma start --no-auto-watch --single-run --browsers=Chrome",
"test:karma-debug": "karma start --auto-watch --no-single-run --browsers=PhantomJS_debug",
"test:karma-dev": "karma start --auto-watch --no-single-run --capture",
- "test:jasmine": "concurrently \"http-server -a localhost -p 8085\" \"open http://localhost:8085/test/run.html\""
+ "test:jasmine": "concurrently \"http-server -p 8085\" \"open http://localhost:8085/test/run.html\""
},
"exclude": [
"report",
diff --git a/test/all.js b/test/all.js
index 63547f1f63..4046180a29 100644
--- a/test/all.js
+++ b/test/all.js
@@ -18,7 +18,8 @@ module.exports = require("montage-testing").run(require, [
"spec/bindings/converter-spec",
"spec/bindings/self-spec",
{name: "spec/document-resources-spec", node: false},
- {name: "spec/claimed-pointer-spec", node: false},
+ { name: "spec/claimed-pointer-spec", node: false },
+ { name: "spec/montage-custom-element-spec", node: false },
// Core
"spec/core/browser-spec",
"spec/core/core-spec",
@@ -81,7 +82,7 @@ module.exports = require("montage-testing").run(require, [
{name: "spec/serialization/montage-serializer-spec"},
{name: "spec/serialization/montage-serializer-element-spec", node: false},
{name: "spec/serialization/montage-deserializer-spec"},
- {name: "spec/serialization/montage-deserializer-element-spec", node: false},
+ { name: "spec/serialization/montage-deserializer-element-spec", node: false, karma: false},
// Trigger
{name: "spec/trigger/trigger-spec", node: false},
// UI
@@ -94,7 +95,7 @@ module.exports = require("montage-testing").run(require, [
{name: "spec/ui/modal-overlay-spec", node: false},
{name: "spec/ui/overlay-spec", node: false},
{name: "spec/ui/slot-spec", node: false},
- {name: "spec/ui/substitution-spec", node: false},
+ {name: "spec/ui/substitution-spec", node: false},
{name: "spec/ui/text-input-spec", node: false},
{name: "spec/ui/slider-spec", node: false},
{name: "spec/ui/text/text-spec", node: false},
@@ -105,19 +106,19 @@ module.exports = require("montage-testing").run(require, [
// Reel
{name: "spec/reel/template-spec", node: false, karma: true},
// UI - repetition
- {name: "spec/ui/repetition-spec", node: false},
+ { name: "spec/ui/repetition-spec", node: false, karma: false},
{name: "spec/ui/repetition-selection-spec", node: false, karma: false},
{name: "spec/ui/repetition-binding-spec", node: false},
{name: "spec/core/localizer-spec", node: false, karma: false},
{name: "spec/core/localizer/serialization-spec", node: false, karma: false},
- // Bluerint
- {name: "spec/meta/converter-blueprint-spec", karma: false},
- {name: "spec/meta/module-blueprint-spec", karma: false},
- {name: "spec/meta/build-in-component-blueprint-spec", node: false, karma: false},
- {name: "spec/meta/component-blueprint-spec", node: false},
- {name: "spec/meta/controller-blueprint-spec", node: false},
- {name: "spec/meta/event-blueprint-spec", node: false},
- {name: "spec/meta/blueprint-spec"}
+ // Meta
+ {name: "spec/meta/converter-object-descriptor-spec", karma: false},
+ {name: "spec/meta/module-object-descriptor-spec", karma: false},
+ {name: "spec/meta/build-in-component-object-descriptor-spec", node: false, karma: false},
+ {name: "spec/meta/component-object-descriptor-spec", node: false},
+ {name: "spec/meta/controller-object-descriptor-spec", node: false},
+ {name: "spec/meta/event-descriptor-spec", node: false},
+ {name: "spec/meta/object-descriptor-spec"}
]).then(function () {
console.log('montage-testing', 'End');
}, function (err) {
diff --git a/test/spec/base/abstract-alert-spec.js b/test/spec/base/abstract-alert-spec.js
index e3a734ef07..bd7a1bbdd5 100644
--- a/test/spec/base/abstract-alert-spec.js
+++ b/test/spec/base/abstract-alert-spec.js
@@ -229,11 +229,11 @@ describe("test/base/abstract-alert-spec", function () {
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractAlert.blueprint || AbstractAlert.objectDescriptor;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractAlert.objectDescriptor || AbstractAlert.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-button-spec.js b/test/spec/base/abstract-button-spec.js
index bffaefda14..694114d9d9 100644
--- a/test/spec/base/abstract-button-spec.js
+++ b/test/spec/base/abstract-button-spec.js
@@ -233,11 +233,11 @@ describe("test/base/abstract-button-spec", function () {
});
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractButton.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractButton.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-checkbox-spec.js b/test/spec/base/abstract-checkbox-spec.js
index c695ca73eb..e216bfeb94 100644
--- a/test/spec/base/abstract-checkbox-spec.js
+++ b/test/spec/base/abstract-checkbox-spec.js
@@ -272,11 +272,11 @@ describe("test/base/abstract-checkbox-spec", function () {
expect(aCheckbox.element.getAttribute("aria-checked")).toBe("false");
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractCheckbox.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractCheckbox.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-confirm-spec.js b/test/spec/base/abstract-confirm-spec.js
index cbe8a1e701..4e433d667d 100644
--- a/test/spec/base/abstract-confirm-spec.js
+++ b/test/spec/base/abstract-confirm-spec.js
@@ -262,11 +262,11 @@ describe("test/base/abstract-confirm-spec", function () {
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractConfirm.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractConfirm.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}).finally(function () {
done();
})
diff --git a/test/spec/base/abstract-image-spec.js b/test/spec/base/abstract-image-spec.js
index de8f3e35e8..a8a0af8c92 100644
--- a/test/spec/base/abstract-image-spec.js
+++ b/test/spec/base/abstract-image-spec.js
@@ -362,11 +362,11 @@ describe("test/base/abstract-image-spec", function () {
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractImage.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractImage.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-link-spec.js b/test/spec/base/abstract-link-spec.js
index cf2e172b58..723c38caf2 100644
--- a/test/spec/base/abstract-link-spec.js
+++ b/test/spec/base/abstract-link-spec.js
@@ -223,11 +223,11 @@ describe("test/base/abstract-link-spec", function () {
});
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractLink.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractLink.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-number-field-spec.js b/test/spec/base/abstract-number-field-spec.js
index d14f8c8966..56bd5024c1 100644
--- a/test/spec/base/abstract-number-field-spec.js
+++ b/test/spec/base/abstract-number-field-spec.js
@@ -443,11 +443,11 @@ describe("test/base/abstract-number-field-spec", function () {
});
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractNumberField.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractNumberField.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-radio-button-spec.js b/test/spec/base/abstract-radio-button-spec.js
index 5ee1cd7cff..efb3989b74 100644
--- a/test/spec/base/abstract-radio-button-spec.js
+++ b/test/spec/base/abstract-radio-button-spec.js
@@ -268,11 +268,11 @@ describe("test/base/abstract-radio-button-spec", function () {
expect(aRadioButton.element.getAttribute("aria-checked")).toBe("false");
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractRadioButton.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractRadioButton.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-select-spec.js b/test/spec/base/abstract-select-spec.js
index b2bc8a3fa1..ce5d160db2 100644
--- a/test/spec/base/abstract-select-spec.js
+++ b/test/spec/base/abstract-select-spec.js
@@ -386,11 +386,11 @@ describe("test/base/abstract-select-spec", function () {
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractSelect.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractSelect.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-slider-spec.js b/test/spec/base/abstract-slider-spec.js
index 6f3b45eb0f..568d48a177 100644
--- a/test/spec/base/abstract-slider-spec.js
+++ b/test/spec/base/abstract-slider-spec.js
@@ -383,11 +383,11 @@ describe("test/base/abstract-slider-spec", function () {
});
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractSlider.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractSlider.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-text-area-spec.js b/test/spec/base/abstract-text-area-spec.js
index a8d53ebd6e..e5c16b1d78 100644
--- a/test/spec/base/abstract-text-area-spec.js
+++ b/test/spec/base/abstract-text-area-spec.js
@@ -178,11 +178,11 @@ describe("test/base/abstract-text-area-spec", function () {
expect(aTextArea.element.hasEventListener("change", aTextArea)).toBe(true);
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractTextArea.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractTextArea.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}).finally(function () {
done();
});
diff --git a/test/spec/base/abstract-text-field-spec.js b/test/spec/base/abstract-text-field-spec.js
index c1df1872d7..808229a44c 100644
--- a/test/spec/base/abstract-text-field-spec.js
+++ b/test/spec/base/abstract-text-field-spec.js
@@ -367,11 +367,11 @@ describe("test/base/abstract-text-field-spec", function () {
});
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractTextField.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractTextField.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-toggle-button-spec.js b/test/spec/base/abstract-toggle-button-spec.js
index 1b47a80d6d..34d7303fa8 100644
--- a/test/spec/base/abstract-toggle-button-spec.js
+++ b/test/spec/base/abstract-toggle-button-spec.js
@@ -302,11 +302,11 @@ describe("test/base/abstract-toggle-button-spec", function () {
});
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractToggleButton.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractToggleButton.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/base/abstract-toggle-switch-spec.js b/test/spec/base/abstract-toggle-switch-spec.js
index f5384bae17..d394c7c5d6 100644
--- a/test/spec/base/abstract-toggle-switch-spec.js
+++ b/test/spec/base/abstract-toggle-switch-spec.js
@@ -65,11 +65,11 @@ describe("test/base/abstract-toggle-switch-spec", function () {
});
});
- describe("blueprint", function () {
+ describe("objectDescriptor", function () {
it("can be created", function (done) {
- var blueprintPromise = AbstractToggleSwitch.blueprint;
- blueprintPromise.then(function (blueprint) {
- expect(blueprint).not.toBeNull();
+ var objectDescriptorPromise = AbstractToggleSwitch.objectDescriptor;
+ objectDescriptorPromise.then(function (objectDescriptor) {
+ expect(objectDescriptor).not.toBeNull();
}, function (err) {
fail(err);
}).finally(function () {
diff --git a/test/spec/converter-spec.js b/test/spec/converter-spec.js
index cb4a8a9e79..637010f1a2 100644
--- a/test/spec/converter-spec.js
+++ b/test/spec/converter-spec.js
@@ -30,13 +30,19 @@ POSSIBILITY OF SUCH DAMAGE.
*/
var Montage = require("montage").Montage;
var Converter= require("montage/core/converter/converter").Converter,
-UpperCaseConverter = require("montage/core/converter/upper-case-converter").UpperCaseConverter,
-LowerCaseConverter = require("montage/core/converter/lower-case-converter").LowerCaseConverter,
-TrimConverter = require("montage/core/converter/trim-converter").TrimConverter,
+UpperCaseConverter = require("montage/core/converter/upper-case-converter").singleton,
+LowerCaseConverter = require("montage/core/converter/lower-case-converter").singleton,
+TrimConverter = require("montage/core/converter/trim-converter").singleton,
NumberConverter = require("montage/core/converter/number-converter").NumberConverter,
BytesConverter = require("montage/core/converter/bytes-converter").BytesConverter,
+InvertConverterModule = require("montage/core/converter/invert-converter"),
+InvertConverter = InvertConverterModule.InvertConverter,
+InvertConverterSingleton = InvertConverterModule.singleton,
DateConverter = require("montage/core/converter/date-converter").DateConverter,
ExpressionConverter = require("montage/core/converter/expression-converter").ExpressionConverter,
+CamelCaseConverter = require("montage/core/converter/camel-case-converter").singleton,
+SnakeCaseConverter = require("montage/core/converter/snake-case-converter").singleton,
+KebabCaseConverter = require("montage/core/converter/kebab-case-converter").singleton,
CurrencyConverter = require("montage/core/converter/currency-converter").CurrencyConverter;
describe("converter-spec", function () {
@@ -46,11 +52,10 @@ describe("converter-spec", function () {
date = new Date('25 Aug 2011 12:00:00 PM');
beforeEach(function () {
- //stringConverter = new StringConverter();
- ucaseConverter = new UpperCaseConverter();
- lcaseConverter = new LowerCaseConverter();
- trimConverter = new TrimConverter();
-
+ ucaseConverter = UpperCaseConverter;
+ lcaseConverter = LowerCaseConverter;
+ trimConverter = TrimConverter;
+ invertConverter = InvertConverterSingleton;
numberConverter = new NumberConverter();
numberConverter.shorten = true;
bytesConverter = new BytesConverter();
@@ -62,39 +67,57 @@ describe("converter-spec", function () {
expressionConverter = new ExpressionConverter();
expressionConverter.convertExpression = "map{foo}";
expressionConverter.revertExpression = "map{{foo:this}}";
- //dateConverter.pattern = 'YYYY-MM-DD';
+
+ camelCaseConverter = CamelCaseConverter;
+ snakeCaseConverter = SnakeCaseConverter;
+ kebabCaseConverter = KebabCaseConverter;
});
describe("test string formatters", function () {
it("should format a string to uppercase", function () {
var value = "hello world";
- //stringConverter.fn = "uppercase";
var result = ucaseConverter.convert(value);
expect(result).toBe('HELLO WORLD');
});
it("should format a string to lowercase", function () {
var value = "HELLO World";
- //stringConverter.fn = "lowercase";
var result = lcaseConverter.convert(value);
expect(result).toBe('hello world');
});
it("should format a string by trimming it", function () {
var value = " hello world ";
- //stringConverter.fn = "trim";
var result = trimConverter.convert(value);
expect(result).toBe('hello world');
});
- /*
- it("should format a string by converting newline characters to
", function () {
- var value = " hello \r\n world ";
- stringConverter.fn = "trim";
- var result = stringConverter.convert(value);
- expect(result).toBe('hello
world');
+ it("should inverts value", function () {
+ expect(invertConverter.convert(true)).toBe(false);
+ expect(invertConverter.convert(0)).toBe(true);
+ });
+
+ it("should converts string to camel case", function () {
+ expect(camelCaseConverter.convert('hello world')).toBe('helloWorld');
+ expect(camelCaseConverter.convert('HELLO WORLD')).toBe('helloWorld');
+ expect(camelCaseConverter.convert('hello-world')).toBe('helloWorld');
+ });
+
+ it("should converts string to snake case", function () {
+ expect(snakeCaseConverter.convert('hello world')).toBe('hello_world');
+ expect(snakeCaseConverter.convert('HELLO WORLD')).toBe('hello_world');
+ expect(snakeCaseConverter.convert('hello-world')).toBe('hello_world');
+ });
+
+ it("should converts string to kebab case", function () {
+ expect(kebabCaseConverter.convert('hello world')).toBe('hello-world');
+ expect(kebabCaseConverter.convert('HELLO WORLD')).toBe('hello-world');
+ expect(kebabCaseConverter.convert('hello_world')).toBe('hello-world');
+ });
+
+ it("should be a singleton", function () {
+ expect(invertConverter === new InvertConverter()).toBe(true);
});
- */
});
diff --git a/test/spec/custom-elements/custom-elements-test.js b/test/spec/custom-elements/custom-elements-test.js
new file mode 100644
index 0000000000..b3a0ba639f
--- /dev/null
+++ b/test/spec/custom-elements/custom-elements-test.js
@@ -0,0 +1,14 @@
+
+var querySelector = function (e) { return document.querySelector(e); }
+
+var Montage = require("montage").Montage;
+var Component = require("montage/ui/component").Component;
+var Application = require("montage/core/application").application;
+var MontageText = require("montage/ui/text.reel").Text;
+var MyButton = require("spec/custom-elements/my-button.reel").MyButton;
+
+var CustomElementTest = exports.CustomElementTest = Montage.specialize({
+ textLabel2: {
+ value: 'textLabel2'
+ }
+});
diff --git a/test/spec/custom-elements/custom-elements.html b/test/spec/custom-elements/custom-elements.html
new file mode 100644
index 0000000000..a7eca0e4da
--- /dev/null
+++ b/test/spec/custom-elements/custom-elements.html
@@ -0,0 +1,43 @@
+
+