1 /**
  2  * @fileOverview responsible for un-registering event
  3  * @author yiminghe@gmail.com
  4  */
  5 KISSY.add("event/remove", function (S, Event, DOM, Utils, _data, EVENT_SPECIAL) {
  6     var isValidTarget = Utils.isValidTarget,
  7         simpleRemove = Utils.simpleRemove;
  8 
  9     S.mix(Event,
 10         /**
 11          * @lends Event
 12          */
 13         {
 14             // single target, single type, fixed native
 15             __remove:function (isNativeTarget, target, type, fn, scope) {
 16 
 17                 if (!target || (isNativeTarget && !isValidTarget(target))) {
 18                     return;
 19                 }
 20 
 21                 var typedGroups = Utils.getTypedGroups(type);
 22                 type = typedGroups[0];
 23                 var groups = typedGroups[1],
 24                     selector,
 25                     // in case type is undefined
 26                     originalFn = fn,
 27                     originalScope = scope,
 28                     hasSelector, s = EVENT_SPECIAL[type];
 29 
 30                 if (S.isObject(fn)) {
 31                     scope = fn.scope;
 32                     hasSelector = ("selector" in fn);
 33                     selector = fn.selector;
 34                     fn = fn.fn;
 35                     if (selector) {
 36                         if (s && s['delegateFix']) {
 37                             type = s['delegateFix'];
 38                         }
 39                     }
 40                 }
 41 
 42                 if (!selector) {
 43                     if (s && s['onFix']) {
 44                         type = s['onFix'];
 45                     }
 46                 }
 47 
 48                 var eventDesc = _data._data(target),
 49                     events = eventDesc && eventDesc.events,
 50                     handlers,
 51                     handler,
 52                     len,
 53                     i,
 54                     j,
 55                     t,
 56                     special = (isNativeTarget && EVENT_SPECIAL[type]) || { };
 57 
 58                 if (!events) {
 59                     return;
 60                 }
 61 
 62                 // remove all types of event
 63                 if (!type) {
 64                     for (type in events) {
 65                         if (events.hasOwnProperty(type)) {
 66                             Event.__remove(isNativeTarget,
 67                                 target, type + groups, originalFn,
 68                                 originalScope);
 69                         }
 70                     }
 71                     return;
 72                 }
 73 
 74                 var groupsRe;
 75 
 76                 if (groups) {
 77                     groupsRe = Utils.getGroupsRe(groups);
 78                 }
 79 
 80                 if ((handlers = events[type])) {
 81                     len = handlers.length;
 82                     // 移除 fn
 83                     if ((fn || hasSelector || groupsRe ) && len) {
 84                         scope = scope || target;
 85 
 86                         for (i = 0, j = 0, t = []; i < len; ++i) {
 87                             handler = handlers[i];
 88                             var handlerScope = handler.scope || target;
 89                             if (
 90                                 (scope != handlerScope) ||
 91                                     // 指定了函数,函数不相等,保留
 92                                     (fn && fn != handler.fn) ||
 93                                     // 1.没指定函数
 94                                     // 1.1 没有指定选择器,删掉 else2
 95                                     // 1.2 指定选择器,字符串为空
 96                                     // 1.2.1 指定选择器,字符串为空,待比较 handler 有选择器,删掉 else
 97                                     // 1.2.2 指定选择器,字符串为空,待比较 handler 没有选择器,保留
 98                                     // 1.3 指定选择器,字符串不为空,字符串相等,删掉 else
 99                                     // 1.4 指定选择器,字符串不为空,字符串不相等,保留
100                                     // 2.指定了函数且函数相等
101                                     // 2.1 没有指定选择器,删掉 else
102                                     // 2.2 指定选择器,字符串为空
103                                     // 2.2.1 指定选择器,字符串为空,待比较 handler 有选择器,删掉 else
104                                     // 2.2.2 指定选择器,字符串为空,待比较 handler 没有选择器,保留
105                                     // 2.3 指定选择器,字符串不为空,字符串相等,删掉  else
106                                     // 2.4 指定选择器,字符串不为空,字符串不相等,保留
107                                     (
108                                         hasSelector &&
109                                             (
110                                                 (selector && selector != handler.selector) ||
111                                                     (!selector && !handler.selector)
112                                                 )
113                                         ) ||
114 
115                                     // 指定了删除的某些组,而该 handler 不属于这些组,保留,否则删除
116                                     (groupsRe && !handler.groups.match(groupsRe))
117 
118                                 ) {
119                                 t[j++] = handler;
120                             }
121                             else {
122                                 if (handler.selector && handlers.delegateCount) {
123                                     handlers.delegateCount--;
124                                 }
125                                 if (handler.last && handlers.lastCount) {
126                                     handlers.lastCount--;
127                                 }
128                                 if (special.remove) {
129                                     special.remove.call(target, handler);
130                                 }
131                             }
132                         }
133                         t.delegateCount = handlers.delegateCount;
134                         t.lastCount = handlers.lastCount;
135                         events[type] = t;
136                         len = t.length;
137                     } else {
138                         // 全部删除
139                         len = 0;
140                     }
141 
142                     if (!len) {
143                         // remove(el, type) or fn 已移除光
144                         // dom node need to detach handler from dom node
145                         if (isNativeTarget &&
146                             (!special['tearDown'] ||
147                                 special['tearDown'].call(target) === false)) {
148                             simpleRemove(target, type, eventDesc.handler);
149                         }
150                         // remove target's single event description
151                         delete events[type];
152                     }
153                 }
154 
155                 // remove target's  all events description
156                 if (S.isEmptyObject(events)) {
157                     eventDesc.handler.target = null;
158                     delete eventDesc.handler;
159                     delete eventDesc.events;
160                     Event._removeData(target);
161                 }
162             },
163 
164             /**
165              * Detach an event or set of events from an element. similar to removeEventListener in DOM3 Events
166              * @param targets KISSY selector
167              * @param {String} [type] The type of event to remove.
168              * use space to separate multiple event types.
169              * @param {Function} [fn] The event handler/listener.
170              * @param {Object} [scope] The scope (this reference) in which the handler function is executed.
171              */
172             remove:function (targets, type, fn, scope) {
173 
174                 type = S.trim(type);
175 
176                 if (Utils.batchForType(Event.remove, targets, type, fn, scope)) {
177                     return targets;
178                 }
179 
180                 targets = DOM.query(targets);
181 
182                 for (var i = targets.length - 1; i >= 0; i--) {
183                     Event.__remove(true, targets[i], type, fn, scope);
184                 }
185 
186                 return targets;
187 
188             }
189         });
190 }, {
191     requires:['./base', 'dom', './utils', './data', './special']
192 });