17 * |
17 * |
18 * Unsupported things: |
18 * Unsupported things: |
19 * - No editor.onEvent |
19 * - No editor.onEvent |
20 * - Can't cancel execCommands with beforeExecCommand |
20 * - Can't cancel execCommands with beforeExecCommand |
21 */ |
21 */ |
22 (function(tinymce) { |
22 (function (tinymce) { |
23 var reported; |
23 var reported; |
24 |
24 |
25 function noop() { |
25 function noop() { |
26 } |
26 } |
27 |
27 |
28 function log(apiCall) { |
28 function log(apiCall) { |
29 if (!reported && window && window.console) { |
29 if (!reported && window && window.console) { |
30 reported = true; |
30 reported = true; |
31 console.log("Deprecated TinyMCE API call: " + apiCall); |
31 console.log("Deprecated TinyMCE API call: " + apiCall); |
32 } |
32 } |
33 } |
33 } |
34 |
34 |
35 function Dispatcher(target, newEventName, argsMap, defaultScope) { |
35 function Dispatcher(target, newEventName, argsMap, defaultScope) { |
36 target = target || this; |
36 target = target || this; |
37 |
37 var cbs = []; |
38 if (!newEventName) { |
38 |
39 this.add = this.addToTop = this.remove = this.dispatch = noop; |
39 if (!newEventName) { |
40 return; |
40 this.add = this.addToTop = this.remove = this.dispatch = noop; |
41 } |
41 return; |
42 |
42 } |
43 this.add = function(callback, scope, prepend) { |
43 |
44 log('<target>.on' + newEventName + ".add(..)"); |
44 this.add = function (callback, scope, prepend) { |
45 |
45 log('<target>.on' + newEventName + ".add(..)"); |
46 // Convert callback({arg1:x, arg2:x}) -> callback(arg1, arg2) |
46 |
47 function patchedEventCallback(e) { |
47 // Convert callback({arg1:x, arg2:x}) -> callback(arg1, arg2) |
48 var callbackArgs = []; |
48 function patchedEventCallback(e) { |
49 |
49 var callbackArgs = []; |
50 if (typeof argsMap == "string") { |
50 |
51 argsMap = argsMap.split(" "); |
51 if (typeof argsMap == "string") { |
52 } |
52 argsMap = argsMap.split(" "); |
53 |
53 } |
54 if (argsMap && typeof argsMap != "function") { |
54 |
55 for (var i = 0; i < argsMap.length; i++) { |
55 if (argsMap && typeof argsMap !== "function") { |
56 callbackArgs.push(e[argsMap[i]]); |
56 for (var i = 0; i < argsMap.length; i++) { |
57 } |
57 callbackArgs.push(e[argsMap[i]]); |
58 } |
58 } |
59 |
59 } |
60 if (typeof argsMap == "function") { |
60 |
61 callbackArgs = argsMap(newEventName, e, target); |
61 if (typeof argsMap == "function") { |
62 if (!callbackArgs) { |
62 callbackArgs = argsMap(newEventName, e, target); |
63 return; |
63 if (!callbackArgs) { |
64 } |
64 return; |
65 } |
65 } |
66 |
66 } |
67 if (!argsMap) { |
67 |
68 callbackArgs = [e]; |
68 if (!argsMap) { |
69 } |
69 callbackArgs = [e]; |
70 |
70 } |
71 callbackArgs.unshift(defaultScope || target); |
71 |
72 |
72 callbackArgs.unshift(defaultScope || target); |
73 if (callback.apply(scope || defaultScope || target, callbackArgs) === false) { |
73 |
74 e.stopImmediatePropagation(); |
74 if (callback.apply(scope || defaultScope || target, callbackArgs) === false) { |
75 } |
75 e.stopImmediatePropagation(); |
76 } |
76 } |
77 |
77 } |
78 target.on(newEventName, patchedEventCallback, prepend); |
78 |
79 |
79 target.on(newEventName, patchedEventCallback, prepend); |
80 return patchedEventCallback; |
80 |
81 }; |
81 var handlers = { |
82 |
82 original: callback, |
83 this.addToTop = function(callback, scope) { |
83 patched: patchedEventCallback |
84 this.add(callback, scope, true); |
84 }; |
85 }; |
85 |
86 |
86 cbs.push(handlers); |
87 this.remove = function(callback) { |
87 return patchedEventCallback; |
88 return target.off(newEventName, callback); |
88 }; |
89 }; |
89 |
90 |
90 this.addToTop = function (callback, scope) { |
91 this.dispatch = function() { |
91 this.add(callback, scope, true); |
92 target.fire(newEventName); |
92 }; |
93 |
93 |
94 return true; |
94 this.remove = function (callback) { |
95 }; |
95 cbs.forEach(function (item, i) { |
96 } |
96 if (item.original === callback) { |
97 |
97 cbs.splice(i, 1); |
98 tinymce.util.Dispatcher = Dispatcher; |
98 return target.off(newEventName, item.patched); |
99 tinymce.onBeforeUnload = new Dispatcher(tinymce, "BeforeUnload"); |
99 } |
100 tinymce.onAddEditor = new Dispatcher(tinymce, "AddEditor", "editor"); |
100 }); |
101 tinymce.onRemoveEditor = new Dispatcher(tinymce, "RemoveEditor", "editor"); |
101 |
102 |
102 return target.off(newEventName, callback); |
103 tinymce.util.Cookie = { |
103 }; |
104 get: noop, getHash: noop, remove: noop, set: noop, setHash: noop |
104 |
105 }; |
105 this.dispatch = function () { |
106 |
106 target.fire(newEventName); |
107 function patchEditor(editor) { |
107 return true; |
108 function patchEditorEvents(oldEventNames, argsMap) { |
108 }; |
109 tinymce.each(oldEventNames.split(" "), function(oldName) { |
109 } |
110 editor["on" + oldName] = new Dispatcher(editor, oldName, argsMap); |
110 |
111 }); |
111 tinymce.util.Dispatcher = Dispatcher; |
112 } |
112 tinymce.onBeforeUnload = new Dispatcher(tinymce, "BeforeUnload"); |
113 |
113 tinymce.onAddEditor = new Dispatcher(tinymce, "AddEditor", "editor"); |
114 function convertUndoEventArgs(type, event, target) { |
114 tinymce.onRemoveEditor = new Dispatcher(tinymce, "RemoveEditor", "editor"); |
115 return [ |
115 |
116 event.level, |
116 tinymce.util.Cookie = { |
117 target |
117 get: noop, getHash: noop, remove: noop, set: noop, setHash: noop |
118 ]; |
118 }; |
119 } |
119 |
120 |
120 function patchEditor(editor) { |
121 function filterSelectionEvents(needsSelection) { |
121 |
122 return function(type, e) { |
122 function translate(str) { |
123 if ((!e.selection && !needsSelection) || e.selection == needsSelection) { |
123 var prefix = editor.settings.language || "en"; |
124 return [e]; |
124 var prefixedStr = [prefix, str].join('.'); |
125 } |
125 var translatedStr = tinymce.i18n.translate(prefixedStr); |
126 }; |
126 |
127 } |
127 return prefixedStr !== translatedStr ? translatedStr : tinymce.i18n.translate(str); |
128 |
128 } |
129 if (editor.controlManager) { |
129 |
130 return; |
130 function patchEditorEvents(oldEventNames, argsMap) { |
131 } |
131 tinymce.each(oldEventNames.split(" "), function (oldName) { |
132 |
132 editor["on" + oldName] = new Dispatcher(editor, oldName, argsMap); |
133 function cmNoop() { |
133 }); |
134 var obj = {}, methods = 'add addMenu addSeparator collapse createMenu destroy displayColor expand focus ' + |
134 } |
135 'getLength hasMenus hideMenu isActive isCollapsed isDisabled isRendered isSelected mark ' + |
135 |
136 'postRender remove removeAll renderHTML renderMenu renderNode renderTo select selectByIndex ' + |
136 function convertUndoEventArgs(type, event, target) { |
137 'setActive setAriaProperty setColor setDisabled setSelected setState showMenu update'; |
137 return [ |
138 |
138 event.level, |
139 log('editor.controlManager.*'); |
139 target |
140 |
140 ]; |
141 function _noop() { |
141 } |
142 return cmNoop(); |
142 |
143 } |
143 function filterSelectionEvents(needsSelection) { |
144 |
144 return function (type, e) { |
145 tinymce.each(methods.split(' '), function(method) { |
145 if ((!e.selection && !needsSelection) || e.selection == needsSelection) { |
146 obj[method] = _noop; |
146 return [e]; |
147 }); |
147 } |
148 |
148 }; |
149 return obj; |
149 } |
150 } |
150 |
151 |
151 if (editor.controlManager) { |
152 editor.controlManager = { |
152 return; |
153 buttons: {}, |
153 } |
154 |
154 |
155 setDisabled: function(name, state) { |
155 function cmNoop() { |
156 log("controlManager.setDisabled(..)"); |
156 var obj = {}, methods = 'add addMenu addSeparator collapse createMenu destroy displayColor expand focus ' + |
157 |
157 'getLength hasMenus hideMenu isActive isCollapsed isDisabled isRendered isSelected mark ' + |
158 if (this.buttons[name]) { |
158 'postRender remove removeAll renderHTML renderMenu renderNode renderTo select selectByIndex ' + |
159 this.buttons[name].disabled(state); |
159 'setActive setAriaProperty setColor setDisabled setSelected setState showMenu update'; |
160 } |
160 |
161 }, |
161 log('editor.controlManager.*'); |
162 |
162 |
163 setActive: function(name, state) { |
163 function _noop() { |
164 log("controlManager.setActive(..)"); |
164 return cmNoop(); |
165 |
165 } |
166 if (this.buttons[name]) { |
166 |
167 this.buttons[name].active(state); |
167 tinymce.each(methods.split(' '), function (method) { |
168 } |
168 obj[method] = _noop; |
169 }, |
169 }); |
170 |
170 |
171 onAdd: new Dispatcher(), |
171 return obj; |
172 onPostRender: new Dispatcher(), |
172 } |
173 |
173 |
174 add: function(obj) { |
174 editor.controlManager = { |
175 return obj; |
175 buttons: {}, |
176 }, |
176 |
177 createButton: cmNoop, |
177 setDisabled: function (name, state) { |
178 createColorSplitButton: cmNoop, |
178 log("controlManager.setDisabled(..)"); |
179 createControl: cmNoop, |
179 |
180 createDropMenu: cmNoop, |
180 if (this.buttons[name]) { |
181 createListBox: cmNoop, |
181 this.buttons[name].disabled(state); |
182 createMenuButton: cmNoop, |
182 } |
183 createSeparator: cmNoop, |
183 }, |
184 createSplitButton: cmNoop, |
184 |
185 createToolbar: cmNoop, |
185 setActive: function (name, state) { |
186 createToolbarGroup: cmNoop, |
186 log("controlManager.setActive(..)"); |
187 destroy: noop, |
187 |
188 get: noop, |
188 if (this.buttons[name]) { |
189 setControlType: cmNoop |
189 this.buttons[name].active(state); |
190 }; |
190 } |
191 |
191 }, |
192 patchEditorEvents("PreInit BeforeRenderUI PostRender Load Init Remove Activate Deactivate", "editor"); |
192 |
193 patchEditorEvents("Click MouseUp MouseDown DblClick KeyDown KeyUp KeyPress ContextMenu Paste Submit Reset"); |
193 onAdd: new Dispatcher(), |
194 patchEditorEvents("BeforeExecCommand ExecCommand", "command ui value args"); // args.terminate not supported |
194 onPostRender: new Dispatcher(), |
195 patchEditorEvents("PreProcess PostProcess LoadContent SaveContent Change"); |
195 |
196 patchEditorEvents("BeforeSetContent BeforeGetContent SetContent GetContent", filterSelectionEvents(false)); |
196 add: function (obj) { |
197 patchEditorEvents("SetProgressState", "state time"); |
197 return obj; |
198 patchEditorEvents("VisualAid", "element hasVisual"); |
198 }, |
199 patchEditorEvents("Undo Redo", convertUndoEventArgs); |
199 createButton: cmNoop, |
200 |
200 createColorSplitButton: cmNoop, |
201 patchEditorEvents("NodeChange", function(type, e) { |
201 createControl: cmNoop, |
202 return [ |
202 createDropMenu: cmNoop, |
203 editor.controlManager, |
203 createListBox: cmNoop, |
204 e.element, |
204 createMenuButton: cmNoop, |
205 editor.selection.isCollapsed(), |
205 createSeparator: cmNoop, |
206 e |
206 createSplitButton: cmNoop, |
207 ]; |
207 createToolbar: cmNoop, |
208 }); |
208 createToolbarGroup: cmNoop, |
209 |
209 destroy: noop, |
210 var originalAddButton = editor.addButton; |
210 get: noop, |
211 editor.addButton = function(name, settings) { |
211 setControlType: cmNoop |
212 var originalOnPostRender, string, translated; |
212 }; |
213 |
213 |
214 function patchedPostRender() { |
214 patchEditorEvents("PreInit BeforeRenderUI PostRender Load Init Remove Activate Deactivate", "editor"); |
215 editor.controlManager.buttons[name] = this; |
215 patchEditorEvents("Click MouseUp MouseDown DblClick KeyDown KeyUp KeyPress ContextMenu Paste Submit Reset"); |
216 |
216 patchEditorEvents("BeforeExecCommand ExecCommand", "command ui value args"); // args.terminate not supported |
217 if (originalOnPostRender) { |
217 patchEditorEvents("PreProcess PostProcess LoadContent SaveContent Change"); |
218 return originalOnPostRender.call(this); |
218 patchEditorEvents("BeforeSetContent BeforeGetContent SetContent GetContent", filterSelectionEvents(false)); |
219 } |
219 patchEditorEvents("SetProgressState", "state time"); |
220 } |
220 patchEditorEvents("VisualAid", "element hasVisual"); |
221 |
221 patchEditorEvents("Undo Redo", convertUndoEventArgs); |
222 for (var key in settings) { |
222 |
223 if (key.toLowerCase() === "onpostrender") { |
223 patchEditorEvents("NodeChange", function (type, e) { |
224 originalOnPostRender = settings[key]; |
224 return [ |
225 settings.onPostRender = patchedPostRender; |
225 editor.controlManager, |
226 } |
226 e.element, |
227 } |
227 editor.selection.isCollapsed(), |
228 |
228 e |
229 if (!originalOnPostRender) { |
229 ]; |
230 settings.onPostRender = patchedPostRender; |
230 }); |
231 } |
231 |
232 |
232 var originalAddButton = editor.addButton; |
233 if ( settings.title ) { |
233 editor.addButton = function (name, settings) { |
234 // WP |
234 var originalOnPostRender; |
235 string = (editor.settings.language || "en") + "." + settings.title; |
235 |
236 translated = tinymce.i18n.translate(string); |
236 function patchedPostRender() { |
237 |
237 editor.controlManager.buttons[name] = this; |
238 if ( string !== translated ) { |
238 |
239 settings.title = translated; |
239 if (originalOnPostRender) { |
240 } |
240 return originalOnPostRender.apply(this, arguments); |
241 // WP end |
241 } |
242 } |
242 } |
243 |
243 |
244 return originalAddButton.call(this, name, settings); |
244 for (var key in settings) { |
245 }; |
245 if (key.toLowerCase() === "onpostrender") { |
246 |
246 originalOnPostRender = settings[key]; |
247 editor.on('init', function() { |
247 settings.onPostRender = patchedPostRender; |
248 var undoManager = editor.undoManager, selection = editor.selection; |
248 } |
249 |
249 } |
250 undoManager.onUndo = new Dispatcher(editor, "Undo", convertUndoEventArgs, null, undoManager); |
250 |
251 undoManager.onRedo = new Dispatcher(editor, "Redo", convertUndoEventArgs, null, undoManager); |
251 if (!originalOnPostRender) { |
252 undoManager.onBeforeAdd = new Dispatcher(editor, "BeforeAddUndo", null, undoManager); |
252 settings.onPostRender = patchedPostRender; |
253 undoManager.onAdd = new Dispatcher(editor, "AddUndo", null, undoManager); |
253 } |
254 |
254 |
255 selection.onBeforeGetContent = new Dispatcher(editor, "BeforeGetContent", filterSelectionEvents(true), selection); |
255 if (settings.title) { |
256 selection.onGetContent = new Dispatcher(editor, "GetContent", filterSelectionEvents(true), selection); |
256 settings.title = translate(settings.title); |
257 selection.onBeforeSetContent = new Dispatcher(editor, "BeforeSetContent", filterSelectionEvents(true), selection); |
257 } |
258 selection.onSetContent = new Dispatcher(editor, "SetContent", filterSelectionEvents(true), selection); |
258 |
259 }); |
259 return originalAddButton.call(this, name, settings); |
260 |
260 }; |
261 editor.on('BeforeRenderUI', function() { |
261 |
262 var windowManager = editor.windowManager; |
262 editor.on('init', function () { |
263 |
263 var undoManager = editor.undoManager, selection = editor.selection; |
264 windowManager.onOpen = new Dispatcher(); |
264 |
265 windowManager.onClose = new Dispatcher(); |
265 undoManager.onUndo = new Dispatcher(editor, "Undo", convertUndoEventArgs, null, undoManager); |
266 windowManager.createInstance = function(className, a, b, c, d, e) { |
266 undoManager.onRedo = new Dispatcher(editor, "Redo", convertUndoEventArgs, null, undoManager); |
267 log("windowManager.createInstance(..)"); |
267 undoManager.onBeforeAdd = new Dispatcher(editor, "BeforeAddUndo", null, undoManager); |
268 |
268 undoManager.onAdd = new Dispatcher(editor, "AddUndo", null, undoManager); |
269 var constr = tinymce.resolve(className); |
269 |
270 return new constr(a, b, c, d, e); |
270 selection.onBeforeGetContent = new Dispatcher(editor, "BeforeGetContent", filterSelectionEvents(true), selection); |
271 }; |
271 selection.onGetContent = new Dispatcher(editor, "GetContent", filterSelectionEvents(true), selection); |
272 }); |
272 selection.onBeforeSetContent = new Dispatcher(editor, "BeforeSetContent", filterSelectionEvents(true), selection); |
273 } |
273 selection.onSetContent = new Dispatcher(editor, "SetContent", filterSelectionEvents(true), selection); |
274 |
274 }); |
275 tinymce.on('SetupEditor', patchEditor); |
275 |
276 tinymce.PluginManager.add("compat3x", patchEditor); |
276 editor.on('BeforeRenderUI', function () { |
277 |
277 var windowManager = editor.windowManager; |
278 tinymce.addI18n = function(prefix, o) { |
278 |
279 var I18n = tinymce.util.I18n, each = tinymce.each; |
279 windowManager.onOpen = new Dispatcher(); |
280 |
280 windowManager.onClose = new Dispatcher(); |
281 if (typeof(prefix) == "string" && prefix.indexOf('.') === -1) { |
281 windowManager.createInstance = function (className, a, b, c, d, e) { |
282 I18n.add(prefix, o); |
282 log("windowManager.createInstance(..)"); |
283 return; |
283 |
284 } |
284 var constr = tinymce.resolve(className); |
285 |
285 return new constr(a, b, c, d, e); |
286 if (!tinymce.is(prefix, 'string')) { |
286 }; |
287 each(prefix, function(o, lc) { |
287 }); |
288 each(o, function(o, g) { |
288 } |
289 each(o, function(o, k) { |
289 |
290 if (g === 'common') { |
290 tinymce.on('SetupEditor', function (e) { |
291 I18n.data[lc + '.' + k] = o; |
291 patchEditor(e.editor); |
292 } else { |
292 }); |
293 I18n.data[lc + '.' + g + '.' + k] = o; |
293 |
294 } |
294 tinymce.PluginManager.add("compat3x", patchEditor); |
295 }); |
295 |
296 }); |
296 tinymce.addI18n = function (prefix, o) { |
297 }); |
297 var I18n = tinymce.util.I18n, each = tinymce.each; |
298 } else { |
298 |
299 each(o, function(o, k) { |
299 if (typeof prefix == "string" && prefix.indexOf('.') === -1) { |
300 I18n.data[prefix + '.' + k] = o; |
300 I18n.add(prefix, o); |
301 }); |
301 return; |
302 } |
302 } |
303 }; |
303 |
|
304 if (!tinymce.is(prefix, 'string')) { |
|
305 each(prefix, function (o, lc) { |
|
306 each(o, function (o, g) { |
|
307 each(o, function (o, k) { |
|
308 if (g === 'common') { |
|
309 I18n.data[lc + '.' + k] = o; |
|
310 } else { |
|
311 I18n.data[lc + '.' + g + '.' + k] = o; |
|
312 } |
|
313 }); |
|
314 }); |
|
315 }); |
|
316 } else { |
|
317 each(o, function (o, k) { |
|
318 I18n.data[prefix + '.' + k] = o; |
|
319 }); |
|
320 } |
|
321 }; |
304 })(tinymce); |
322 })(tinymce); |