/**
* @private
*/
Ext.define('Ext.event.publisher.ComponentPaint', {
extend: 'Ext.event.publisher.Publisher',
targetType: 'component',
handledEvents: ['painted', 'erased'],
eventNames: {
painted: 'painted',
erased: 'erased'
},
constructor: function() {
this.callParent(arguments);
this.hiddenQueue = {};
this.renderedQueue = {};
},
getSubscribers: function(eventName, createIfNotExist) {
var subscribers = this.subscribers;
if (!subscribers.hasOwnProperty(eventName)) {
if (!createIfNotExist) {
return null;
}
subscribers[eventName] = {
$length: 0
};
}
return subscribers[eventName];
},
setDispatcher: function(dispatcher) {
var targetType = this.targetType;
dispatcher.doAddListener(targetType, '*', 'renderedchange', 'onBeforeComponentRenderedChange', this, null, 'before');
dispatcher.doAddListener(targetType, '*', 'hiddenchange', 'onBeforeComponentHiddenChange', this, null, 'before');
dispatcher.doAddListener(targetType, '*', 'renderedchange', 'onComponentRenderedChange', this, null, 'after');
dispatcher.doAddListener(targetType, '*', 'hiddenchange', 'onComponentHiddenChange', this, null, 'after');
return this.callParent(arguments);
},
subscribe: function(target, eventName) {
var match = target.match(this.idSelectorRegex),
subscribers,
id;
if (!match) {
return false;
}
id = match[1];
subscribers = this.getSubscribers(eventName, true);
if (subscribers.hasOwnProperty(id)) {
subscribers[id]++;
return true;
}
subscribers[id] = 1;
subscribers.$length++;
return true;
},
unsubscribe: function(target, eventName, all) {
var match = target.match(this.idSelectorRegex),
subscribers,
id;
if (!match || !(subscribers = this.getSubscribers(eventName))) {
return false;
}
id = match[1];
if (!subscribers.hasOwnProperty(id) || (!all && --subscribers[id] > 0)) {
return true;
}
delete subscribers[id];
if (--subscribers.$length === 0) {
delete this.subscribers[eventName];
}
return true;
},
onBeforeComponentRenderedChange: function(container, component, rendered) {
var eventNames = this.eventNames,
eventName = rendered ? eventNames.painted : eventNames.erased,
subscribers = this.getSubscribers(eventName),
queue;
if (subscribers && subscribers.$length > 0) {
this.renderedQueue[component.getId()] = queue = [];
this.publish(subscribers, component, eventName, queue);
}
},
onBeforeComponentHiddenChange: function(component, hidden) {
var eventNames = this.eventNames,
eventName = hidden ? eventNames.erased : eventNames.painted,
subscribers = this.getSubscribers(eventName),
queue;
if (subscribers && subscribers.$length > 0) {
this.hiddenQueue[component.getId()] = queue = [];
this.publish(subscribers, component, eventName, queue);
}
},
onComponentRenderedChange: function(container, component) {
var renderedQueue = this.renderedQueue,
id = component.getId(),
queue;
if (!renderedQueue.hasOwnProperty(id)) {
return;
}
queue = renderedQueue[id];
delete renderedQueue[id];
if (queue.length > 0) {
this.dispatchQueue(queue);
}
},
onComponentHiddenChange: function(component) {
var hiddenQueue = this.hiddenQueue,
id = component.getId(),
queue;
if (!hiddenQueue.hasOwnProperty(id)) {
return;
}
queue = hiddenQueue[id];
delete hiddenQueue[id];
if (queue.length > 0) {
this.dispatchQueue(queue);
}
},
dispatchQueue: function(dispatchingQueue) {
var dispatcher = this.dispatcher,
targetType = this.targetType,
eventNames = this.eventNames,
queue = dispatchingQueue.slice(),
ln = queue.length,
i, item, component, eventName, isPainted;
dispatchingQueue.length = 0;
if (ln > 0) {
for (i = 0; i < ln; i++) {
item = queue[i];
component = item.component;
eventName = item.eventName;
isPainted = component.isPainted();
if ((eventName === eventNames.painted && isPainted) || eventName === eventNames.erased && !isPainted) {
dispatcher.doDispatchEvent(targetType, '#' + item.id, eventName, [component]);
}
}
queue.length = 0;
}
},
publish: function(subscribers, component, eventName, dispatchingQueue) {
var id = component.getId(),
needsDispatching = false,
eventNames, items, i, ln, isPainted;
if (subscribers[id]) {
eventNames = this.eventNames;
isPainted = component.isPainted();
if ((eventName === eventNames.painted && !isPainted) || eventName === eventNames.erased && isPainted) {
needsDispatching = true;
}
else {
return this;
}
}
if (component.isContainer) {
items = component.getItems().items;
for (i = 0,ln = items.length; i < ln; i++) {
this.publish(subscribers, items[i], eventName, dispatchingQueue);
}
}
else if (component.isDecorator) {
this.publish(subscribers, component.getComponent(), eventName, dispatchingQueue);
}
if (needsDispatching) {
dispatchingQueue.push({
id: id,
eventName: eventName,
component: component
});
}
}
});