-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnodeOldIE.js
197 lines (179 loc) · 6.12 KB
/
nodeOldIE.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
define(["heya-has/sniff", "heya-dom/dom", "heya-events/EventSource"],
function(has, dom, EventSource){
var major = window.ScriptEngineMajorVersion;
has.add("jscript", major && (major() + ScriptEngineMinorVersion() / 10));
has.add("event-orientationchange", has("touch") && !has("android")); // TODO: how do we detect this?
has.add("event-stopimmediatepropagation", function(global){
return global.Event && global.Event.prototype && !!global.Event.prototype.stopImmediatePropagation;
});
has.add("event-focusin", function(global, doc, element){
// All browsers except firefox support focusin, but too hard to feature test webkit since element.onfocusin
// is undefined. Just return true for IE and use fallback path for other browsers.
return !!element.attachEvent;
});
function NodeEvents(source, type, filter){
EventSource.call(this);
this.source = dom.byId(source);
this._removals = [];
if(this.source && type){
var self = this;
if(typeof type == "string"){
type.replace(/\b\w+\b/g, function(name){
self.attach(name);
return "";
});
}else if(type instanceof Array){
type.forEach(function(name){
self.attach(name);
});
}
}
if(filter){
this.micro.callback = EventSource.makeMultiplexer(this, filter);
}
}
NodeEvents.prototype = Object.create(EventSource.prototype);
NodeEvents.prototype.destroy =
NodeEvents.prototype.remove =
NodeEvents.prototype.release = function release(){
this.remove();
EventSource.prototype.release.call(this);
};
NodeEvents.prototype.attach = function(type){
if(typeof type == "function"){
return type(this);
}
var source = this.source, capture = false;
// touch events are removed because old IE do not support them
// IE will leak memory on certain handlers in frames (IE8 and earlier) and in unattached DOM nodes for JScript 5.7 and below.
// Here we use global redirection to solve the memory leaks
if(typeof _dojoIEListeners_ == "undefined"){
_dojoIEListeners_ = [];
}
var emitter = source[type];
if(!emitter || !emitter.listeners){
var oldListener = emitter;
emitter = Function("event", "var callee = arguments.callee; for(var i = 0; i < callee.listeners.length; ++i){ var listener = _dojoIEListeners_[callee.listeners[i]]; if(listener){ listener.call(this, event); } }");
emitter.listeners = [];
source[type] = emitter;
emitter._dojoIEListeners_ = _dojoIEListeners_;
if(oldListener){
emitter.listeners.push(_dojoIEListeners_.push(oldListener) - 1);
}
}
var handle;
emitter.listeners.push(handle = (emitter._dojoIEListeners_.push(listener) - 1));
this._removals.push(function(){
delete _dojoIEListeners_[handle];
});
};
NodeEvents.prototype.dispatch = function(evt){
this.micro.send(new EventSource.Value(evt));
};
NodeEvents.prototype.remove = function(){
this._removals.forEach(function(f){ f(); });
this._removals = [];
};
// utilities
var lastEvent; //TODO: why do we even need it?
function listener(evt){
if(!evt){
evt = (window && (window.ownerDocument || window.document ||
window).parentWindow || window).event;
}
if(evt){
if(evt.immediatelyStopped){
return;
}
evt.stopImmediatePropagation = stopImmediatePropagation;
try{
if(lastEvent && evt.type === lastEvent.type && evt.srcElement === lastEvent.target){
// should be same event, reuse event object (so it can be augmented);
// accessing evt.srcElement rather than evt.target since evt.target not set on IE until fixup below
evt = lastEvent;
}
}catch(e){
// will occur on IE on lastEvent.type reference if lastEvent points to a previous event that already
// finished bubbling, but the setTimeout() to clear lastEvent hasn't fired yet
}
if(!evt.target){ // check to see if it has been fixed yet
evt.target = evt.srcElement;
evt.currentTarget = (window || evt.srcElement);
if(evt.type == "mouseover"){
evt.relatedTarget = evt.fromElement;
}
if(evt.type == "mouseout"){
evt.relatedTarget = evt.toElement;
}
if(!evt.stopPropagation){
evt.stopPropagation = stopPropagation;
evt.preventDefault = preventDefault;
}
if(evt.type === "keypress"){
var c = "charCode" in evt ? evt.charCode : evt.keyCode;
switch(c){
case 10:
// CTRL-ENTER is CTRL-ASCII(10) on IE,
// but CTRL-ENTER on Mozilla
c = 0;
evt.keyCode = 13;
break;
case 13:
case 27:
// Mozilla considers ENTER and ESC non-printable
c = 0;
break;
case 3:
// Mozilla maps CTRL-BREAK to CTRL-c
c = 99;
break;
}
// Mozilla sets keyCode to 0 when there is a charCode
// but that stops the event on IE.
evt.charCode = c;
setKeyChar(evt);
}
}
}
this.dispatch(evt);
// a hack to capture the last event
if(evt.modified){
// cache the last event and reuse it if we can
if(!lastEvent){
setTimeout(function(){ lastEvent = null; }, 0); // ha-ha
}
lastEvent = evt;
}
}
function setKeyChar(evt){
evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : "";
evt.charOrCode = evt.keyChar || evt.keyCode;
}
function stopPropagation(){
this.cancelBubble = true;
}
function stopImmediatePropagation(){
this.immediatelyStopped = true;
this.modified = true; // mark it as modified so the event will be cached in IE
}
function preventDefault(){
// Setting keyCode to 0 is the only way to prevent certain keypresses (namely
// ctrl-combinations that correspond to menu accelerator keys).
// Otoh, it prevents upstream listeners from getting this information
// Try to split the difference here by clobbering keyCode only for ctrl
// combinations. If you still need to access the key upstream, bubbledKeyCode is
// provided as a workaround.
this.bubbledKeyCode = this.keyCode;
if(this.ctrlKey){
try{
// squelch errors when keyCode is read-only
// (e.g. if keyCode is ctrl or shift)
this.keyCode = 0;
}catch(e){}
}
this.defaultPrevented = true;
this.returnValue = false;
this.modified = true; // mark it as modified (for defaultPrevented flag) so the event will be cached in IE
};
return NodeEvents;
});