Ext.define('Ext.ux.event.Player', {
extend: 'Ext.ux.event.Driver',
keyFrameEvents: {
click: true
},
pauseForAnimations: true,
speed: 1.0,
stallTime: 0,
tagPathRegEx: /(\w+)(?:\[(\d+)\])?/,
constructor: function (config) {
var me = this;
me.callParent(arguments);
me.addEvents(
'beforeplay',
'keyframe'
);
me.eventObject = new Ext.EventObjectImpl();
me.timerFn = function () {
me.onTick();
};
me.attachTo = me.attachTo || window;
},
getElementFromXPath: function (xpath) {
var me = this,
parts = xpath.split('/'),
regex = me.tagPathRegEx,
i, n, m, count, tag, child,
el = me.attachTo.document;
el = (parts[0] == '~') ? el.body
: el.getElementById(parts[0].substring(1));
for (i = 1, n = parts.length; el && i < n; ++i) {
m = regex.exec(parts[i]);
count = m[2] ? parseInt(m[2], 10) : 1;
tag = m[1].toUpperCase();
for (child = el.firstChild; child; child = child.nextSibling) {
if (child.tagName == tag) {
if (count == 1) {
break;
}
--count;
}
}
el = child;
}
return el;
},
getTimeIndex: function () {
var t = this.getTimestamp() - this.stallTime;
return t * this.speed;
},
makeToken: function (eventDescriptor, signal) {
var me = this,
t0;
eventDescriptor[signal] = true;
eventDescriptor.defer = function () {
eventDescriptor[signal] = false;
t0 = me.getTime();
};
eventDescriptor.finish = function () {
eventDescriptor[signal] = true;
me.stallTime += me.getTime() - t0;
me.schedule();
};
},
nextEvent: function (eventDescriptor) {
var me = this,
index = ++me.queueIndex;
if (me.keyFrameEvents[eventDescriptor.type]) {
Ext.Array.insert(me.eventQueue, index, [
{ keyframe: true, ts: eventDescriptor.ts }
]);
}
},
peekEvent: function () {
var me = this,
queue = me.eventQueue,
index = me.queueIndex,
eventDescriptor = queue[index],
type = eventDescriptor && eventDescriptor.type,
tmp;
if (type == 'mduclick') {
tmp = [
Ext.applyIf({ type: 'mousedown' }, eventDescriptor),
Ext.applyIf({ type: 'mouseup' }, eventDescriptor),
Ext.applyIf({ type: 'click' }, eventDescriptor)
];
me.replaceEvent(index, tmp);
}
return queue[index] || null;
},
replaceEvent: function (index, events) {
for (var t, i = 0, n = events.length; i < n; ++i) {
if (i) {
t = events[i-1];
delete t.afterplay;
delete t.screenshot;
delete events[i].beforeplay;
}
}
Ext.Array.replace(this.eventQueue, index, 1, events);
},
processEvents: function () {
var me = this,
animations = me.pauseForAnimations && me.attachTo.Ext.fx.Manager.items,
eventDescriptor;
while ((eventDescriptor = me.peekEvent()) !== null) {
if (animations && animations.getCount()) {
return true;
}
if (eventDescriptor.keyframe) {
if (!me.processKeyFrame(eventDescriptor)) {
return false;
}
me.nextEvent(eventDescriptor);
} else if (eventDescriptor.ts <= me.getTimeIndex() &&
me.fireEvent('beforeplay', me, eventDescriptor) !== false &&
me.playEvent(eventDescriptor)) {
if(window.__x && eventDescriptor.screenshot) {
__x.poll.sendSyncRequest({cmd: 'screenshot'});
}
me.nextEvent(eventDescriptor);
} else {
return true;
}
}
me.stop();
return false;
},
processKeyFrame: function (eventDescriptor) {
var me = this;
if (!eventDescriptor.defer) {
me.makeToken(eventDescriptor, 'done');
me.fireEvent('keyframe', me, eventDescriptor);
}
return eventDescriptor.done;
},
injectEvent: function (target, event) {
event.injectEvent(target);
},
playEvent: function (eventDescriptor) {
var me = this,
target = me.getElementFromXPath(eventDescriptor.target),
event;
if (!target) {
return false;
}
if (!me.playEventHook(eventDescriptor, 'beforeplay')) {
return false;
}
if (!eventDescriptor.injected) {
eventDescriptor.injected = true;
event = me.translateEvent(eventDescriptor, target);
me.injectEvent(target, event);
}
return me.playEventHook(eventDescriptor, 'afterplay');
},
playEventHook: function (eventDescriptor, hookName) {
var me = this,
doneName = hookName + '.done',
firedName = hookName + '.fired',
hook = eventDescriptor[hookName];
if (hook && !eventDescriptor[doneName]) {
if (!eventDescriptor[firedName]) {
eventDescriptor[firedName] = true;
me.makeToken(eventDescriptor, doneName);
me.eventScope[hook](eventDescriptor);
}
return false;
}
return true;
},
schedule: function () {
var me = this;
if (!me.timer) {
me.timer = setTimeout(me.timerFn, 10);
}
},
translateEvent: function (eventDescriptor, target) {
var me = this,
event = me.eventObject,
modKeys = eventDescriptor.modKeys || '',
xy;
if ('x' in eventDescriptor) {
event.xy = xy = Ext.fly(target).getXY();
xy[0] += eventDescriptor.x;
xy[1] += eventDescriptor.y;
}
if ('wheel' in eventDescriptor) {
}
event.type = eventDescriptor.type;
event.button = eventDescriptor.button;
event.altKey = modKeys.indexOf('A') > 0;
event.ctrlKey = modKeys.indexOf('C') > 0;
event.metaKey = modKeys.indexOf('M') > 0;
event.shiftKey = modKeys.indexOf('S') > 0;
return event;
},
onStart: function () {
var me = this;
me.queueIndex = 0;
me.schedule();
},
onStop: function () {
var me = this;
if (me.timer) {
clearTimeout(me.timer);
me.timer = null;
}
if (window.__x) {
__x.poll.sendSyncRequest({cmd: 'finish'});
}
},
onTick: function () {
var me = this;
me.timer = null;
if (me.processEvents()) {
me.schedule();
}
}
});