Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TIMOB-10464] Event bubbling architecture changes #3623

Merged
merged 12 commits into from
Jan 10, 2013
224 changes: 167 additions & 57 deletions mobileweb/titanium/Ti/UI.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
/*global Ti define window document navigator instrumentation*/
define(
["Ti/_", "Ti/_/Evented", "Ti/_/has", "Ti/_/lang", "Ti/_/ready", "Ti/_/style", "Ti/_/dom"],
function(_, Evented, has, lang, ready, style, dom) {
['Ti/_', 'Ti/_/Evented', 'Ti/_/has', 'Ti/_/lang', 'Ti/_/ready', 'Ti/_/style', 'Ti/_/dom', 'Ti/_/event',
'Ti/_/Gestures/DoubleTap', 'Ti/_/Gestures/Dragging', 'Ti/_/Gestures/LongPress', 'Ti/_/Gestures/Pinch', 'Ti/_/Gestures/SingleTap',
'Ti/_/Gestures/Swipe', 'Ti/_/Gestures/TouchCancel', 'Ti/_/Gestures/TouchEnd', 'Ti/_/Gestures/TouchMove',
'Ti/_/Gestures/TouchStart', 'Ti/_/Gestures/TwoFingerTap'],
function(_, Evented, has, lang, ready, style, dom, event,
DoubleTap, Dragging, LongPress, Pinch, SingleTap, Swipe, TouchCancel, TouchEnd, TouchMove, TouchStart, TwoFingerTap) {

var global = window,
doc = document,
body = doc.body,
on = require.on,
modules = "2DMatrix,ActivityIndicator,AlertDialog,Animation,Button,EmailDialog,ImageView,Label,OptionDialog,Picker,PickerColumn,PickerRow,ProgressBar,ScrollableView,ScrollView,Slider,Switch,Tab,TabGroup,TableView,TableViewRow,TableViewSection,TextArea,TextField,View,WebView,Window",
is = require.is,
modules = '2DMatrix,ActivityIndicator,AlertDialog,Animation,Button,EmailDialog,ImageView,Label,OptionDialog,Picker,PickerColumn,PickerRow,ProgressBar,ScrollableView,ScrollView,Slider,Switch,Tab,TabGroup,TableView,TableViewRow,TableViewSection,TextArea,TextField,View,WebView,Window',
creators = {},
setStyle = style.set,
handheld = navigator.userAgent.toLowerCase().match(/(iphone|android)/),
iphone = handheld && handheld[0] === "iphone",
iphone = handheld && handheld[0] === 'iphone',
targetHeight = {},
hidingAddressBar,
finishAddressBar = function() {
Expand All @@ -20,23 +26,36 @@ define(
hideAddressBar = finishAddressBar,
splashScreen,
unitize = dom.unitize,
Gesture;

on(body, "touchmove", function(e) {
Gesture,
recognizers = [
TouchStart,
TouchEnd,
TouchMove,
TouchCancel,
Dragging,
SingleTap,
DoubleTap,
LongPress,
Pinch,
Swipe,
TwoFingerTap
];

on(body, 'touchmove', function(e) {
e.preventDefault();
});

modules.split(',').forEach(function(name) {
creators['create' + name] = function(args) {
return new (require("Ti/UI/" + name))(args);
return new (require('Ti/UI/' + name))(args);
};
});

if (!navigator.standalone && handheld) {
hideAddressBar = function() {
if (!hidingAddressBar) {
hidingAddressBar = 1;
var isPortrait = require("Ti/Gesture").isPortrait | 0,
var isPortrait = require('Ti/Gesture').isPortrait | 0,
h = targetHeight[isPortrait],
timer;

Expand All @@ -52,7 +71,7 @@ define(
targetHeight[isPortrait] = h;
}

setStyle(body, "height", h + "px");
setStyle(body, 'height', h + 'px');

if (iphone) {
global.scrollTo(0, 0);
Expand All @@ -67,33 +86,35 @@ define(
}, 50);
}
}
}
};
ready(hideAddressBar);
on(global, "orientationchange", hideAddressBar);
on(global, "touchstart", hideAddressBar);
on(global, 'orientationchange', hideAddressBar);
on(global, 'touchstart', hideAddressBar);
}

ready(10, function() {
setTimeout(function() {
var container = (Ti.UI._container = Ti.UI.createView({
var container = Ti.UI._container = Ti.UI.createView({
left: 0,
top: 0
})),
}),
node = container.domNode,
coefficients = container._layoutCoefficients;
coefficients = container._layoutCoefficients,
useTouch = 'ontouchstart' in global,
touching = 0;

coefficients.width.x1 = 1;
coefficients.height.x1 = 1;
container._measuredTop = 0;
container._measuredLeft = 0;
node.id = "TiUIContainer";
setStyle(node, "overflow", "hidden");
node.id = 'TiUIContainer';
setStyle(node, 'overflow', 'hidden');
body.appendChild(node);

(splashScreen = doc.getElementById("splash")) && container.addEventListener("postlayout", function(){
(splashScreen = doc.getElementById('splash')) && container.addEventListener('postlayout', function(){
setTimeout(function(){
setStyle(splashScreen,{
position: "absolute",
position: 'absolute',
width: unitize(container._measuredWidth),
height: unitize(container._measuredHeight),
left: 0,
Expand All @@ -104,14 +125,66 @@ define(
}, 10);
});
hideAddressBar();

function processTouchEvent(eventType, evt) {
var i = 0, len = recognizers.length,
j,
events = [],
results,
recognizer,
elements = evt._elements;

if (elements && elements.length) {
// Convert mouse* events to touch* events
useTouch || require.mix(evt, {
touches: evt.type === 'mouseup' ? [] : [evt],
targetTouches: [],
changedTouches: [evt]
});

// Calculate the set of gesture events
for (; i < len; i++) {
recognizer = recognizers[i]['process' + eventType];
if (recognizer) {
results = recognizer(evt, elements);
for(j in results) {
events[j] || (events[j] = []);
events[j] = events[j].concat(results[j]);
}
}
}

// Fire the events
Ti.UI._fireGestureEvents(events, elements);
}
}

on(node, useTouch ? 'touchstart' : 'mousedown', function(evt){
var handles = [
on(global, useTouch ? 'touchmove' : 'mousemove', function(evt){
(useTouch || touching) && processTouchEvent('TouchMoveEvent', evt);
}),
on(global, useTouch ? 'touchend' : 'mouseup', function(evt){
touching = 0;
processTouchEvent('TouchEndEvent', evt);
event.off(handles);
}),
useTouch && on(global, 'touchcancel', function(evt){
processTouchEvent('TouchCancelEvent', evt);
event.off(handles);
})
];
touching = 1;
processTouchEvent('TouchStartEvent', evt);
});
}, 1);
});

on(global, "resize", function() {
on(global, 'resize', function() {
Ti.UI._recalculateLayout();
});

return lang.setObject("Ti.UI", Evented, creators, {
return lang.setObject('Ti.UI', Evented, creators, {

_addWindow: function(win, set) {
this._container.add(win.modal ? win._modalParentContainer : win);
Expand All @@ -132,6 +205,44 @@ define(
return win;
},

_fireGestureEvents: function(events, elements) {
var i = 0, len = recognizers.length,
j,
x, y, pt,
sourceIndex = 0,
e;

// Fire the events
while(elements[sourceIndex] && !elements[sourceIndex]._isPublished) {
sourceIndex++;
}
elements[sourceIndex] || (sourceIndex = 0);
for (i in events) {
for (j = 0, len = events[i].length; j < len; j++) {

// Create the event object with proper relative locations, etc
e = events[i][j];
if (is(e.x, 'Number') && is(e.y, 'Number')) {
pt = this._container.convertPointToView({
x: e.x,
y: e.y
}, elements[sourceIndex]);
x = pt ? pt.x : e.x;
y = pt ? pt.y : e.y;
} else {
x = y = void 0;
}
e.x = x;
e.y = y;
e.bubbles = true;
e.cancelBubble = false; // We use true and false here instead of 0 and 1 because they are user facing

// Fire the event
elements[0].fireEvent(i, e);
}
}
},

_layoutSemaphore: 0,

_nodesToLayout: [],
Expand Down Expand Up @@ -175,7 +286,7 @@ define(
j,
len = nodes.length;

has("ti-instrumentation") && (self._layoutInstrumentationTest = instrumentation.startTest("Layout"));
has('ti-instrumentation') && (self._layoutInstrumentationTest = instrumentation.startTest('Layout'));

// Determine which nodes need to be re-layed out
for (i = 0; i < len; i++) {
Expand All @@ -189,7 +300,7 @@ define(
children = node._children;
for (j in children) {
child = children[j];
if (node.layout !== "composite" || child._needsMeasuring || node._layout._isDependentOnParent(child)) {
if (node.layout !== 'composite' || child._needsMeasuring || node._layout._isDependentOnParent(child)) {
recursionStack.push(child);
}
}
Expand Down Expand Up @@ -222,7 +333,7 @@ define(
children = node._children;
for (j in children) {
child = children[j];
if (child !== previousParent && (node.layout !== "composite" || child._needsMeasuring || node._layout._isDependentOnParent(child))) {
if (child !== previousParent && (node.layout !== 'composite' || child._needsMeasuring || node._layout._isDependentOnParent(child))) {
child._markedForLayout = true;
recursionStack.push(child);
}
Expand All @@ -239,20 +350,19 @@ define(

// Layout all nodes that need it
if (layoutRootNode) {
var container = self._container,
props = container.properties.__values__,
var props = container.properties.__values__,
width = container._measuredWidth = props.width = global.innerWidth,
height = container._measuredHeight = props.height = global.innerHeight;
container._measuredSandboxWidth = width;
container._measuredSandboxHeight = height;
container.fireEvent("postlayout");
container.fireEvent('postlayout');
setStyle(container.domNode, {
width: width + "px",
height: height + "px"
width: width + 'px',
height: height + 'px'
});
container._layout._doLayout(container, width, height, false, false);
}
for (var i in rootNodesToLayout) {
for (i = 0; i < rootNodesToLayout.length; i++) {
node = rootNodesToLayout[i];
node._layout._doLayout(node,
node._measuredWidth - node._borderLeftWidth - node._borderRightWidth,
Expand All @@ -261,14 +371,14 @@ define(
node._parent._layout._getHeight(node, node.height) === Ti.UI.SIZE);
}

has("ti-instrumentation") && instrumentation.stopTest(self._layoutInstrumentationTest,
self._elementLayoutCount + " out of approximately " + document.getElementById("TiUIContainer").getElementsByTagName("*").length + " elements laid out.");
has('ti-instrumentation') && instrumentation.stopTest(self._layoutInstrumentationTest,
self._elementLayoutCount + ' out of approximately ' + document.getElementById('TiUIContainer').getElementsByTagName('*').length + ' elements laid out.');

self._layoutInProgress = false;
self._layoutTimer = null;
self._nodesToLayout = [];
self.fireEvent("postlayout");

self.fireEvent('postlayout');
}

if (force) {
Expand All @@ -282,7 +392,7 @@ define(
},

_recalculateLayout: function() {
Gesture || (Gesture = require("Ti/Gesture"));
Gesture || (Gesture = require('Ti/Gesture'));
Gesture._updateOrientation();
var container = this._container;
if (container) {
Expand All @@ -299,7 +409,7 @@ define(
},
backgroundImage: {
set: function(value) {
return setStyle(body, "backgroundImage", value ? style.url(value) : "");
return setStyle(body, 'backgroundImage', value ? style.url(value) : '');
}
},
currentTab: void 0
Expand Down Expand Up @@ -357,35 +467,35 @@ define(
RETURNKEY_SEARCH: 8, // Search
RETURNKEY_SEND: 9, // Send
RETURNKEY_YAHOO: 10, // Search
TEXT_ALIGNMENT_CENTER: "center",
TEXT_ALIGNMENT_RIGHT: "right",
TEXT_ALIGNMENT_LEFT: "left",
TEXT_ALIGNMENT_CENTER: 'center',
TEXT_ALIGNMENT_RIGHT: 'right',
TEXT_ALIGNMENT_LEFT: 'left',
TEXT_AUTOCAPITALIZATION_ALL: 3,
TEXT_AUTOCAPITALIZATION_NONE: 0,
TEXT_AUTOCAPITALIZATION_SENTENCES: 2,
TEXT_AUTOCAPITALIZATION_WORDS: 1,
TEXT_VERTICAL_ALIGNMENT_BOTTOM: "bottom",
TEXT_VERTICAL_ALIGNMENT_CENTER: "center",
TEXT_VERTICAL_ALIGNMENT_TOP: "top",
TEXT_VERTICAL_ALIGNMENT_BOTTOM: 'bottom',
TEXT_VERTICAL_ALIGNMENT_CENTER: 'center',
TEXT_VERTICAL_ALIGNMENT_TOP: 'top',
ANIMATION_CURVE_EASE_IN: 1,
ANIMATION_CURVE_EASE_IN_OUT: 0,
ANIMATION_CURVE_EASE_OUT: 2,
ANIMATION_CURVE_LINEAR: 3,
SIZE: "auto",
FILL: "fill",
INHERIT: "inherit",
UNIT_PX: "px",
UNIT_MM: "mm",
UNIT_CM: "cm",
UNIT_IN: "in",
UNIT_DIP: "dp", // We don't have DIPs, so we treat them as pixels
SIZE: 'auto',
FILL: 'fill',
INHERIT: 'inherit',
UNIT_PX: 'px',
UNIT_MM: 'mm',
UNIT_CM: 'cm',
UNIT_IN: 'in',
UNIT_DIP: 'dp', // We don't have DIPs, so we treat them as pixels

// Hidden constants
_LAYOUT_COMPOSITE: "composite",
_LAYOUT_VERTICAL: "vertical",
_LAYOUT_HORIZONTAL: "horizontal",
_LAYOUT_CONSTRAINING_VERTICAL: "constrainingVertical",
_LAYOUT_CONSTRAINING_HORIZONTAL: "constrainingHorizontal"
_LAYOUT_COMPOSITE: 'composite',
_LAYOUT_VERTICAL: 'vertical',
_LAYOUT_HORIZONTAL: 'horizontal',
_LAYOUT_CONSTRAINING_VERTICAL: 'constrainingVertical',
_LAYOUT_CONSTRAINING_HORIZONTAL: 'constrainingHorizontal'
}

});
Expand Down
2 changes: 1 addition & 1 deletion mobileweb/titanium/Ti/UI/Label.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ define(["Ti/_/declare", "Ti/_/UI/FontWidget", "Ti/_/dom", "Ti/_/css", "Ti/_/styl

_setText: function() {
this._textContainerDomNode.innerHTML = this._getText();
this._hasSizeDimensions() && this._triggerLayout();
this._triggerLayout();
},

_setTextShadow: function() {
Expand Down