From 2a5484af59544a9dfdda854d707455f08a24fe69 Mon Sep 17 00:00:00 2001 From: Armen Kesablyan Date: Wed, 15 Feb 2012 14:28:21 -0800 Subject: Latest Montage Updates 0.6 Fixes Signed-off-by: Armen Kesablyan --- node_modules/montage/ui/button.reel/button.js | 206 ++-------- node_modules/montage/ui/check-input.js | 93 ++++- node_modules/montage/ui/component.js | 6 - node_modules/montage/ui/composer/composer.js | 1 - node_modules/montage/ui/composer/press-composer.js | 434 +++++++++++++++++++++ .../montage/ui/condition.reel/condition.js | 67 +++- .../montage/ui/date-input.reel/date-input.js | 20 +- node_modules/montage/ui/flow-path-cubic.js | 6 + node_modules/montage/ui/flow-path-lerp.js | 6 + node_modules/montage/ui/flow-path-linear.js | 6 + node_modules/montage/ui/flow-path-sigmoid.js | 6 + node_modules/montage/ui/flow-path.js | 6 + node_modules/montage/ui/flow.reel/flow.js | 6 + node_modules/montage/ui/native-control.js | 175 +++++---- .../ui/nearest-neighbor-component-search.js | 6 + .../montage/ui/number-input.reel/number-input.js | 9 +- .../montage/ui/radio-button.reel/radio-button.js | 19 +- .../montage/ui/range-input.reel/range-input.js | 48 ++- .../montage/ui/scroll-bars.reel/scroll-bars.js | 6 + node_modules/montage/ui/scroll.js | 6 + node_modules/montage/ui/scroller.reel/scroller.js | 6 + .../montage/ui/scrollview.reel/scrollview.js | 43 +- .../montage/ui/select-input.reel/select-input.js | 53 ++- node_modules/montage/ui/text-input.js | 109 +++--- .../montage/ui/textfield.reel/textfield.js | 5 +- .../montage/ui/toggle-button.reel/toggle-button.js | 4 +- .../ui/toggle-switch.reel/toggle-switch.css | 162 -------- .../ui/toggle-switch.reel/toggle-switch.html | 16 - .../montage/ui/toggle-switch.reel/toggle-switch.js | 424 -------------------- 29 files changed, 934 insertions(+), 1020 deletions(-) create mode 100644 node_modules/montage/ui/composer/press-composer.js delete mode 100755 node_modules/montage/ui/toggle-switch.reel/toggle-switch.css delete mode 100755 node_modules/montage/ui/toggle-switch.reel/toggle-switch.html delete mode 100644 node_modules/montage/ui/toggle-switch.reel/toggle-switch.js (limited to 'node_modules/montage/ui') diff --git a/node_modules/montage/ui/button.reel/button.js b/node_modules/montage/ui/button.reel/button.js index 51f4c011..5da92482 100644 --- a/node_modules/montage/ui/button.reel/button.js +++ b/node_modules/montage/ui/button.reel/button.js @@ -3,11 +3,13 @@ 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. */ + /*global require, exports*/ var Montage = require("montage").Montage, Component = require("ui/component").Component, - NativeControl = require("ui/native-control").NativeControl; + NativeControl = require("ui/native-control").NativeControl, + PressComposer = require("ui/composer/press-composer").PressComposer; /** - * The Text input + * The Button input */ var Button = exports.Button = Montage.create(NativeControl, { @@ -127,56 +129,25 @@ var Button = exports.Button = Montage.create(NativeControl, { } }, - // Low-level event listeners - - /** - Description TODO - @function - @param {Event} event The handleMousedown event - */ - handleMousedown: { - value: function(event) { - if (this._observedPointer !== null) { - return; - } - if (!this._disabled) { - this._startInteraction("mouse"); - } - - event.preventDefault(); - - if (!this._preventFocus) { - this._element.focus(); - } - } - }, - /** - Description TODO - @function - @param {Event} event The handleMouseup event - */ - handleMouseup: { - value: function(event) { - this._interpretInteraction(event); + prepareForActivationEvents: { + value: function() { + var pressComposer = PressComposer.create(); + this.addComposer(pressComposer); + pressComposer.addEventListener("pressstart", this, false); + pressComposer.addEventListener("press", this, false); + pressComposer.addEventListener("presscancel", this, false); } }, + // Handlers + /** - Description TODO - @function - @param {Event} event The handleTouchstart event + Called when the user starts interacting with the component. */ - handleTouchstart: { + handlePressstart: { value: function(event) { - if (this._observedPointer !== null) { - return; - } - if (!this._disabled) { - this._startInteraction(event.changedTouches[0].identifier); - } + this.active = true; - // NOTE preventingDefault disables the magnifying class - // sadly it also disables double tapping on the button to zoom... event.preventDefault(); if (!this._preventFocus) { @@ -184,142 +155,38 @@ var Button = exports.Button = Montage.create(NativeControl, { } } }, - /** - Description TODO - @function - @param {Event} event The handleTouchend event - */ - handleTouchend: { - value: function(event) { - var i = 0, changedTouchCount = event.changedTouches.length; - - for (; i < changedTouchCount; i++) { - if (event.changedTouches[i].identifier === this._observedPointer) { - this._interpretInteraction(event); - return; - } - } - } - }, /** - Description TODO - @function - @param {Event} event The handleTouchcancel event + Called when the user has interacted with the button. */ - handleTouchcancel: { + handlePress: { value: function(event) { - var i = 0, changedTouchCount = event.changedTouches.length; - - for (; i < changedTouchCount; i++) { - if (event.changedTouches[i].identifier === this._observedPointer) { - this._endInteraction(); - return; - } - } - - } - }, - - /** - If we have to surrender the pointer we are no longer active. This will - stop the action event being dispatched. - */ - surrenderPointer: { - value: function(pointer, component) { - if (pointer === this._observedPointer) { - this._endInteraction(); - } - return true; + this.active = false; + this._dispatchActionEvent(); } }, - // Internal state management - - /** - Stores the pointer that pressed down the button. Needed for multitouch. - @private - */ - _observedPointer: { - enumerable: true, - value: null - }, - - /** - Called when the user starts interacting with the component. Adds release - (touch and mouse) listeners. - @private - */ - _startInteraction: { - value: function(pointer) { - this.eventManager.claimPointer(pointer, this); - this._observedPointer = pointer; - this.active = true; - - if (window.Touch) { - document.addEventListener("touchend", this); - document.addEventListener("touchcancel", this); - } else { - document.addEventListener("mouseup", this); - } - }, - enumerable: false - }, - /** - Called when the user has interacted with the button. Decides whether to - dispatch an action event. - @private + Called when all interaction is over. */ - _interpretInteraction: { + handlePresscancel: { value: function(event) { - if (!this._active) { - return; - } - - var target = event.target; - while (target !== this.element && target && target.parentNode) { - target = target.parentNode; - } - - if (this.element === target) { - this._dispatchActionEvent(); - } - - this._endInteraction(); - }, - enumerable: false - }, - /** - Called when all interaction is over. Removes listeners. - @private - */ - _endInteraction: { - value: function() { - if (window.Touch) { - document.removeEventListener("touchend", this); - document.removeEventListener("touchcancel", this); - } else { - document.removeEventListener("mouseup", this); - } - - if (this.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) { - this.eventManager.forfeitPointer(this._observedPointer, this); - } - this._observedPointer = null; this.active = false; } }, /** - Description TODO + If this is an input element then the label is handled differently. @private */ - _isInputElement: {value: false}, + _isInputElement: { + value: false, + enumerable: false + }, - deserializedFromTemplate: { + didSetElement: { value: function() { - var o = Object.getPrototypeOf(Button).deserializedFromTemplate.call(this); + var o = NativeControl.didSetElement.call(this); this._element.classList.add("montage-button"); this._element.setAttribute("aria-role", "button"); @@ -356,20 +223,6 @@ var Button = exports.Button = Montage.create(NativeControl, { } }, - /** - Description TODO - @function - */ - prepareForActivationEvents: { - value: function() { - if (window.Touch) { - this._element.addEventListener("touchstart", this); - } else { - this._element.addEventListener("mousedown", this); - } - - } - }, /** Draws the label to the DOM. @@ -411,6 +264,7 @@ Button.addAttributes({ formmethod: null, formnovalidate: null, formtarget: null, + type: {value: 'button'}, name: null, value: null }); diff --git a/node_modules/montage/ui/check-input.js b/node_modules/montage/ui/check-input.js index 6338c42c..42538c02 100644 --- a/node_modules/montage/ui/check-input.js +++ b/node_modules/montage/ui/check-input.js @@ -3,10 +3,11 @@ 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. */ - +/*global require, exports */ var Montage = require("montage").Montage, Component = require("ui/component").Component, - NativeControl = require("ui/native-control").NativeControl; + NativeControl = require("ui/native-control").NativeControl, + PressComposer = require("ui/composer/press-composer").PressComposer; var CheckInput = exports.CheckInput = Montage.create(NativeControl, { @@ -14,33 +15,97 @@ var CheckInput = exports.CheckInput = Montage.create(NativeControl, { draw: { value: function() { // Call super - Object.getPrototypeOf(CheckInput).draw.call(this); + NativeControl.draw.call(this); this._element.setAttribute("aria-checked", this._checked); } }, + _pressComposer: { + enumerable: false, + value: null + }, + + prepareForActivationEvents: { + value: function() { + var pressComposer = this._pressComposer = PressComposer.create(); + this.addComposer(pressComposer); + pressComposer.addEventListener("pressstart", this, false); + pressComposer.addEventListener("press", this, false); + } + }, + + prepareForDraw: { + enumerable: false, + value: function() { + this._element.addEventListener('change', this); + } + }, + + + /** - Description TODO - @function + Fake the checking of the element. + + Changes the checked property of the element and dispatches a change event. + Radio button overrides this. + + @private */ - prepareForDraw: { + _fakeCheck: { enumerable: false, value: function() { - this.element.addEventListener('change', this); + var changeEvent; + // NOTE: this may be BAD, modifying the element outside of + // the draw loop, but it's what a click/touch would + // actually have done + this._element.checked = !this._element.checked; + changeEvent = document.createEvent("HTMLEvents"); + changeEvent.initEvent("change", true, true); + this._element.dispatchEvent(changeEvent); } }, -/** - Description TODO - @function - @param {Event Handler} event TODO + /** + Stores if we need to fake checking. + + When preventDefault is called on touchstart and touchend events (e.g. by + the scrollview component) the checkbox doesn't check itself, so we need + to fake it later. + + @default false + @private */ + _shouldFakeCheck: { + enumerable: false, + value: false + }, + + // Handlers + + handlePressstart: { + value: function(event) { + this._shouldFakeCheck = event.defaultPrevented; + } + }, + + + handlePress: { + value: function(event) { + if (this._shouldFakeCheck) { + this._shouldFakeCheck = false; + this._fakeCheck(); + } + } + }, + handleChange: { enumerable: false, value: function(event) { - Object.getPropertyDescriptor(this, "checked").set.call(this, - this.element.checked, true); - this._dispatchActionEvent(); + if (!this._pressComposer || this._pressComposer.state !== PressComposer.CANCELLED) { + Object.getPropertyDescriptor(this, "checked").set.call(this, + this.element.checked, true); + this._dispatchActionEvent(); + } } } }); diff --git a/node_modules/montage/ui/component.js b/node_modules/montage/ui/component.js index e41a1958..d347f655 100755 --- a/node_modules/montage/ui/component.js +++ b/node_modules/montage/ui/component.js @@ -6,7 +6,6 @@ /** @module montage/ui/component @requires montage/core/core - @requires montage/core/event/mutable-event @requires montage/ui/reel @requires montage/core/gate @requires montage/core/logger | component @@ -14,7 +13,6 @@ @requires montage/core/event/event-manager */ var Montage = require("montage").Montage, - MutableEvent = require("core/event/mutable-event").MutableEvent, Template = require("ui/template").Template, Gate = require("core/gate").Gate, logger = require("core/logger").logger("component"), @@ -441,10 +439,6 @@ var Component = exports.Component = Montage.create(Montage,/** @lends module:mon childComponents.splice(ix, 1); childComponent._cachedParentComponent = null; } - - if (element && element.parentNode) { - element.parentNode.removeChild(element); - } } }, /** diff --git a/node_modules/montage/ui/composer/composer.js b/node_modules/montage/ui/composer/composer.js index eee7be67..52027a7c 100644 --- a/node_modules/montage/ui/composer/composer.js +++ b/node_modules/montage/ui/composer/composer.js @@ -47,7 +47,6 @@ exports.Composer = Montage.create(Montage, /** @lends module:montage/ui/composer * cycle after addComposer has been called on its associated component. If * `true` loading of the composer is delayed until its associated component * has prepareForActivationEvents called. - * @property * @default false */ lazyLoad: { diff --git a/node_modules/montage/ui/composer/press-composer.js b/node_modules/montage/ui/composer/press-composer.js new file mode 100644 index 00000000..942de162 --- /dev/null +++ b/node_modules/montage/ui/composer/press-composer.js @@ -0,0 +1,434 @@ +/* + 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. +
*/ +/*global require, exports*/ +/** + @module montage/ui/composer/press-composer + @requires montage + @requires montage/ui/composer/composer +*/ +var Montage = require("montage").Montage, + Composer = require("ui/composer/composer").Composer, + MutableEvent = require("core/event/mutable-event").MutableEvent; +/** + @class module:montage/ui/composer/press-composer.PressComposer + @extends module:montage/ui/composer/composer.Composer +*/ +var PressComposer = exports.PressComposer = Montage.create(Composer,/** @lends module:montage/ui/event/composer/press-composer.PressComposer# */ { + + /** + @event + @name pressstart + @param {Event} event + + Dispatched when a press begins. It is ended by either a {@link press} or + {@link presscancel} event. + */ + + /** + @event + @name press + @param {Event} event + + Dispatched when a press is complete. + */ + + /** + @event + @name presscancel + @param {Event} event + + Dispatched when a press is canceled. This could be because the pointer + left the element, was claimed by another component or maybe a phone call + came in. + */ + + // Load/unload + + load: { + value: function() { + if (window.Touch) { + this._element.addEventListener("touchstart", this); + } else { + this._element.addEventListener("mousedown", this); + } + } + }, + + unload: { + value: function() { + if (window.Touch) { + this._element.removeEventListener("touchstart", this); + } else { + this._element.removeEventListener("mousedown", this); + } + } + }, + + UNPRESSED: { + value: 0 + }, + PRESSED: { + value: 1 + }, + CANCELLED: { + value: 2 + }, + + _state: { + enumerable: false, + value: 0 + }, + state: { + get: function() { + return this._state; + } + }, + + // Magic + + /** + @default null + @private + */ + _observedPointer: { + enumerable: false, + value: null + }, + + // TODO: maybe this should be split and moved into handleTouchstart + // and handleMousedown + _startInteraction: { + enumerable: false, + value: function(event) { + if ("disabled" in this.component && this.component.disabled) { + return false; + } + + var i = 0, changedTouchCount; + + if (event.type === "touchstart") { + changedTouchCount = event.changedTouches.length; + for (; i < changedTouchCount; i++) { + if (!this.component.eventManager.componentClaimingPointer(event.changedTouches[i].identifier)) { + this._observedPointer = event.changedTouches[i].identifier; + break; + } + } + + if (this._observedPointer === null) { + // All touches have been claimed + return false; + } + + document.addEventListener("touchend", this); + document.addEventListener("touchcancel", this); + } else if (event.type === "mousedown") { + this._observedPointer = "mouse"; + // Needed to cancel action event dispatch is mouseup'd when + // not on the component + document.addEventListener("mouseup", this); + // Needed to preventDefault if another component has claimed + // the pointer + document.addEventListener("click", this); + } + + this.component.eventManager.claimPointer(this._observedPointer, this); + + this._dispatchPressstart(event); + } + }, + + /** + Decides what should be done based on an interaction. + + @param {Event} event The event that caused this to be called. + */ + _interpretInteraction: { + value: function(event) { + // TODO maybe the code should be moved out to handleClick and + // handleMouseup + var isSurrendered, target, isTarget; + + if (this._observedPointer === null) { + this._endInteraction(event); + return; + } + + isSurrendered = !this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this); + target = event.target; + while (target !== this._element && target && target.parentNode) { + target = target.parentNode; + } + isTarget = target === this.component.element; + + if (isSurrendered && event.type === "click") { + // Pointer surrendered, so prevent the default action + event.preventDefault(); + // No need to dispatch an event as presscancel was dispatched + // in surrenderPointer, just end the interaction. + this._endInteraction(event); + return; + } + + if (!isSurrendered && isTarget && event.type === "mouseup") { + this._dispatchPress(event); + this._endInteraction(event); + return; + } + + if (!isSurrendered && !isTarget && event.type === "mouseup") { + this._dispatchPresscancel(event); + this._endInteraction(event); + return; + } + } + }, + + /** + Remove event listeners after an interaction has finished. + */ + _endInteraction: { + value: function(event) { + if (!event || event.type === "touchend" || event.type === "touchcancel") { + document.removeEventListener("touchend", this); + document.removeEventListener("touchcancel", this); + } else if (!event || event.type === "click" || event.type === "mouseup") { + document.removeEventListener("click", this); + document.removeEventListener("mouseup", this); + } + + if (this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) { + this.component.eventManager.forfeitPointer(this._observedPointer, this); + } + this._observedPointer = null; + this._state = PressComposer.UNPRESSED; + } + }, + + /** + Checks if we are observing one of the changed touches. Returns the index + of the changed touch if one matches, otherwise returns false. Make sure + to check against !== false or === false as the + matching index might be 0. + + @function + @private + @returns {Number,Boolean} The index of the matching touch, or false + */ + _changedTouchisObserved: { + value: function(changedTouches) { + if (this._observedPointer === null) { + return false; + } + + var i = 0, changedTouchCount = event.changedTouches.length; + + for (; i < changedTouchCount; i++) { + if (event.changedTouches[i].identifier === this._observedPointer) { + return i; + } + } + return false; + } + }, + + // Surrender pointer + + surrenderPointer: { + value: function(pointer, component) { + var shouldSurrender = this.callDelegateMethod("surrenderPointer", pointer, component); + if (typeof shouldSurrender !== "undefined" && shouldSurrender === false) { + return false; + } + + this._dispatchPresscancel(); + return true; + } + }, + + // Handlers + + handleTouchstart: { + value: function(event) { + this._startInteraction(event); + } + }, + handleTouchend: { + value: function(event) { + if (this._observedPointer === null) { + this._endInteraction(event); + return; + } + + if (this._changedTouchisObserved(event.changedTouches) !== false) { + if (this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) { + this._dispatchPress(event); + } else { + event.preventDefault(); + } + this._endInteraction(event); + } + } + }, + handleTouchcancel: { + value: function(event) { + if (this._observedPointer === null || this._changedTouchisObserved(event.changedTouches) !== false) { + if (this.component.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) { + this._dispatchPresscancel(event); + } + this._endInteraction(event); + } + } + }, + + handleMousedown: { + value: function(event) { + this._startInteraction(event); + } + }, + handleClick: { + value: function(event) { + this._interpretInteraction(event); + } + }, + handleMouseup: { + value: function(event) { + this._interpretInteraction(event); + } + }, + + // Event dispatch + + _createPressEvent: { + enumerable: false, + value: function(name, event) { + var pressEvent, detail, index; + + if (!event) { + event = document.createEvent("CustomEvent"); + event.initCustomEvent(name, true, true, null); + } + + pressEvent = PressEvent.create(); + pressEvent.event = event; + pressEvent.type = name; + pressEvent.pointer = this._observedPointer; + + if (event.changedTouches && + (index = this._changedTouchisObserved(event.changedTouches)) !== false + ) { + pressEvent.touch = event.changedTouches[index]; + } + + return pressEvent; + } + }, + + /** + Dispatch the pressstart event + @private + */ + _dispatchPressstart: { + enumerable: false, + value: function (event) { + this._state = PressComposer.PRESSED; + this.dispatchEvent(this._createPressEvent("pressstart", event)); + } + }, + + /** + Dispatch the press event + @private + */ + _dispatchPress: { + enumerable: false, + value: function (event) { + this.dispatchEvent(this._createPressEvent("press", event)); + this._state = PressComposer.UNPRESSED; + } + }, + + /** + Dispatch the presscancel event + @private + */ + _dispatchPresscancel: { + enumerable: false, + value: function (event) { + this._state = PressComposer.CANCELLED; + this.dispatchEvent(this._createPressEvent("presscancel", event)); + } + } + +}); + + +var PressEvent = (function(){ + var value, eventProps, typeProps, eventPropDescriptor, typePropDescriptor, i; + + value = Montage.create(Montage, { + type: { + value: "press" + }, + _event: { + enumerable: false, + value: null + }, + event: { + get: function() { + return this._event; + }, + set: function(value) { + this._event = value; + } + }, + _touch: { + enumerable: false, + value: null + }, + touch: { + get: function() { + return this._touch; + }, + set: function(value) { + this._touch = value; + } + } + }); + + // These properties are available directly on the event + eventProps = ["altKey", "ctrlKey", "metaKey", "shiftKey", + "cancelBubble", "clipboardData", "currentTarget", "defaultPrevented", + "eventPhase", "returnValue", "srcElement", "timeStamp", "preventDefault", + "stopImmediatePropagation", "stopPropagation"]; + // These properties are available on the event in the case of mouse, and + // on the _touch in the case of touch + typeProps = ["clientX", "clientY", "pageX", "pageY", "screenX", "screenY", "target"]; + + eventPropDescriptor = function(prop) { + return { + get: function() { + return this._event[prop]; + } + }; + }; + typePropDescriptor = function(prop) { + return { + get: function() { + return (this._touch) ? this._touch[prop] : this._event[prop]; + } + }; + }; + + for (i = eventProps.length - 1; i >= 0; i--) { + Montage.defineProperty(value, eventProps[i], eventPropDescriptor(eventProps[i])); + } + for (i = typeProps.length - 1; i >= 0; i--) { + Montage.defineProperty(value, typeProps[i], typePropDescriptor(typeProps[i])); + } + + return value; +}()); diff --git a/node_modules/montage/ui/condition.reel/condition.js b/node_modules/montage/ui/condition.reel/condition.js index 298edb13..e88d96a1 100755 --- a/node_modules/montage/ui/condition.reel/condition.js +++ b/node_modules/montage/ui/condition.reel/condition.js @@ -53,6 +53,13 @@ exports.Condition = Montage.create(Component, /** @lends module:"montage/ui/cond this._condition = value; this.needsDraw = true; + if (this.removalStrategy === "remove") { + if (value) { + this._slot.content = this.content; + } else { + this._slot.content = null; + } + } }, get: function() { return this._condition; @@ -83,16 +90,59 @@ exports.Condition = Montage.create(Component, /** @lends module:"montage/ui/cond this._content = value; this.needsDraw = true; + + if (this.removalStrategy === "remove") { + if (this.condition) { + this._slot.content = value; + } + } else { + this._slot.content = value; + } + } }, + /** + @private + */ + _removalStrategy:{ + value: "remove", + enumerable:false + }, + + /** + + */ // TODO should this strategy be part of another class? // TODO expose the options as an exported enum - removalStrategy: { - enumerable: false, - value: "remove" + removalStrategy:{ + get:function () { + return this._removalStrategy; + }, + set:function (value) { + if (this._removalStrategy === value) { + return; + } + if (value === "hide" || this.condition) { + // was remove OR was hide + this._slot.content = this.content; + } + this._removalStrategy = value; + } }, + /** + + @param + @returns + */ + didCreate:{ + value:function () { + this._slot = Slot.create(); + } + }, + + /** Description TODO @function @@ -117,10 +167,6 @@ exports.Condition = Montage.create(Component, /** @lends module:"montage/ui/cond var slotRoot = document.createElement("div"); this.element.appendChild(slotRoot); - this.content.parentNode.removeChild(this.content); - slotRoot.appendChild(this.content); - - this._slot = Slot.create(); this._slot.element = slotRoot; } }, @@ -133,14 +179,9 @@ exports.Condition = Montage.create(Component, /** @lends module:"montage/ui/cond value: function() { if (this.condition) { - this._slot.content = this.content; this.element.classList.remove("montage-invisible"); } else { - if ("hide" === this.removalStrategy) { - this.element.classList.add("montage-invisible"); - } else { - this._slot.content = null; - } + this.element.classList.add("montage-invisible"); } } diff --git a/node_modules/montage/ui/date-input.reel/date-input.js b/node_modules/montage/ui/date-input.reel/date-input.js index af163258..0d8ff613 100644 --- a/node_modules/montage/ui/date-input.reel/date-input.js +++ b/node_modules/montage/ui/date-input.reel/date-input.js @@ -10,22 +10,10 @@ var Montage = require("montage").Montage, * The Component wrapper for input type="date" */ var DateInput = exports.DateInput = Montage.create(TextInput, { - hasTemplate: {value: true} }); DateInput.addAttributes({ - autocomplete: null, - disabled: {dataType: 'boolean'}, - list: null, // list of autocomplete options - max: null, - maxlength: null, - min: null, - multiple: null, - name: null, - pattern: null, - placeholder: null, - readonly: {dataType: 'boolean'}, - required: {dataType: 'boolean'}, - size: null, - src: null -}); + max: null, + min: null, + step: null // 'any' or a floating point number +}); \ No newline at end of file diff --git a/node_modules/montage/ui/flow-path-cubic.js b/node_modules/montage/ui/flow-path-cubic.js index a4be0dbe..ec4c6600 100644 --- a/node_modules/montage/ui/flow-path-cubic.js +++ b/node_modules/montage/ui/flow-path-cubic.js @@ -1,3 +1,9 @@ +/* + 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. +
*/ + var Montage = require("montage").Montage; var FlowPathCubic = exports.FlowPathCubic = Montage.create(Montage, { diff --git a/node_modules/montage/ui/flow-path-lerp.js b/node_modules/montage/ui/flow-path-lerp.js index b88fee39..bc550500 100644 --- a/node_modules/montage/ui/flow-path-lerp.js +++ b/node_modules/montage/ui/flow-path-lerp.js @@ -1,3 +1,9 @@ +/* + 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. +
*/ + var Montage = require("montage").Montage; var FlowPathLerp = exports.FlowPathLerp = Montage.create(Montage, { diff --git a/node_modules/montage/ui/flow-path-linear.js b/node_modules/montage/ui/flow-path-linear.js index b95ddb92..9bf83279 100644 --- a/node_modules/montage/ui/flow-path-linear.js +++ b/node_modules/montage/ui/flow-path-linear.js @@ -1,3 +1,9 @@ +/* + 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. +
*/ + var Montage = require("montage").Montage; var FlowPathLinear = exports.FlowPathLinear = Montage.create(Montage, { diff --git a/node_modules/montage/ui/flow-path-sigmoid.js b/node_modules/montage/ui/flow-path-sigmoid.js index 2e776b5a..5f161544 100644 --- a/node_modules/montage/ui/flow-path-sigmoid.js +++ b/node_modules/montage/ui/flow-path-sigmoid.js @@ -1,3 +1,9 @@ +/* + 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. +
*/ + var Montage = require("montage").Montage; var FlowPathSigmoid = exports.FlowPathSigmoid = Montage.create(Montage, { diff --git a/node_modules/montage/ui/flow-path.js b/node_modules/montage/ui/flow-path.js index ecb1d8fa..51ecd63c 100644 --- a/node_modules/montage/ui/flow-path.js +++ b/node_modules/montage/ui/flow-path.js @@ -1,3 +1,9 @@ +/* + 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. +
*/ + var Montage = require("montage").Montage; var FlowPath = exports.FlowPath = Montage.create(Montage, { diff --git a/node_modules/montage/ui/flow.reel/flow.js b/node_modules/montage/ui/flow.reel/flow.js index 21556e41..f1311292 100644 --- a/node_modules/montage/ui/flow.reel/flow.js +++ b/node_modules/montage/ui/flow.reel/flow.js @@ -1,3 +1,9 @@ +/* + 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. +
*/ + var Montage = require("montage").Montage, Component = require("ui/component").Component; diff --git a/node_modules/montage/ui/native-control.js b/node_modules/montage/ui/native-control.js index d3c3a635..d308ad89 100644 --- a/node_modules/montage/ui/native-control.js +++ b/node_modules/montage/ui/native-control.js @@ -11,48 +11,31 @@ var isUndefined = function(obj) { return (typeof obj === 'undefined'); }; -var extend = function(destination, source) { - for (var property in source) { - destination[property] = source[property]; - } - return destination; -}; - -var STRING_CLASS = '[object String]'; -var _toString = Object.prototype.toString; -var isString = function(object) { - return _toString.call(object) === STRING_CLASS; -}; /** * Base component for all native controls. */ -exports.NativeControl = Montage.create(Component, { +var NativeControl = exports.NativeControl = Montage.create(Component, { hasTemplate: { value: false }, - //http://www.w3.org/TR/html5/elements.html#global-attributes - _baseElementProperties: { - value: { - accesskey: null, - contenteditable: null, // true, false, inherit - contextmenu: null, - 'class': null, - dir: null, - draggable: {dataType: 'boolean'}, - dropzone: null, // copy/move/link - hidden: {dataType: 'boolean'}, - //id: null, - lang: null, - spellcheck: null, - style: null, - tabindex: null, - title: null + element: { + serializable: true, + enumerable: true, + get: function() { + return this._element; + }, + set: function(value) { + //var component = Object.getPrototypeOf(NativeControl); + // call super set + Object.getPropertyDescriptor(Component, "element").set.call(this, value); + this.didSetElement(); } }, + /** Stores values that need to be set on the element. Cleared each draw * cycle. */ @@ -64,11 +47,30 @@ exports.NativeControl = Montage.create(Component, { /** Stores the descriptors of the properties that can be set on this * control */ - _propertyDescriptors: { + + _elementAttributeDescriptors: { value: {}, distinct: true }, + + _getElementAttributeDescriptor: { + value: function(attributeName) { + var attributeDescriptor, instance = this; + // walk up the prototype chain from the instance to NativeControl's prototype + while(instance && !isUndefined(instance._elementAttributeDescriptors)) { + attributeDescriptor = instance._elementAttributeDescriptors[attributeName]; + if(attributeDescriptor) { + break; + } else { + instance = Object.getPrototypeOf(instance); + } + } + + return attributeDescriptor; + } + }, + /** * Add a property to this Component. A default getter/setter is provided and a * "_" property is created by default. Eg: if the property is "title", "_title" is @@ -86,7 +88,8 @@ exports.NativeControl = Montage.create(Component, { return function(value) { var attrName = '_' + name; - var desc = this._propertyDescriptors[name]; + var desc = this._getElementAttributeDescriptor(name, this); + // if requested dataType is boolean (eg: checked, readonly etc) // coerce the value to boolean if(desc && "boolean" === desc.dataType) { @@ -121,64 +124,56 @@ exports.NativeControl = Montage.create(Component, { * Add the specified properties as properties of this Component */ addAttributes: { - value: function(props) { - var i, desc, prop, obj; - var standardAttributes = {}; - standardAttributes = extend(standardAttributes, this._baseElementProperties); - standardAttributes = extend(standardAttributes, props); - - this._propertyDescriptors = standardAttributes; + value: function(properties) { + var i, descriptor, property, object; + this._elementAttributeDescriptors = properties; - for(prop in standardAttributes) { - if(standardAttributes.hasOwnProperty(prop)) { - obj = standardAttributes[prop]; + for(property in properties) { + if(properties.hasOwnProperty(property)) { + object = properties[property]; // Make sure that the descriptor is of the correct form. - if(obj === null || isString(obj)) { - desc = {value: obj, dataType: "string"}; - standardAttributes[prop] = desc; + if(object === null || String.isString(object)) { + descriptor = {value: object, dataType: "string"}; + properties[property] = descriptor; } else { - desc = obj; + descriptor = object; } - // Only add the internal prop, and getter and setter if + // Only add the internal property, and getter and setter if // they don't already exist. - if(isUndefined(this[prop])) { - this.defineAttribute(prop, desc); + if(isUndefined(this[property])) { + this.defineAttribute(property, descriptor); } } } } }, - deserializedFromTemplate: { + didSetElement: { value: function() { // The element is now ready, so we can read the attributes that // have been set on it. - var attrs = this.element.attributes || []; - var i=0, len = attrs.length, name, value, d, desc; + var attributes = this.element.attributes || []; + var i=0, length = attributes.length, name, value, attributeName, descriptor, textContent; - for(i=0; i< len; i++) { - name = attrs[i].name; - value = attrs[i].value; + for(i=0; i< length; i++) { + name = attributes[i].name; + value = attributes[i].value; if(isUndefined(this._elementAttributeValues[name])) { this._elementAttributeValues[name] = value; - // since deserializedFromTemplate is called *after* the initial binding - // is done, override the values only if a value does not already exist - if(isUndefined(this[name]) || this[name] === null) { + if(isUndefined(this[name]) || this[name] == null) { this[name] = value; } } } // check if this element has textContent - var textContent = this.element.textContent; + textContent = this.element.textContent; // set textContent only if it is defined as part of element properties if(('textContent' in this) && textContent && ("" !== textContent)) { if(isUndefined(this._elementAttributeValues['textContent'])) { this._elementAttributeValues['textContent'] = textContent; - // since deserializedFromTemplate is called *after* the initial binding - // is done, override the values only if a value does not already exist if(isUndefined(this['textContent']) || this['textContent'] === null) { this['textContent'] = textContent; } @@ -187,10 +182,10 @@ exports.NativeControl = Montage.create(Component, { // Set defaults for any properties that weren't serialised or set // as attributes on the element. - for (d in this._propertyDescriptors) { - desc = this._propertyDescriptors[d]; - if (this["_"+d] === null && desc !== null && "value" in desc) { - this["_"+d] = this._propertyDescriptors[d].value; + for (attributeName in this._elementAttributeDescriptors) { + descriptor = this._elementAttributeDescriptors[attributeName]; + if (this["_"+attributeName] === null && descriptor !== null && "value" in descriptor) { + this["_"+attributeName] = this._elementAttributeDescriptors[attributeName].value; } } @@ -201,30 +196,30 @@ exports.NativeControl = Montage.create(Component, { draw: { enumerable: false, value: function() { - var el = this.element, desc; + var element = this.element, descriptor; - for(var i in this._elementAttributeValues) { - if(this._elementAttributeValues.hasOwnProperty(i)) { - if(i === 'value') { + for(var attributeName in this._elementAttributeValues) { + if(this._elementAttributeValues.hasOwnProperty(attributeName)) { + if(attributeName === 'value') { continue; } - var val = this[i]; - desc = this._propertyDescriptors[i]; - if(desc && desc.dataType === 'boolean') { - if(val === true) { - el[i] = true; - el.setAttribute(i, i.toLowerCase()); + var value = this[attributeName]; + descriptor = this._getElementAttributeDescriptor(attributeName, this); + if(descriptor && descriptor.dataType === 'boolean') { + if(value === true) { + element[attributeName] = true; + element.setAttribute(attributeName, attributeName.toLowerCase()); } else { - el[i] = false; - el.removeAttribute(i); + element[attributeName] = false; + element.removeAttribute(attributeName); } } else { - if(!isUndefined(val) && val !== null) { - if(i === 'textContent') { - el.textContent = val; + if(!isUndefined(value)) { + if(attributeName === 'textContent') { + element.textContent = value; } else { //https://developer.mozilla.org/en/DOM/element.setAttribute - el.setAttribute(i, val); + element.setAttribute(attributeName, value); } } @@ -238,3 +233,21 @@ exports.NativeControl = Montage.create(Component, { } } }); + +//http://www.w3.org/TR/html5/elements.html#global-attributes +NativeControl.addAttributes({ + accesskey: null, + contenteditable: null, // true, false, inherit + contextmenu: null, + 'class': null, + dir: null, + draggable: null, + dropzone: null, // copy/move/link + hidden: {dataType: 'boolean'}, + //id: null, + lang: null, + spellcheck: null, + style: null, + tabindex: null, + title: null +}); diff --git a/node_modules/montage/ui/nearest-neighbor-component-search.js b/node_modules/montage/ui/nearest-neighbor-component-search.js index 209d25f8..6ba155ea 100644 --- a/node_modules/montage/ui/nearest-neighbor-component-search.js +++ b/node_modules/montage/ui/nearest-neighbor-component-search.js @@ -1,3 +1,9 @@ +/* + 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. +
*/ + var Montage = require("montage").Montage; var NearestNeighborComponentSearch = exports.NearestNeighborComponentSearch = Montage.create(Montage, { diff --git a/node_modules/montage/ui/number-input.reel/number-input.js b/node_modules/montage/ui/number-input.reel/number-input.js index b5fd0a66..dfd7235f 100644 --- a/node_modules/montage/ui/number-input.reel/number-input.js +++ b/node_modules/montage/ui/number-input.reel/number-input.js @@ -5,8 +5,7 @@ */ var Montage = require("montage").Montage, Component = require("ui/component").Component, - TextInput = require("ui/text-input").TextInput, - StandardInputAttributes = require("ui/text-input").StandardInputAttributes; + TextInput = require("ui/text-input").TextInput; /** * The Number input */ @@ -14,4 +13,8 @@ var NumberInput = exports.NumberInput = Montage.create(TextInput, { }); -NumberInput.addAttributes(StandardInputAttributes); +NumberInput.addAttributes({ + max: {dataType: 'number'}, + min: {dataType: 'number'}, + step: null // number or 'any' +}); diff --git a/node_modules/montage/ui/radio-button.reel/radio-button.js b/node_modules/montage/ui/radio-button.reel/radio-button.js index 8468ee21..9fe43336 100755 --- a/node_modules/montage/ui/radio-button.reel/radio-button.js +++ b/node_modules/montage/ui/radio-button.reel/radio-button.js @@ -10,6 +10,23 @@ var Montage = require("montage").Montage, * The Text input */ var RadioButton = exports.RadioButton = Montage.create(CheckInput, { + _fakeCheck: { + enumerable: false, + value: function() { + var changeEvent; + // NOTE: this may be BAD, modifying the element outside of + // the draw loop, but it's what a click/touch would + // actually have done + + if (!this._element.checked) { + this._element.checked = true; + changeEvent = document.createEvent("HTMLEvents"); + changeEvent.initEvent("change", true, true); + this._element.dispatchEvent(changeEvent); + } + } + }, + _checkedSyncedWithInputField: { enumerable: false, value: false @@ -75,7 +92,7 @@ var RadioButton = exports.RadioButton = Montage.create(CheckInput, { } // Call super - var fn = Object.getPrototypeOf(RadioButton).draw.call(this); + Object.getPrototypeOf(RadioButton).draw.call(this); } } }); diff --git a/node_modules/montage/ui/range-input.reel/range-input.js b/node_modules/montage/ui/range-input.reel/range-input.js index 0c247603..e97c2de9 100644 --- a/node_modules/montage/ui/range-input.reel/range-input.js +++ b/node_modules/montage/ui/range-input.reel/range-input.js @@ -3,22 +3,54 @@ 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. */ +/*global require,exports */ var Montage = require("montage").Montage, Component = require("ui/component").Component, - TextInput = require("ui/text-input").TextInput; + TextInput = require("ui/text-input").TextInput, + PressComposer = require("ui/composer/press-composer").PressComposer; + /** * The input type="range" field */ var RangeInput = exports.RangeInput = Montage.create(TextInput, { + prepareForActivationEvents: { + value: function() { + var pressComposer = PressComposer.create(); + pressComposer.delegate = this; + this.addComposer(pressComposer); + pressComposer.addEventListener("pressstart", this, false); + pressComposer.addEventListener("press", this, false); + pressComposer.addEventListener("presscancel", this, false); + } + }, + + handlePressstart: { + value: function(e) { + var interactionStartEvent = document.createEvent("CustomEvent"); + interactionStartEvent.initCustomEvent("montage_range_interaction_start", true, true, null); + this.dispatchEvent(interactionStartEvent); + } + }, + + handlePress: { + value: function(e) { + var interactionEndEvent = document.createEvent("CustomEvent"); + interactionEndEvent.initCustomEvent("montage_range_interaction_end", true, true, null); + this.dispatchEvent(interactionEndEvent); + } + }, + surrenderPointer: { + value: function(pointer, composer) { + // If the user is sliding us then we do not want anyone using + // the pointer + return false; + } + } }); RangeInput.addAttributes({ - disabled: {dataType: 'boolean'}, - max: null, - min: null, - name: null, - readonly: {dataType: 'boolean'}, - required: {dataType: 'boolean'}, - step: null + max: {dataType: 'number'}, + min: {dataType: 'number'}, + step: null // number or 'any' }); diff --git a/node_modules/montage/ui/scroll-bars.reel/scroll-bars.js b/node_modules/montage/ui/scroll-bars.reel/scroll-bars.js index 4a954399..4db27941 100644 --- a/node_modules/montage/ui/scroll-bars.reel/scroll-bars.js +++ b/node_modules/montage/ui/scroll-bars.reel/scroll-bars.js @@ -1,3 +1,9 @@ +/* + 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. +
*/ + var Montage = require("montage").Montage, Component = require("ui/component").Component; diff --git a/node_modules/montage/ui/scroll.js b/node_modules/montage/ui/scroll.js index 3126ae1c..bf1ea7f2 100755 --- a/node_modules/montage/ui/scroll.js +++ b/node_modules/montage/ui/scroll.js @@ -1,3 +1,9 @@ +/* + 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. +
*/ + var Montage = require("montage").Montage, defaultEventManager = require("core/event/event-manager").defaultEventManager; diff --git a/node_modules/montage/ui/scroller.reel/scroller.js b/node_modules/montage/ui/scroller.reel/scroller.js index 32df2906..2dfff059 100644 --- a/node_modules/montage/ui/scroller.reel/scroller.js +++ b/node_modules/montage/ui/scroller.reel/scroller.js @@ -1,3 +1,9 @@ +/* + 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. +
*/ + var Montage = require("montage").Montage, Component = require("ui/component").Component TranslateComposer = require("ui/composer/translate-composer").TranslateComposer; diff --git a/node_modules/montage/ui/scrollview.reel/scrollview.js b/node_modules/montage/ui/scrollview.reel/scrollview.js index 389b1858..3ac195e8 100755 --- a/node_modules/montage/ui/scrollview.reel/scrollview.js +++ b/node_modules/montage/ui/scrollview.reel/scrollview.js @@ -20,6 +20,19 @@ var Scrollview = exports.Scrollview = Montage.create(Component, /** @lends modul enumerable: false, value: false }, + + /** + These elements perform some native action when clicked/touched and so we + should not preventDefault when a mousedown/touchstart happens on them. + @private + */ + _NATIVE_ELEMENTS: { + value: ["A", "IFRAME", "EMBED", "OBJECT", "VIDEO", "AUDIO", "CANVAS", + "LABEL", "INPUT", "BUTTON", "SELECT", "TEXTAREA", "KEYGEN", + "DETAILS", "COMMAND" + ] + }, + /** Description TODO @private @@ -356,6 +369,19 @@ var Scrollview = exports.Scrollview = Montage.create(Component, /** @lends modul enumerable: false, value: null }, + + /** + Returns if we should preventDefault on a touchstart/mousedown event. + @param {Event} The event + @returns {Boolean} Whether preventDefault should be called + @private + */ + _shouldPreventDefault: { + value: function(event) { + return !!event.target.tagName && Scrollview._NATIVE_ELEMENTS.indexOf(event.target.tagName) === -1 && !event.target.isContentEditable; + } + }, + /** Description TODO @function @@ -364,13 +390,7 @@ var Scrollview = exports.Scrollview = Montage.create(Component, /** @lends modul captureMousedown: { enumerable: false, value: function (event) { - - // TODO this is a bit of a temporary workaround to ensure that we allow input fields - //to receive the mousedown that gives them focus and sets the cursor a the mousedown coordinates - if (!(event.target.tagName && - ("INPUT" === event.target.tagName || "SELECT" === event.target.tagName || "TEXTAREA" === event.target.tagName)) && - !event.target.isContentEditable) { - + if (this._shouldPreventDefault(event)) { event.preventDefault(); } @@ -458,8 +478,9 @@ var Scrollview = exports.Scrollview = Montage.create(Component, /** @lends modul captureTouchstart: { enumerable: false, value: function (event) { - - event.preventDefault(); + if (this._shouldPreventDefault(event)) { + event.preventDefault(); + } // If already scrolling the scrollview, ignore any new touchstarts if (this._observedPointer !== null && this.eventManager.isPointerClaimedByComponent(this._observedPointer, this)) { @@ -482,7 +503,9 @@ var Scrollview = exports.Scrollview = Montage.create(Component, /** @lends modul if (!this.eventManager.componentClaimingPointer(this._observedPointer)) { if (event.targetTouches.length === 1) { - event.preventDefault(); + if (this._shouldPreventDefault(event)) { + event.preventDefault(); + } this.eventManager.claimPointer(this._observedPointer, this); this._start(event.targetTouches[0].clientX, event.targetTouches[0].clientY); diff --git a/node_modules/montage/ui/select-input.reel/select-input.js b/node_modules/montage/ui/select-input.reel/select-input.js index 76de1a5a..09a064d4 100644 --- a/node_modules/montage/ui/select-input.reel/select-input.js +++ b/node_modules/montage/ui/select-input.reel/select-input.js @@ -7,14 +7,8 @@ var Montage = require("montage").Montage, Component = require("ui/component").Component, ArrayController = require("ui/controller/array-controller").ArrayController, - NativeControl = require("ui/native-control").NativeControl; - -var STRING_CLASS = '[object String]'; -var _toString = Object.prototype.toString; - -var isString = function(object) { - return _toString.call(object) === STRING_CLASS; -}; + NativeControl = require("ui/native-control").NativeControl, + PressComposer = require("ui/composer/press-composer").PressComposer; var SelectInput = exports.SelectInput = Montage.create(NativeControl, { @@ -154,9 +148,6 @@ var SelectInput = exports.SelectInput = Montage.create(NativeControl, { deserializedFromTemplate: { value: function() { - // @todo - Need a better way to do this. - var fn = Object.getPrototypeOf(SelectInput).deserializedFromTemplate; - fn.call(this); /* 1) If