/* <copyright>
This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
</copyright> */
/**
@module montage/ui/component
@requires montage/core/core
@requires montage/core/event/mutable-event
@requires montage/core/bitfield
@requires montage/ui/reel
@requires montage/core/gate
@requires montage/core/logger | component
@requires montage/core/logger | drawing
@requires montage/core/event/event-manager
*/
var Montage = require("montage").Montage,
MutableEvent = require("core/event/mutable-event").MutableEvent,
BitField = require("core/bitfield").BitField,
Template = require("ui/template").Template,
Gate = require("core/gate").Gate,
logger = require("core/logger").logger("component"),
drawLogger = require("core/logger").logger("drawing"),
defaultEventManager = require("core/event/event-manager").defaultEventManager;
/**
* @class module:montage/ui/component.Component
* @classdesc Base class for all Montage components.
@extends module:montage/core/core.Montage
*/
var Component = exports.Component = Montage.create(Montage,/** @lends module:montage/ui/component.Component# */ {
/**
Description TODO
@type {Property}
@default null
*/
delegate: {
enumerable: false,
value: null
},
parentProperty: {
serializable: true,
value: "parentComponent"
},
/**
Dispatch the actionEvent this component is configured to emit upon interaction
@private
*/
_dispatchActionEvent: {
value: function() {
this.dispatchEvent(this.createActionEvent());
},
enumerable: false
},
/**
Create a custom event to dispatch upon interaction
@type {Function}
@returns and event to dispatch upon interaction
*/
createActionEvent: {
value: function() {
var actionEvent = document.createEvent("CustomEvent");
actionEvent.initCustomEvent("action", true, true, null);
actionEvent.type = "action";
return actionEvent;
}
},
/**
Description TODO
@function
@returns this._canDrawGate
*/
canDrawGate: {
get: function() {
if (!this._canDrawGate) {
this._canDrawGate = Gate.create().initWithDelegate(this);
this._canDrawGate.setField("componentTreeLoaded", false);
}
return this._canDrawGate;
}
},
/**
Description TODO
@private
*/
_blockDrawGate: {
value: null
},
/**
Description TODO
@function
@returns this._blockDrawGate
*/
blockDrawGate: {
get: function() {
if (!this._blockDrawGate) {
this._blockDrawGate = Gate.create().initWithDelegate(this);
this._blockDrawGate.setField("element", false);
this._blockDrawGate.setField("drawRequested", false);
}
return this._blockDrawGate;
}
},
/**
Description TODO
@private
*/ _firstDraw: {
enumerable: false,
value: true
},
/**
Description TODO
@private
*/
_completedFirstDraw: {
enumerable: false,
value: false
},
/**
Description TODO
@private
*/
_element: {
enumerable: false,
value: null
},
/**
Description TODO
@type {Function}
@default null
*/
element: {
serializable: true,
enumerable: true,
get: function() {
return this._element;
},
set: function(value) {
if (value == null) {
console.log("Warning: Tried to set element of ", this, " as " + value + ".");
return;
}
this.eventManager.registerEventHandlerForElement(this, value);
if (this.isDeserializing) {
// if this component has a template and has been already instantiated then assume the value is the template.
if (this._isTemplateInstantiated) {
this._templateElement = value;
} else {
this._element = value;
if (!this.blockDrawGate.value && this._element) {
this.blockDrawGate.setField("element", true);
}
}
} else {
this._element = value;
if (!this.blockDrawGate.value && this._element) {
this.blockDrawGate.setField("element", true);
}
}
}
},
// access to the Application object
/**
Description TODO
@function
@returns document.application
*/
application: {
get: function() {
return document.application;
}
},
/**
Description TODO
@function
@returns defaultEventManager
*/
eventManager: {
get: function() {
return defaultEventManager;
}
},
/**
Description TODO
@function
@returns rootComponent
*/
rootComponent: {
get: function() {
return rootComponent;
}
},
/**
Description TODO
@function
@returns {Boolean} false
*/
acceptsDirectFocus: {
enumerable: false,
value: function() {
return false;
}
},
/**
Description TODO
@function
@returns targetElementController
*/
elementControllerFromEvent: {
enumerable: false,
value: function(event, targetElementController) {
return targetElementController;
}
},
/**
Description TODO
@private
*/
_cachedParentComponent: {
value: null
},
// TODO store the value and delete it after draw
/**
The parent component is found by walking up the DOM tree from the node returned by the <i>element</i> property.<br>
If we find a parentNode that has a controller then we return this controller.<br>
Returns undefined if this is the rootComponent.
@function
@returns undefined or cachedParentComponent
*/
parentComponent: {
enumerable: false,
get: function() {
var cachedParentComponent = this._cachedParentComponent;
if (cachedParentComponent == null) {
var anElement = this.element,
aParentNode,
eventManager = this.eventManager;
if (anElement) {
while ((aParentNode = anElement.parentNode) !== null && eventManager.eventHandlerForElement(aParentNode) == null) {
anElement = aParentNode;
}
return (this._cachedParentComponent = aParentNode ? eventManager.eventHandlerForElement(aParentNode) : null);
}
} else {
return cachedParentComponent;
}
}
},
querySelectorComponent: {
value: function(selector) {
if (typeof selector !== "string") {
throw "querySelectorComponent: Selector needs to be a string.";
}
// \s*(?:@([^>\s]+)) leftHandOperand [<label>]
// \s*(>)?\s* operator [>] (if undefined it's a space)
// @([^>\s]+) rightHandOperand [<label>]
// (.*) rest
var matches = selector.match(/^\s*(?:@([^>\s]+))?(?:\s*(>)?\s*@([^>\s]+)(.*))?$/);
if (!matches) {
throw "querySelectorComponent: Syntax error \"" + selector + "\"";
}
var childComponents = this.childComponents,
leftHandOperand = matches[1],
operator = matches[2] || " ",
rightHandOperand = matches[3],
rest = matches[4],
found;
if (leftHandOperand) {
rest = rightHandOperand ? "@"+rightHandOperand + rest : "";
for (var i = 0, childComponent; (childComponent = childComponents[i]); i++) {
if (leftHandOperand === Montage.getInfoForObject(childComponent).label) {
if (rest) {
return childComponent.querySelectorComponent(rest);
} else {
return childComponent;
}
} else {
found = childCo
|