/
i-bem-dom__events_type_bem.js
125 lines (108 loc) · 3.9 KB
/
i-bem-dom__events_type_bem.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/**
* @module i-bem-dom__events_type_bem
*/
modules.define(
'i-bem-dom__events_type_bem',
[
'i-bem-dom__events',
'i-bem__internal',
'inherit',
'functions',
'jquery',
'identify',
'events'
],
function(
provide,
bemDomEvents,
bemInternal,
inherit,
functions,
$,
identify,
events) {
var EVENT_PREFIX = '__bem__',
MOD_CHANGE_EVENT = 'modchange',
specialEvents = $.event.special,
specialEventsStorage = {},
createSpecialEvent = function(event) {
return {
setup : function() {
specialEventsStorage[event] || (specialEventsStorage[event] = true);
},
teardown : functions.noop
};
},
eventBuilder = function(e, params) {
var event = EVENT_PREFIX + params.bindEntityCls.getEntityName() +
(typeof e === 'object'?
e instanceof events.Event?
e.type :
bemInternal.buildModPostfix(e.modName, e.modVal) :
e);
specialEvents[event] ||
(specialEvents[event] = createSpecialEvent(event));
return event;
},
/**
* @class EventManagerFactory
* @augments i-bem-dom__events:EventManagerFactory
* @exports i-bem-dom__events_type_bem:EventManagerFactory
*/
EventManagerFactory = inherit(bemDomEvents.EventManagerFactory,/** @lends EventManagerFactory.prototype */{
/** @override */
_createEventManager : function(ctx, params, isInstance) {
function wrapperFn(fn, fnCtx, fnId) {
return function(e, data, flags, originalEvent) {
if(flags.fns[fnId]) return;
var instance,
instanceDomElem;
if(isInstance) {
instance = ctx;
instanceDomElem = instance.domElem;
} else {
// TODO: we could optimize all these "closest" to a single traversing
instanceDomElem = $(e.target).closest(params.ctxSelector);
instanceDomElem.length && (instance = instanceDomElem.bem(ctx));
}
if(instance &&
(!flags.propagationStoppedDomNode ||
!$.contains(instanceDomElem[0], flags.propagationStoppedDomNode))) {
originalEvent.data = e.data;
// TODO: do we really need both target and bemTarget?
originalEvent.bemTarget = originalEvent.target;
flags.fns[fnId] = true;
fn.call(fnCtx || instance, originalEvent, data);
if(originalEvent.isPropagationStopped()) {
e.stopPropagation();
flags.propagationStoppedDomNode = instanceDomElem[0];
}
}
};
}
return new this._eventManagerCls(params, wrapperFn, eventBuilder);
}
});
provide({
/**
* @param {BemDomEntity} ctx
* @param {String|Object|events:Event} e Event name
* @param {Object} [data]
*/
emit : function(ctx, e, data) {
var originalEvent;
if(typeof e === 'string') {
originalEvent = new events.Event(e, ctx);
} else if(e.modName) {
originalEvent = new events.Event(MOD_CHANGE_EVENT, ctx);
} else if(!e.target) {
e.target = ctx;
originalEvent = e;
}
var event = eventBuilder(e, { bindEntityCls : ctx.__self });
specialEventsStorage[event] &&
ctx.domElem.trigger(event, [data, { fns : {}, propagationStoppedDomNode : null }, originalEvent]);
},
EventManagerFactory : EventManagerFactory
});
});