From 7e94d5786df400b599df3233b3086bfe9eff2bde Mon Sep 17 00:00:00 2001 From: Eric Guzman Date: Wed, 16 May 2012 22:58:24 -0700 Subject: Objects Panel - Add Objects controller and montage/application hack to expose template --- node_modules/montage/ui/application.js | 3 +++ 1 file changed, 3 insertions(+) (limited to 'node_modules') diff --git a/node_modules/montage/ui/application.js b/node_modules/montage/ui/application.js index bbce6835..43443ecc 100755 --- a/node_modules/montage/ui/application.js +++ b/node_modules/montage/ui/application.js @@ -153,6 +153,9 @@ var Application = exports.Application = Montage.create(Montage, /** @lends monta // assign to the exports so that it is available in the deserialization of the template exports.application = self; + ///// TODO: Remove this hack when montage exposes this + this._template = template; + template.instantiateWithOwnerAndDocument(null, window.document, function() { require("ui/component").__root__.needsDraw = true; if (callback) { -- cgit v1.2.3 From 2c1aec1f4d7b2ca03cb9911feeb8a9d1d66f9826 Mon Sep 17 00:00:00 2001 From: Eric Guzman Date: Fri, 25 May 2012 16:34:21 -0700 Subject: Data Binding - Hacked patch to Montage to enable serialization of dynamically bound objects. We should remove this once montage github issue [gh-657] is in our version of montage. --- node_modules/montage/core/event/binding.js | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'node_modules') diff --git a/node_modules/montage/core/event/binding.js b/node_modules/montage/core/event/binding.js index 2e226372..c10c52e4 100755 --- a/node_modules/montage/core/event/binding.js +++ b/node_modules/montage/core/event/binding.js @@ -343,9 +343,31 @@ var BindingDescriptor = exports.BindingDescriptor = Montage.create(Montage, /** }); Serializer.defineSerializationUnit("bindings", function(object) { - var bindingDescriptors = object._bindingDescriptors; + var bindingDescriptors = object._bindingDescriptors, + bindingDescriptorsCopy; + + // TODO: Hacked this function to create copy of object literal + // TODO: Remove when montage finds out how to identify object literals + // TODO: in a different way + function cloneObject(object, level) { + var clone = {}; + + for (var key in object) { + if (level > 0) { + clone[key] = cloneObject(object[key], level - 1); + } else { + clone[key] = object[key]; + } + } + + return clone; + } if (bindingDescriptors) { + if (Object.getPrototypeOf(bindingDescriptors) !== Object.prototype) { + bindingDescriptors = cloneObject(bindingDescriptors , 1); + } + return bindingDescriptors; } }); -- cgit v1.2.3 From 16b70e723f411088a4f1a2a9d94fd7702fdca7dc Mon Sep 17 00:00:00 2001 From: Eric Guzman Date: Fri, 1 Jun 2012 13:26:27 -0700 Subject: Manually Add Fix for Montage serialization problem --- node_modules/montage/core/serializer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'node_modules') diff --git a/node_modules/montage/core/serializer.js b/node_modules/montage/core/serializer.js index 72543328..deadbc68 100755 --- a/node_modules/montage/core/serializer.js +++ b/node_modules/montage/core/serializer.js @@ -529,10 +529,10 @@ var Serializer = Montage.create(Montage, /** @lends module:montage/serializer.Se return this._serializeElement(value); } else if (Array.isArray(value)) { return this._serializeArray(value, indent + 1); - } else if (Object.getPrototypeOf(value) === Object.prototype) { - return this._serializeObjectLiteral(value, null, indent + 1); } else if (value.constructor === Function) { return this._serializeFunction(value, indent); + } else if (!("getInfoForObject" in value)) { // we consider object literals the ones who aren't a Montage object + return this._serializeObjectLiteral(value, null, indent + 1); } else { // TODO: should refactor this to handle references here, doesn't make // sense to wait until it hits _serializeObject for that to happen -- cgit v1.2.3 From 557473639c1854d2e545f542d5f8656a040d575c Mon Sep 17 00:00:00 2001 From: Armen Kesablyan Date: Wed, 6 Jun 2012 14:42:12 -0700 Subject: Object Controller Signed-off-by: Armen Kesablyan --- node_modules/montage/ui/native-control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'node_modules') diff --git a/node_modules/montage/ui/native-control.js b/node_modules/montage/ui/native-control.js index 8dad5408..d2c7f8b1 100644 --- a/node_modules/montage/ui/native-control.js +++ b/node_modules/montage/ui/native-control.js @@ -96,7 +96,7 @@ var NativeControl = exports.NativeControl = Montage.create(Component, /** @lends var newDescriptor = { configurable: (typeof descriptor.configurable == 'undefined') ? true: descriptor.configurable, enumerable: (typeof descriptor.enumerable == 'undefined') ? true: descriptor.enumerable, - serializable: (typeof descriptor.serializable == 'undefined') ? true: descriptor.serializable, + set: (function(name, attrName) { return function(value) { var desc = this._getElementAttributeDescriptor(name, this); -- cgit v1.2.3 From 4565558afff6fb07db3b5165042e028f467ac41b Mon Sep 17 00:00:00 2001 From: Armen Kesablyan Date: Thu, 21 Jun 2012 15:46:26 -0700 Subject: Binding View :Requested Changes for Pull Request Signed-off-by: Armen Kesablyan --- node_modules/montage/core/event/binding.js | 134 ++++++++++++----------------- 1 file changed, 56 insertions(+), 78 deletions(-) (limited to 'node_modules') diff --git a/node_modules/montage/core/event/binding.js b/node_modules/montage/core/event/binding.js index 4206e1c2..4091fe6a 100755 --- a/node_modules/montage/core/event/binding.js +++ b/node_modules/montage/core/event/binding.js @@ -5,13 +5,13 @@ */ /** - @module montage/core/event/binding - @requires montage/core/core - @requires montage/core/event/mutable-event - @requires montage/core/serializer - @requires montage/core/deserializer - @requires montage/core/event/event-manager -*/ + @module montage/core/event/binding + @requires montage/core/core + @requires montage/core/event/mutable-event + @requires montage/core/serializer + @requires montage/core/deserializer + @requires montage/core/event/event-manager + */ var Montage = require("montage").Montage, ChangeNotification = require("core/change-notification").ChangeNotification, @@ -23,14 +23,14 @@ var Montage = require("montage").Montage, UNDERSCORE = "_"; /** - @class module:montage/core/event/binding.ChangeEventDispatchingArray -*/ + @class module:montage/core/event/binding.ChangeEventDispatchingArray + */ var ChangeEventDispatchingArray = exports.ChangeEventDispatchingArray = []; /** - @class module:montage/core/event/binding.PropertyChangeBindingListener - @extends module:montage/core/core.Montage -*/ + @class module:montage/core/event/binding.PropertyChangeBindingListener + @extends module:montage/core/core.Montage + */ var PropertyChangeBindingListener = exports.PropertyChangeBindingListener = Object.create(Montage, /** module:montage/core/event/binding.PropertyChangeBindingListener# */ { useCapture: {value:false, writable: true}, @@ -86,11 +86,11 @@ var PropertyChangeBindingListener = exports.PropertyChangeBindingListener = Obje value:function (notification) { var bindingOriginTriggeredChange, - // Left + // Left bindingOrigin = this.bindingOrigin, bindingOriginPropertyPath = this.bindingPropertyPath, bindingOriginValue = bindingOrigin.getProperty(bindingOriginPropertyPath), - // Right + // Right boundObject = this.target, boundObjectPropertyPath = this.targetPropertyPath, boundObjectValue; @@ -162,14 +162,14 @@ var PropertyChangeBindingListener = exports.PropertyChangeBindingListener = Obje }); /** - @function external:Object#propertyChangeBindingListener - @param {string} type The event type to listen for. - @param {function} listener The event listener object. - @param {boolean} useCapture Specifies whether to listen for the property change during the capture or bubble event phases. - @param {object} bindingOrigin The source of the binding. - @param {string} bindingPropertyPath The key path of the property on the source object. - @param {object} bindingDescriptor A property descriptor object that specifies the bound object and the bound object property path. -*/ + @function external:Object#propertyChangeBindingListener + @param {string} type The event type to listen for. + @param {function} listener The event listener object. + @param {boolean} useCapture Specifies whether to listen for the property change during the capture or bubble event phases. + @param {object} bindingOrigin The source of the binding. + @param {string} bindingPropertyPath The key path of the property on the source object. + @param {object} bindingDescriptor A property descriptor object that specifies the bound object and the bound object property path. + */ Object.defineProperty(Object.prototype, "propertyChangeBindingListener", { value: function(type, listener, useCapture, atSignIndex, bindingOrigin, bindingPropertyPath, bindingDescriptor) { @@ -203,41 +203,41 @@ Object.defineProperty(Object.prototype, "propertyChangeBindingListener", { Binding descriptor keys @class module:montage/core/event/binding.BindingDescriptor @extends module:montage/core/core.Montage -*/ + */ var BindingDescriptor = exports.BindingDescriptor = Montage.create(Montage, /** @lends module:montage/core/event/binding.BindingDescriptor */ { -/** - The object sourceObject will be bound to -*/ + /** + The object sourceObject will be bound to + */ boundObject: { enumerable: false, serializable: true, value: null }, -/** + /** - The key path of boundObject which sourceObject's sourceObjectBindingPath is bound to + The key path of boundObject which sourceObject's sourceObjectBindingPath is bound to -*/ + */ boundObjectPropertyPath: { enumerable: false, serializable: true, value: null }, -/** - Specifies whether the source Object will push value back to it's boundObject's boundObjectPropertyPath or not. Default is false. -*/ + /** + Specifies whether the source Object will push value back to it's boundObject's boundObjectPropertyPath or not. Default is false. + */ oneway: { enumerable: false, serializable: true, value: null }, -/** + /** If true, PropertyChangeBindingListener will buffer the value until it's told to execute binding. Setting this value to false allows for some runtime optimizations.deferred. Default is false, binding values propagate immediately. -*/ + */ deferred: { enumerable: false, serializable: true, @@ -257,31 +257,9 @@ var BindingDescriptor = exports.BindingDescriptor = Montage.create(Montage, /** }); Serializer.defineSerializationUnit("bindings", function(object) { - var bindingDescriptors = object._bindingDescriptors, - bindingDescriptorsCopy; - - // TODO: Hacked this function to create copy of object literal - // TODO: Remove when montage finds out how to identify object literals - // TODO: in a different way - function cloneObject(object, level) { - var clone = {}; - - for (var key in object) { - if (level > 0) { - clone[key] = cloneObject(object[key], level - 1); - } else { - clone[key] = object[key]; - } - } - - return clone; - } + var bindingDescriptors = object._bindingDescriptors; if (bindingDescriptors) { - if (Object.getPrototypeOf(bindingDescriptors) !== Object.prototype) { - bindingDescriptors = cloneObject(bindingDescriptors , 1); - } - return bindingDescriptors; } }); @@ -320,12 +298,12 @@ Deserializer.defineDeserializationUnit("bindings", function(object, bindings, de }); /** - @function external:Object.defineBinding - @param {object} sourceObject The source object of the data binding. This object establishes the binding between itself and the "bound object" specified by the bindingDescriptor parameter. - @param {string} sourceObjectPropertyBindingPath The key path to the source object's property that is being bound. - @param {object} bindingDescriptor An object that describes the bound object, the bound object's property path, and other properties. - @see [BindingDescriptor object]{@link module:montage/core/event/binding#BindingDescriptor} -*/ + @function external:Object.defineBinding + @param {object} sourceObject The source object of the data binding. This object establishes the binding between itself and the "bound object" specified by the bindingDescriptor parameter. + @param {string} sourceObjectPropertyBindingPath The key path to the source object's property that is being bound. + @param {object} bindingDescriptor An object that describes the bound object, the bound object's property path, and other properties. + @see [BindingDescriptor object]{@link module:montage/core/event/binding#BindingDescriptor} + */ Object.defineProperty(Object, "defineBinding", {value: function(sourceObject, sourceObjectPropertyBindingPath, bindingDescriptor) { var _bindingDescriptors = sourceObject._bindingDescriptors, oneway = typeof bindingDescriptor.oneway === "undefined" ? false : bindingDescriptor.oneway, @@ -442,11 +420,11 @@ Object.defineProperty(Object.prototype, "_deserializeProperty_bindingDescriptors }); /** - Deletes a single binding on the specified object. - @function external:Object.deleteBinding - @param {object} sourceObject The source object that defined the binding. - @param {string} sourceObjectPropertyBindingPath The key path to the bound object's bound property. -*/ + Deletes a single binding on the specified object. + @function external:Object.deleteBinding + @param {object} sourceObject The source object that defined the binding. + @param {string} sourceObjectPropertyBindingPath The key path to the bound object's bound property. + */ Object.defineProperty(Object, "deleteBinding", {value: function(sourceObject, sourceObjectPropertyBindingPath) { var _bindingDescriptors = sourceObject._bindingDescriptors, bindingDescriptor, @@ -470,10 +448,10 @@ Object.defineProperty(Object, "deleteBinding", {value: function(sourceObject, so }}); /** - Deletes all bindings on the specified object. - @function external:Object.deleteBindings - @param {object} object The object to delete bindings from. -*/ + Deletes all bindings on the specified object. + @function external:Object.deleteBindings + @param {object} object The object to delete bindings from. + */ Object.defineProperty(Object, "deleteBindings", {value: function(object) { var bindingDescriptors = object._bindingDescriptors; @@ -512,17 +490,17 @@ Object.defineProperty(Object, "applyBindingsDeferredValues", {value: function(ob Montage.defineProperty(Object.prototype, "_bindingsDisabled", {enumerable: false, value: null}); /** - Temporarily disables bindings on the specified object. To re-enable bindings, call [Object.enableBindings()]{@link external:Object.enableBindings}. - @function external:Object.disableBindings -*/ + Temporarily disables bindings on the specified object. To re-enable bindings, call [Object.enableBindings()]{@link external:Object.enableBindings}. + @function external:Object.disableBindings + */ Object.defineProperty(Object, "disableBindings", {value: function(object) { object._bindingsDisabled = true; }}); /** - Re-enables data binding on the object after being disabled with [Object.disableBindings()]{@link external:Object.disableBindings}, applying any deferred bindings that were queued during the interval. - @function external:Object#enableBindings -*/ + Re-enables data binding on the object after being disabled with [Object.disableBindings()]{@link external:Object.disableBindings}, applying any deferred bindings that were queued during the interval. + @function external:Object#enableBindings + */ Object.defineProperty(Object, "enableBindings", {value: function(object) { object._bindingsDisabled = false; Object.applyBindingsDeferredValues(object, true); -- cgit v1.2.3 From 23aec4144f9d4352ba6d10367288f51d57ba990f Mon Sep 17 00:00:00 2001 From: Armen Kesablyan Date: Sat, 23 Jun 2012 13:44:49 -0700 Subject: Text Tool Fix - Can Not Switch Document when Text Tool Initialized Signed-off-by: Armen Kesablyan --- .../rich-text-editor.reel/rich-text-editor.css | 112 -- .../rich-text-editor.reel/rich-text-editor.html | 27 - .../labs/rich-text-editor.reel/rich-text-editor.js | 1716 -------------------- .../rich-text-editor.reel/rich-text-resizer.js | 349 ---- .../rich-text-editor.reel/rich-text-sanitizer.js | 132 -- .../labs/rich-text-editor.reel/shortcut-manager.js | 237 --- 6 files changed, 2573 deletions(-) delete mode 100644 node_modules/labs/rich-text-editor.reel/rich-text-editor.css delete mode 100644 node_modules/labs/rich-text-editor.reel/rich-text-editor.html delete mode 100644 node_modules/labs/rich-text-editor.reel/rich-text-editor.js delete mode 100644 node_modules/labs/rich-text-editor.reel/rich-text-resizer.js delete mode 100644 node_modules/labs/rich-text-editor.reel/rich-text-sanitizer.js delete mode 100644 node_modules/labs/rich-text-editor.reel/shortcut-manager.js (limited to 'node_modules') diff --git a/node_modules/labs/rich-text-editor.reel/rich-text-editor.css b/node_modules/labs/rich-text-editor.reel/rich-text-editor.css deleted file mode 100644 index 656183c4..00000000 --- a/node_modules/labs/rich-text-editor.reel/rich-text-editor.css +++ /dev/null @@ -1,112 +0,0 @@ -/* - This file contains proprietary software owned by Motorola Mobility, Inc.
- No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
- (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. -
*/ - -.montage-editor { - /* need to be relative in order for the resizer to be positioned correctly */ - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - padding: 4px; - - font-size: 1.0em; - outline: none; - overflow: auto; - z-index: 1; -} - -.montage-editor-frame { - position: relative; - overflow: auto; - height: 100%; - width: 100%; -} - -.montage-resizer-element::selection { - background: rgba(0,0,0,0); -} - - -/* -Resizer -*/ -.montage-resizer { - display: inline-block; -} - -.montage-resizer-frame { - position: absolute; - border: 1px solid black; - z-index: 30; -} - -.montage-resizer-handle { - position: absolute; - border: 1px solid black; - background-color: white; - width: 6px; - height: 6px; - z-index: 31; -} - -.montage-resizer.dragged .montage-resizer-handle{ - display: none; -} - -.montage-resizer-handle:hover { - background-color: black; -} - -.montage-resizer-n { - cursor: n-resize; -} -.montage-resizer-ne { - cursor: ne-resize; -} -.montage-resizer-e { - cursor: e-resize; -} -.montage-resizer-se { - cursor: se-resize; -} -.montage-resizer-s { - cursor: s-resize; -} -.montage-resizer-sw { - cursor: sw-resize; -} -.montage-resizer-w { - cursor: w-resize; -} -.montage-resizer-nw { - cursor: nw-resize; -} - - -/* -Link Popup -*/ -.montage-link-popup { - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,.2); - -webkit-border-radius: 2px; - border-radius: 2px; - position: absolute; - border: 1px solid; - background-color: white; - color: #666; - padding: 12px 20px; - z-index: 50; - cursor: default; - border-color: #BBB #BBB #A8A8A8; - font: 13px/normal "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; -} - -.montage-link-popup a { - cursor: pointer; - text-decoration: none; - color: #15C; -} \ No newline at end of file diff --git a/node_modules/labs/rich-text-editor.reel/rich-text-editor.html b/node_modules/labs/rich-text-editor.reel/rich-text-editor.html deleted file mode 100644 index 42425b40..00000000 --- a/node_modules/labs/rich-text-editor.reel/rich-text-editor.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/labs/rich-text-editor.reel/rich-text-editor.js b/node_modules/labs/rich-text-editor.reel/rich-text-editor.js deleted file mode 100644 index b88d5868..00000000 --- a/node_modules/labs/rich-text-editor.reel/rich-text-editor.js +++ /dev/null @@ -1,1716 +0,0 @@ -/* - This file contains proprietary software owned by Motorola Mobility, Inc.
- No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
- (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. -
*/ -/** - @module "montage/ui/rich-text-editor.reel" - @requires montage/core/core -*/ -var Montage = require("montage/core/core").Montage, - Component = require("montage/ui/component").Component, - MutableEvent = require("montage/core/event/mutable-event").MutableEvent, - Resizer = require("node_modules/labs/rich-text-editor.reel/rich-text-resizer").Resizer, - Sanitizer = require("node_modules/labs/rich-text-editor.reel/rich-text-sanitizer").Sanitizer; - Point = require("montage/core/geometry/point").Point; - - -/** - @class module:"montage/ui/rich-text-editor.reel".RichTextEditor - @extends module:montage/ui/component.Component -*/ -exports.RichTextEditor = Montage.create(Component,/** @lends module:"montage/ui/rich-text-editor.reel".RichTextEditor# */ { - - /** - Description TODO - @private - */ - _hasSelectionChangeEvent: { - enumerable: false, - value: null // Need to be preset to null, will be set to true or false later on - }, - - /** - Description TODO - @private - */ - _uniqueId: { - enumerable: false, - value: Math.floor(Math.random() * 1000) + "-" + Math.floor(Math.random() * 1000) - }, - - /** - Description TODO - @private - */ - _needsSelectionReset: { - enumerable: false, - value: false - }, - - /** - Description TODO - @private - */ - _selectionChangeTimer: { - enumerable: false, - value: null - }, - - /** - Description TODO - @private - */ - _activeLink: { - enumerable: false, - value: null - }, - - /** - Description TODO - @private - */ - _needsActiveLinkOn: { - enumerable: false, - value: false - }, - - /** - Description TODO - @private - */ - _hasFocus: { - enumerable: false, - value: false - }, - - /** - Description TODO - @type {Function} - */ - hasFocus: { - enumerable: true, - get: function() { - return this._hasFocus; - } - }, - - /** - Description TODO - @private - */ - _dirty: { - enumerable: false, - value: false - }, - - /** - Description TODO - @private - */ - _value: { - enumerable: false, - value: "" - }, - - /** - Description TODO - @type {Function} - */ - value: { - enumerable: true, - serializable: true, - get: function() { - var contentNode = this.element.firstChild, - content; - - if (this._dirtyValue) { - if (this._resizer) { - contentNode = this._resizer.cleanup(contentNode); - } - - contentNode = this._cleanupActiveLink(contentNode); - - content = contentNode ? contentNode.innerHTML : ""; - if (content == "
") { - // when the contentEditable div is emptied, Chrome add a
, let's filter it out - content = ""; - } - if (this._sanitizer) { - content = this._sanitizer.didGetValue(content, this._uniqueId); - } - - this._value = content; - this._dirtyValue = false; - } - return this._value; - }, - set: function(value) { - if (this._value !== value || this._dirtyValue) { - if (this._resizer) { - this._needsHideResizer = true; - } - if (this._sanitizer) { - value = this._sanitizer.willSetValue(value, this._uniqueId); - } - this._value = value; - this._dirtyValue = false; - this._dirtyTextValue = true; - this._needsSelectionReset = true; - this._needsResetContent = true; - this.needsDraw = true; - } - } - }, - - /** - Description TODO - @private - */ - _textValue: { - enumerable: false, - value: "" - }, - - /** - Description TODO - @type {Function} - */ - textValue: { - enumerable: true, - get: function() { - var contentNode = this.element.firstChild, - childNodes; - - if (this._dirtyTextValue) { - if (contentNode) { - if (this._resizer) { - contentNode = this._resizer.cleanup(contentNode); - } - contentNode = this._cleanupActiveLink(contentNode); - } - - this._textValue = contentNode ? this._innerText(contentNode) : ""; - this._dirtyTextValue = false; - } - return this._textValue; - }, - set: function (value) { - if (this._textValue !== value || this._dirtyTextValue) { - if (this._resizer) { - this._needsHideResizer = true; - } - - this._textValue = value; - this._dirtyTextValue = false; - this._dirtyValue = true; - this._needsSelectionReset = true; - this._needsResetContent = true; - this.needsDraw = true; - } - } - }, - - /** - Description TODO - @type {} - */ - delegate: { - enumerable: true, - value: null - }, - - /** - Description TODO - @private - */ - _sanitizer: { - enumerable: false, - value: Sanitizer.create() - }, - - /** - Description TODO - @type {Function} - */ - sanitizer: { - enumerable: false, - get: function() { - return this._sanitizer; - }, - set: function(value) { - this._sanitizer = value; - } - }, - - /** - Description TODO - @private - */ - _resizer: { - enumerable: false, - value: Resizer.create() - }, - - /** - Description TODO - @type {Function} - */ - resizer: { - enumerable: false, - get: function() { - return this._resizer; - }, - set: function(value) { - // force hide the current resizer - if (this._resizer){ - this._resizer.hide(true); - delete this._needsHideResizer; - } - this._resizer = value; - this._resizer.initialize(this); - } - }, - - /** - Description TODO - @private - */ - _statesDirty: { - enumerable: false, - value: false - }, - - /** - Description TODO - @private - */ - _states: { - enumerable: false, - value: null - }, - - /** - Description TODO - @type {Function} - */ - states: { - enumerable: true, - get: function() { - if (this._statesDirty || !this._states) { - this.updateStates(); - } - return this._states; - } - }, - - /** - Description TODO - @type {Function} - */ - updateStates: { - enumerable: true, - value: function() { - var actions = this._actions, - key, - action, - states, - state, - hasFocus = this._hasFocus; - - if (this._states == null || this._statesDirty) { - this._states = this._states || {}; - - if (hasFocus) { - this._statesDirty = false; - states = this._states; - for (key in actions) { - action = actions[key]; - state = "false"; - if (action.enabled && action.status) { - state = document.queryCommandValue(key); - if (typeof state == "boolean") { - state = state ? "true" : "false"; - } - - // Clean up font name - if (key == "fontname") { - state = state.replace(/'/g, ""); - } - } - - if (states[key] !== state) { - states[key] = state; - } - } - } - } - - return this._states; - } - }, - - /** - Description TODO - @private - */ - _allowDrop: { - enumerable: false, - value: true - }, - - /** - Description TODO - @type {Function} - */ - allowDrop: { - enumerable: true, - serializable: true, - get: function() { - return this._allowDrop; - }, - set: function(value) { - this._allowDrop = value; - } - }, - - /** - Description TODO - @private - */ - _actions: { - enumerable: false, - value: { - bold: {enabled: true, needsValue:false, status: true}, - justifyleft: {enabled: true, needsValue:false, status: true}, - justifycenter: {enabled: true, needsValue:false, status: true}, - justifyright: {enabled: true, needsValue:false, status: true}, - justifyfull: {enabled: true, needsValue:false, status: true}, - italic: {enabled: true, needsValue:false, status: true}, - underline: {enabled: true, needsValue:false, status: true}, - strikethrough: {enabled: true, needsValue:false, status: true}, - indent: {enabled: true, needsValue:false, status: false}, - outdent: {enabled: true, needsValue:false, status: false}, - insertorderedlist: {enabled: true, needsValue:false, status: true}, - insertunorderedlist: {enabled: true, needsValue:false, status: true}, - fontname: {enabled: true, needsValue:true, status: true}, - fontsize: {enabled: true, needsValue:true, status: true}, - hilitecolor: {enabled: true, needsValue:true, status: true}, - forecolor: {enabled: true, needsValue:true, status: true} - } - }, - - /** - Description TODO - @type {Function} - */ - actions: { - enumerable: false, - get: function() { - var actions = this._actions, - action, - actionsArray = []; - - for (action in actions) { - actionsArray.push(action); - } - - return actionsArray; - } - }, - - /** - Description TODO - @type {Function} - */ - enabledActions: { - enumerable: true, - serializable: true, - get: function() { - var actions = this._actions, - action, - actionsArray = []; - - for (action in actions) { - if (actions[action].enabled) { - actionsArray.push(action); - } - } - - return actionsArray; - }, - set: function(enabledActions) { - var actions = this._actions, - nbrEnabledActions = enabledActions.length, - action, - i; - - for (action in actions) { - actions[action].enabled = false; - } - - for (i = 0; i < nbrEnabledActions; i ++) { - action = enabledActions[i]; - if (actions[action] !== undefined) { - actions[action].enabled = true; - } - } - } - }, - - /** - Description TODO - @private - */ - _needsFocus: { - value: false - }, - - /** - Description TODO - @type {Function} - */ - focus: { - value: function() { - this._needsFocus = true; - this.needsDraw = true; - } - }, - - // Component Callbacks - /** - Description TODO - @function - */ - prepareForDraw: { - enumerable: false, - value: function() { - var el = this.element, - div; - - if (this._resizer) { - this._resizer.initialize(this); - } - el.classList.add('montage-editor-frame'); - - el.addEventListener("focus", this); - el.addEventListener("dragstart", this, false); - el.addEventListener("dragend", this, false); - el.addEventListener("dragover", this, false); - el.addEventListener("drop", this, false); - - this._needsResetContent = true; - } - }, - - /** - Description TODO - @function - */ - draw: { - enumerable: false, - value: function() { - var thisRef = this, - editorElement = this.element, - element, - range, - offset; - - if (this._needsResetContent === true) { - // Reset the editor content in order to reset the browser undo stack - editorElement.innerHTML = '
'; - - // Set the contentEditable value - if (this._value && !this._dirtyValue) { - editorElement.firstChild.innerHTML = this._value; - // Since this property affects the textValue, we need to fire a change event for it as well - this.dispatchEvent(MutableEvent.changeEventForKeyAndValue("textValue" , this.textValue)); - } else if (this._textValue && !this._dirtyTextValue) { - editorElement.firstChild.innerText = this._textValue; - // Since this property affects the value, we need to fire a change event for it as well - this.dispatchEvent(MutableEvent.changeEventForKeyAndValue("value" , this.value)); - } else { - editorElement.firstChild.innerHTML = ""; - } - - this._adjustPadding(); - this._markDirty(); - delete this._needsResetContent; - } - - if (this._resizer) { - // Need to hide the resizer? - if (this._needsHideResizer) { - this._resizer.hide(); - delete this._needsHideResizer; - } - - // Need to show the resizer? - if (this._needsShowResizerOn) { - element = this._needsShowResizerOn; - this._resizer.show(element); - - // Select the element and its resizer - this._selectingResizer = true; - offset = this._nodeOffset(element); - range = document.createRange(); - range.setStart(element.parentNode, offset); - range.setEnd(element.parentNode, offset + 1); - this._selectedRange = range; - - // Note: Chrome (and maybe other browsers) will fire 2 selectionchange event asynchronously, to work around it let's use a timer - setTimeout(function() {delete thisRef._selectingResizer;}, 0); - - delete this._needsShowResizerOn; - } - - // Let's give a change to the resizer to do any custom drawing if needed - this._resizer.draw(); - } - - if (this._needsActiveLinkOn !== false && this._needsActiveLinkOn != this._activeLink) { - this._showActiveLink(this._needsActiveLinkOn); - this._needsActiveLinkOn = false; - } - - } - }, - - /** - Description TODO - @function - */ - didDraw: { - value: function() { - if (this._needsFocus) { - this.element.firstChild.focus(); - if(document.activeElement == this.element.firstChild) { - this._needsFocus = false; - } else { - // Make sure the element is visible before trying again to set the focus - var style = window.getComputedStyle(this.element); - if (style.getPropertyValue("visibility") == "hidden" || style.getPropertyValue("display") == "none") { - this._needsFocus = false; - } else { - this.needsDraw = true; - } - } - } - } - }, - - /** - Description TODO - @function - */ - _adjustPadding: { - enumerable: false, - value: function() { - var el = this.element.firstChild, - minLeft = 0, - minTop = 0; - - var walkTree = function(node, parentLeft, parentTop) { - var nodes = node ? node.childNodes : [], - nbrNodes = nodes.length, - i, - offsetLeft = node.offsetLeft, - offsetTop = node.offsetTop; - - if (node.offsetParent) { - offsetLeft += parentLeft; - offsetTop += parentTop; - } - if (minLeft > offsetLeft) { - minLeft = offsetLeft; - } - if (minTop > offsetTop) { - minTop = offsetTop; - } - - for (i = 0; i < nbrNodes; i ++) { - walkTree(nodes[i], offsetLeft, offsetTop) - } - }; - walkTree(el, el.offsetLeft, el.offsetTop); - - var computedStyle = document.defaultView.getComputedStyle(el), - paddingLeft = computedStyle.paddingLeft, - paddingTop = computedStyle.paddingTop; - - if (paddingLeft.match(/%$/)) { - paddingLeft = parseInt(paddingLeft, 10) * el.clientWidth; - } else { - paddingLeft = parseInt(paddingLeft, 10); - } - if (paddingTop.match(/%$/)) { - paddingTop = parseInt(paddingTop, 10) * el.clientHeight; - } else { - paddingTop = parseInt(paddingTop, 10); - } - - if (minLeft < 0) { - el.style.paddingLeft = (-minLeft - paddingLeft) + "px"; - } - if (minTop < 0) { - el.style.paddingTop = (-minTop - paddingTop) + "px"; - } - } - }, - - // Event handlers - // Event handlers - /** - Description TODO - @function - */ - handleFocus: { - enumerable: false, - value: function() { - var thisRef = this, - el = this.element, - content = el.firstChild, - savedRange, - timer; - - this._hasFocus = true; - if (this._needsSelectionReset) { - var node = this._lastInnerNode(), - range, - length, - leafNodes = ["#text", "BR", "IMG"]; - - // Select the last inner node - if (node) { - if (leafNodes.indexOf(node.nodeName) !== -1) { - node = node.parentNode; - } - range = document.createRange(); - length = node.childNodes ? node.childNodes.length : 0; - range.setStart(node, length); - range.setEnd(node, length); - this._selectedRange = range; - } - - // Scroll the content to make sure the caret is visible, but only only if the focus wasn't the result of a user click/touch - savedRange = this._selectedRange; - timer = setInterval(function() { - if (thisRef._equalRange(thisRef._selectedRange, savedRange) && - content.scrollTop + content.offsetHeight != content.scrollHeight) { - content.scrollTop = content.scrollHeight - content.offsetHeight; - } - }, 10); - - setTimeout(function(){clearInterval(timer)}, 1000); - - this._needsSelectionReset = false; - } - - el.addEventListener("blur", this); - el.addEventListener("input", this); - el.addEventListener("keypress", this); - el.addEventListener("paste", this, false); - el.addEventListener(window.Touch ? "touchstart" : "mousedown", this); - document.addEventListener(window.Touch ? "touchend" : "mouseup", this); - - document.addEventListener("selectionchange", this, false); - // Check if the browser does not supports the DOM event selectionchange - if (this._hasSelectionChangeEvent === null) { - var thisRef = this; - setTimeout(function(){ - if (thisRef._hasSelectionChangeEvent === null) { - thisRef._hasSelectionChangeEvent = false; - } - }, 0); - } - if (this._hasSelectionChangeEvent === false) { - // We need to listen to more event in order to simulate a selectionchange event - el.addEventListener("keydup", this); - } - - // Turn off image resize (if supported) - document.execCommand("enableObjectResizing", false, false); - // Force use css for styling (if supported) - document.execCommand("styleWithCSS", false, true); - - // Update the states if they are dirty - if (this._statesDirty) { - this.updateStates(); - } - } - }, - - /** - Description TODO - @function - */ - handleBlur: { - enumerable: false, - value: function() { - var el = this.element; - - // Force a selectionchange when we lose the focus - this.handleSelectionchange(); - - el.removeEventListener("blur", this); - el.removeEventListener("input", this); - el.removeEventListener("keypress", this); - el.removeEventListener("paste", this, false); - el.removeEventListener(window.Touch ? "touchstart" : "mousedown", this); - document.removeEventListener(window.Touch ? "touchend" : "mouseup", this); - - document.removeEventListener("selectionchange", this); - - if (this._hasSelectionChangeEvent === false) { - el.removeEventListener("keydup", this); - } - - this._hasFocus = false; - } - }, - - /** - Description TODO - @function - */ - handleKeypress: { - enumerable: false, - value: function() { - if (this._hasSelectionChangeEvent === false) { - this.handleSelectionchange(); - } - - if (this._activeLink) { - this._hideActiveLink(); - } - - this._markDirty(); - } - }, - - /** - Description TODO - @function - */ - handleInput: { - enumerable: false, - value: function(event) { - if (this._hasSelectionChangeEvent === false) { - this.handleSelectionchange(); - } - - if (this._activeLink) { - this._hideActiveLink(); - } - - this.handleDragend(event); - this._markDirty(); - } - }, - - /** - Description TODO - @function - */ - handleShortcut: { - enumerable: false, - value: function(event, action) { - if (this._actions[action] && this._actions[action].enabled) { - this.doAction(action); - return true; - } - - return false; - } - }, - - /** - Description TODO - @function - */ - handleMousedown: { - enumerable: false, - value: function(event) { - if (this._resizer) { - if (this.resizer.startUserAction(event)) { - event.preventDefault(); - event.stopPropagation(); - - return; - } - } - } - }, - - /** - Description TODO - @function - */ - handleMouseup: { - enumerable: false, - value: function(event) { - var thisRef = this, - element = event.target, - range, - offset; - - if (this._resizer) { - if (this.resizer.endUserAction(event)) { - event.preventDefault(); - event.stopPropagation(); - - return; - } - } - - if (element.tagName === "IMG") { - if (this._currentResizerElement !== element) { - this._needsShowResizerOn = element; - this.needsDraw = true; - } - } else { - if (this._resizer && this._resizer.element) { - this._needsHideResizer = true; - this.needsDraw = true; - } - - if (this._hasSelectionChangeEvent === false) { - this.handleSelectionchange(); - } - this.handleDragend(event); - } - } - }, - - /** - Description TODO - @function - */ - handleTouchstart: { - enumerable: false, - value: function() { - this.handleMousedown(event); - } - }, - - /** - Description TODO - @function - */ - handleTouchend: { - enumerable: false, - value: function() { - this.handleMouseup(event); - } - }, - - /** - Description TODO - @function - */ - handleSelectionchange: { - enumerable: false, - value: function() { - var thisRef = this, - range, - element, - hideLinkPopup = true; - - if (this._ignoreSelectionchange) { - return; - } - - if (this._hasSelectionChangeEvent == null) { - this._hasSelectionChangeEvent = true; - } - - if (this._resizer) { - if (this._selectingResizer !== true && this._resizer.element) { - this._needsHideResizer = true; - this.needsDraw = true; - } - } - - //Check if we are inside an anchor - range = this._selectedRange; - if (range && range.collapsed) { - element = range.commonAncestorContainer; - while (element && element != this._element) { - if (element.nodeName == "A") { - hideLinkPopup = false; - if (element != this._activeLink) { - this._needsActiveLinkOn = element; - this.needsDraw = true; - } - break; - } - element = element.parentElement; - } - } - if (hideLinkPopup) { - this._needsActiveLinkOn = null; - this.needsDraw = true; - } - - this._statesDirty = true; - if (this._selectionChangeTimer) { - clearTimeout(this._selectionChangeTimer); - } - this._selectionChangeTimer = setTimeout(function() { - thisRef._dispatchEditorEvent("editorSelect"); - }, 50); - } - }, - - /** - Description TODO - @function - */ - handleDragstart: { - enumerable: false, - value: function(event) { - // let's remember which element we are dragging - this._dragSourceElement = event.srcElement; - } - }, - - /** - Description TODO - @function - */ - handleDragend: { - enumerable: false, - value: function(event) { - delete this._dragSourceElement; - delete this._dragOverX; - delete this._dragOverY; - - this.handleSelectionchange(); - } - }, - - /** - Description TODO - @function - */ - handleDragover: { - enumerable: false, - value: function(event) { - var thisRef = this, - range; - - // If we are moving an element from within the ourselves, let the browser deal with it... - if (this._dragSourceElement) { - return; - } - - // JFD TODO: check if drop type is acceptable... - event.dataTransfer.dropEffect = this._allowDrop ? "copy" : "none"; - - event.preventDefault(); - event.stopPropagation(); - - // Remove the link popup - if (this._needsActiveLinkOn === false && this._activeLink) { - this._needsActiveLinkOn = null; - this.needsDraw = true; - } - - // Update the caret - if (event.x !== this._dragOverX || event.y !== this._dragOverY) { - this._dragOverX = event.x; - this._dragOverY = event.y; - - this._ignoreSelectionchange = true; - if (document.caretRangeFromPoint) { - range = document.caretRangeFromPoint(event.x, event.y); - } else if (event.rangeParent && event.rangeOffset) { - range = document.createRange(); - range.setStart(event.rangeParent, event.rangeOffset); - range.setEnd(event.rangeParent, event.rangeOffset); - } - - if (range) { - this._selectedRange = range; - } - if (this._ignoreSelectionchangeTimer) { - clearTimeout(this._ignoreSelectionchangeTimer) - } - this._ignoreSelectionchangeTimer = setTimeout(function(){ - delete thisRef._ignoreSelectionchange; - thisRef._ignoreSelectionchangeTimer = null; - }, 0); - } - } - }, - - /** - Description TODO - @function - */ - handleDrop: { - enumerable: false, - value: function(event) { - var thisRef = this, - files = event.dataTransfer.files, - fileLength = files.length, - file, - data, - reader, - i, - delegateMethod, - response; - - if (this._dragSourceElement) { - // Let the browser do the job for us, just make sure we cleanup after us - this.handleDragend(event); - this.handleSelectionchange(); - return; - } - - event.preventDefault(); - event.stopPropagation(); - - if (fileLength) { - for (i = 0; i < fileLength; i ++) { - file = files[i]; - delegateMethod = this._delegateMethod("fileDrop"); - response = true; - - if (window.FileReader) { - reader = new FileReader(); - reader.onload = function() { - data = reader.result; - - if (delegateMethod) { - response = delegateMethod.call(this.delegate, this, file, data); - } - if (response === true) { - if (file.type.match(/^image\//i)) { - document.execCommand("insertimage", false, data); - thisRef._markDirty(); - } - } - } - reader.onprogress = function(e) { - } - reader.onerror = function(e) { - } - reader.readAsDataURL(file); - } else { - // Note: This browser does not support the File API, we cannot do a preview... - if (delegateMethod) { - response = delegateMethod.call(this.delegate, this, file); - } - if (response === true) { - // TODO: for now, we do nothing, up to the consumer to deal with that case - } - } - } - } else { - data = event.dataTransfer.getData("text/html"); - if (data) { - // Sanitize Fragment (CSS & JS) - if (this._sanitizer) { - data = this._sanitizer.willInsertHTMLData(data, this._uniqueId); - } - } else { - data = event.dataTransfer.getData("text/plain") || event.dataTransfer.getData("text"); - if (data) { - var div = document.createElement('div'); - div.innerText = data; - data = div.innerHTML; - } - } - if (data) { - var delegateMethod = this._delegateMethod("drop"), - response; - - if (delegateMethod) { - response = delegateMethod.call(this.delegate, this, data, "text/html"); - if (response === true) { - data = data.replace(/\]+>/gi, ""); // Remove the meta tag. - } else { - data = response === false ? null : response ; - } - } else { - data = data.replace(/\]+>/gi, ""); // Remove the meta tag. - } - if (data && data.length) { - document.execCommand("inserthtml", false, data); - this._markDirty(); - } - } - } - this.handleDragend(event); - } - }, - - /** - Description TODO - @function - */ - handlePaste: { - enumerable: false, - value: function(event) { - var thisRef = this, - clipboardData = event.clipboardData, - data = clipboardData.getData("text/html"), - delegateMethod, - response, - div, - isHTML, - item, - file, - reader; - - /* NOTE: Chrome, and maybe the other browser too, returns html or plain text data when calling getData("text/html), - To determine if the data is actually html, check the data starts with either an html or a meta tag - */ - isHTML = data && data.match(/^(]*>|)/i); - if (data && isHTML) { - // Sanitize Fragment (CSS & JS) - if (this._sanitizer) { - data = this._sanitizer.willInsertHTMLData(data, this._uniqueId); - } - } else { - data = clipboardData.getData("text/plain") || clipboardData.getData("text"); - if (data) { - // Convert plain text to html - div = document.createElement('div'); - div.innerText = data; - data = div.innerHTML; - } - } - - if (data) { - delegateMethod = this._delegateMethod("paste"); - if (delegateMethod) { - response = delegateMethod.call(this.delegate, this, data, "text/html"); - if (response === true) { - data = data.replace(/\]+>/gi, ""); // Remove the meta tag. - } else { - data = response === false ? null : response ; - } - } else { - data = data.replace(/\]+>/gi, ""); // Remove the meta tag. - } - if (data && data.length) { - document.execCommand("inserthtml", false, data); - this._markDirty(); - } - } else { - // Maybe we have trying to paste an image as Blob... - if (clipboardData.items.length) { - item = clipboardData.items[0]; - if (item.kind == "file" && item.type.match(/^image\/.*$/)) { - file = item.getAsFile(); - - response = true; - - if (window.FileReader) { - reader = new FileReader(); - reader.onload = function() { - data = reader.result; - - this._delegateMethod("filePaste"); - if (delegateMethod) { - response = delegateMethod.call(this.delegate, this, file, data); - } - if (response === true) { - if (file.type.match(/^image\//i)) { - document.execCommand("insertimage", false, data); - thisRef._markDirty(); - } - } - } - reader.onprogress = function(e) { - } - reader.onerror = function(e) { - } - reader.readAsDataURL(file); - } else { - // Note: This browser does not support the File API, we cannot handle it directly... - if (delegateMethod) { - response = delegateMethod.call(this.delegate, this, file); - } - if (response === true) { - // TODO: for now, we do nothing, up to the consumer to deal with that case - } - } - } - } - } - - event.preventDefault(); - event.stopPropagation(); - } - }, - - /** - Description TODO - @function - @param {String} pointer TODO - @param {Component} demandingComponent TODO - @returns {Boolean} false - */ - surrenderPointer: { - value: function(pointer, demandingComponent) { - return false; - } - }, - - /** - Description TODO - @private - */ - _observePointer: { - value: function(pointer) { - this.eventManager.claimPointer(pointer, this); - this._observedPointer = pointer; - } - }, - - /** - Description TODO - @private - */ - _releaseInterest: { - value: function() { - this.eventManager.forfeitPointer(this._observedPointer, this); - this._observedPointer = null; - } - }, - - // Actions - /** - Description TODO - @function - */ - handleAction: { - enumerable: false, - value: function(event) { - var target = event.currentTarget, - action = target.action || target.identifier, - value = false; - if (action) { - if (this._actions[action].needsValue) { - value = target.actionValue; - if (value !== undefined) { - value = target[value]; - if (value === undefined) { - value = target.actionValue; - } - } else { - value = target.value; - } - - if (value === undefined) { - value = false; - } - } - this.doAction(action, value); - } - } - }, - - /** - Description TODO - @function - */ - doAction: { - enumerable: true, - value: function(action, value) { - // Check if the action is valid and enabled - if (this._actions[action] && this._actions[action].enabled === true) { - if (value === undefined) { - value = false; - } - document.execCommand(action, false, value); - - this.handleSelectionchange(); - this._markDirty(); - } - } - }, - - - // Private methods - /** - Description TODO - @private - @function - */ - _dispatchEditorEvent: { - enumerable: false, - value: function(type, value) { - var editorEvent = document.createEvent("CustomEvent"); - editorEvent.initCustomEvent(type, true, false, value === undefined ? null : value); - editorEvent.type = type; - this.dispatchEvent(editorEvent); - } - }, - - /** - Description TODO - @private - @function - */ - _markDirty: { - enumerable: false, - value: function() { - var thisRef = this, - updateValues = function() { - clearTimeout(thisRef._forceUpdateValuesTimeout); - delete thisRef._forceUpdateValuesTimeout; - clearTimeout(thisRef._updateValuesTimeout); - delete thisRef._updateValuesTimeout; - thisRef.dispatchEvent(MutableEvent.changeEvent