|
1 /** |
|
2 * EditorObservable.js |
|
3 * |
|
4 * Copyright, Moxiecode Systems AB |
|
5 * Released under LGPL License. |
|
6 * |
|
7 * License: http://www.tinymce.com/license |
|
8 * Contributing: http://www.tinymce.com/contributing |
|
9 */ |
|
10 |
|
11 /** |
|
12 * This mixin contains the event logic for the tinymce.Editor class. |
|
13 * |
|
14 * @mixin tinymce.EditorObservable |
|
15 * @extends tinymce.util.Observable |
|
16 */ |
|
17 define("tinymce/EditorObservable", [ |
|
18 "tinymce/util/Observable", |
|
19 "tinymce/dom/DOMUtils", |
|
20 "tinymce/util/Tools" |
|
21 ], function(Observable, DOMUtils, Tools) { |
|
22 var DOM = DOMUtils.DOM, customEventRootDelegates; |
|
23 |
|
24 /** |
|
25 * Returns the event target so for the specified event. Some events fire |
|
26 * only on document, some fire on documentElement etc. This also handles the |
|
27 * custom event root setting where it returns that element instead of the body. |
|
28 * |
|
29 * @private |
|
30 * @param {tinymce.Editor} editor Editor instance to get event target from. |
|
31 * @param {String} eventName Name of the event for example "click". |
|
32 * @return {Element/Document} HTML Element or document target to bind on. |
|
33 */ |
|
34 function getEventTarget(editor, eventName) { |
|
35 if (eventName == 'selectionchange') { |
|
36 return editor.getDoc(); |
|
37 } |
|
38 |
|
39 // Need to bind mousedown/mouseup etc to document not body in iframe mode |
|
40 // Since the user might click on the HTML element not the BODY |
|
41 if (!editor.inline && /^mouse|click|contextmenu|drop|dragover|dragend/.test(eventName)) { |
|
42 return editor.getDoc().documentElement; |
|
43 } |
|
44 |
|
45 // Bind to event root instead of body if it's defined |
|
46 if (editor.settings.event_root) { |
|
47 if (!editor.eventRoot) { |
|
48 editor.eventRoot = DOM.select(editor.settings.event_root)[0]; |
|
49 } |
|
50 |
|
51 return editor.eventRoot; |
|
52 } |
|
53 |
|
54 return editor.getBody(); |
|
55 } |
|
56 |
|
57 /** |
|
58 * Binds a event delegate for the specified name this delegate will fire |
|
59 * the event to the editor dispatcher. |
|
60 * |
|
61 * @private |
|
62 * @param {tinymce.Editor} editor Editor instance to get event target from. |
|
63 * @param {String} eventName Name of the event for example "click". |
|
64 */ |
|
65 function bindEventDelegate(editor, eventName) { |
|
66 var eventRootElm = getEventTarget(editor, eventName), delegate; |
|
67 |
|
68 if (!editor.delegates) { |
|
69 editor.delegates = {}; |
|
70 } |
|
71 |
|
72 if (editor.delegates[eventName]) { |
|
73 return; |
|
74 } |
|
75 |
|
76 if (editor.settings.event_root) { |
|
77 if (!customEventRootDelegates) { |
|
78 customEventRootDelegates = {}; |
|
79 editor.editorManager.on('removeEditor', function() { |
|
80 var name; |
|
81 |
|
82 if (!editor.editorManager.activeEditor) { |
|
83 if (customEventRootDelegates) { |
|
84 for (name in customEventRootDelegates) { |
|
85 editor.dom.unbind(getEventTarget(editor, name)); |
|
86 } |
|
87 |
|
88 customEventRootDelegates = null; |
|
89 } |
|
90 } |
|
91 }); |
|
92 } |
|
93 |
|
94 if (customEventRootDelegates[eventName]) { |
|
95 return; |
|
96 } |
|
97 |
|
98 delegate = function(e) { |
|
99 var target = e.target, editors = editor.editorManager.editors, i = editors.length; |
|
100 |
|
101 while (i--) { |
|
102 var body = editors[i].getBody(); |
|
103 |
|
104 if (body === target || DOM.isChildOf(target, body)) { |
|
105 if (!editors[i].hidden) { |
|
106 editors[i].fire(eventName, e); |
|
107 } |
|
108 } |
|
109 } |
|
110 }; |
|
111 |
|
112 customEventRootDelegates[eventName] = delegate; |
|
113 DOM.bind(eventRootElm, eventName, delegate); |
|
114 } else { |
|
115 delegate = function(e) { |
|
116 if (!editor.hidden) { |
|
117 editor.fire(eventName, e); |
|
118 } |
|
119 }; |
|
120 |
|
121 DOM.bind(eventRootElm, eventName, delegate); |
|
122 editor.delegates[eventName] = delegate; |
|
123 } |
|
124 } |
|
125 |
|
126 var EditorObservable = { |
|
127 /** |
|
128 * Bind any pending event delegates. This gets executed after the target body/document is created. |
|
129 * |
|
130 * @private |
|
131 */ |
|
132 bindPendingEventDelegates: function() { |
|
133 var self = this; |
|
134 |
|
135 Tools.each(self._pendingNativeEvents, function(name) { |
|
136 bindEventDelegate(self, name); |
|
137 }); |
|
138 }, |
|
139 |
|
140 /** |
|
141 * Toggles a native event on/off this is called by the EventDispatcher when |
|
142 * the first native event handler is added and when the last native event handler is removed. |
|
143 * |
|
144 * @private |
|
145 */ |
|
146 toggleNativeEvent: function(name, state) { |
|
147 var self = this; |
|
148 |
|
149 if (self.settings.readonly) { |
|
150 return; |
|
151 } |
|
152 |
|
153 // Never bind focus/blur since the FocusManager fakes those |
|
154 if (name == "focus" || name == "blur") { |
|
155 return; |
|
156 } |
|
157 |
|
158 if (state) { |
|
159 if (self.initialized) { |
|
160 bindEventDelegate(self, name); |
|
161 } else { |
|
162 if (!self._pendingNativeEvents) { |
|
163 self._pendingNativeEvents = [name]; |
|
164 } else { |
|
165 self._pendingNativeEvents.push(name); |
|
166 } |
|
167 } |
|
168 } else if (self.initialized) { |
|
169 self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]); |
|
170 delete self.delegates[name]; |
|
171 } |
|
172 }, |
|
173 |
|
174 /** |
|
175 * Unbinds all native event handlers that means delegates, custom events bound using the Events API etc. |
|
176 * |
|
177 * @private |
|
178 */ |
|
179 unbindAllNativeEvents: function() { |
|
180 var self = this, name; |
|
181 |
|
182 if (self.delegates) { |
|
183 for (name in self.delegates) { |
|
184 self.dom.unbind(getEventTarget(self, name), name, self.delegates[name]); |
|
185 } |
|
186 |
|
187 delete self.delegates; |
|
188 } |
|
189 |
|
190 if (!self.inline) { |
|
191 self.getBody().onload = null; |
|
192 self.dom.unbind(self.getWin()); |
|
193 self.dom.unbind(self.getDoc()); |
|
194 } |
|
195 |
|
196 self.dom.unbind(self.getBody()); |
|
197 self.dom.unbind(self.getContainer()); |
|
198 } |
|
199 }; |
|
200 |
|
201 EditorObservable = Tools.extend({}, Observable, EditorObservable); |
|
202 |
|
203 return EditorObservable; |
|
204 }); |