4 * Copyright, Moxiecode Systems AB
5 * Released under LGPL License.
7 * License: http://www.tinymce.com/license
8 * Contributing: http://www.tinymce.com/contributing
11 /*global tinymce:true, console:true */
12 /*eslint no-console:0, new-cap:0 */
15 * This plugin adds missing events form the 4.x API back. Not every event is
16 * properly supported but most things should work.
20 * - Can't cancel execCommands with beforeExecCommand
27 function log(apiCall) {
28 if (!reported && window && window.console) {
30 console.log("Deprecated TinyMCE API call: " + apiCall);
34 function Dispatcher(target, newEventName, argsMap, defaultScope) {
35 target = target || this;
38 this.add = this.addToTop = this.remove = this.dispatch = noop;
42 this.add = function(callback, scope, prepend) {
43 log('<target>.on' + newEventName + ".add(..)");
45 // Convert callback({arg1:x, arg2:x}) -> callback(arg1, arg2)
46 function patchedEventCallback(e) {
47 var callbackArgs = [];
49 if (typeof argsMap == "string") {
50 argsMap = argsMap.split(" ");
53 if (argsMap && typeof argsMap != "function") {
54 for (var i = 0; i < argsMap.length; i++) {
55 callbackArgs.push(e[argsMap[i]]);
59 if (typeof argsMap == "function") {
60 callbackArgs = argsMap(newEventName, e, target);
70 callbackArgs.unshift(defaultScope || target);
72 if (callback.apply(scope || defaultScope || target, callbackArgs) === false) {
73 e.stopImmediatePropagation();
77 target.on(newEventName, patchedEventCallback, prepend);
79 return patchedEventCallback;
82 this.addToTop = function(callback, scope) {
83 this.add(callback, scope, true);
86 this.remove = function(callback) {
87 return target.off(newEventName, callback);
90 this.dispatch = function() {
91 target.fire(newEventName);
97 tinymce.util.Dispatcher = Dispatcher;
98 tinymce.onBeforeUnload = new Dispatcher(tinymce, "BeforeUnload");
99 tinymce.onAddEditor = new Dispatcher(tinymce, "AddEditor", "editor");
100 tinymce.onRemoveEditor = new Dispatcher(tinymce, "RemoveEditor", "editor");
102 tinymce.util.Cookie = {
103 get: noop, getHash: noop, remove: noop, set: noop, setHash: noop
106 function patchEditor(editor) {
107 function patchEditorEvents(oldEventNames, argsMap) {
108 tinymce.each(oldEventNames.split(" "), function(oldName) {
109 editor["on" + oldName] = new Dispatcher(editor, oldName, argsMap);
113 function convertUndoEventArgs(type, event, target) {
120 function filterSelectionEvents(needsSelection) {
121 return function(type, e) {
122 if ((!e.selection && !needsSelection) || e.selection == needsSelection) {
128 if (editor.controlManager) {
133 var obj = {}, methods = 'add addMenu addSeparator collapse createMenu destroy displayColor expand focus ' +
134 'getLength hasMenus hideMenu isActive isCollapsed isDisabled isRendered isSelected mark ' +
135 'postRender remove removeAll renderHTML renderMenu renderNode renderTo select selectByIndex ' +
136 'setActive setAriaProperty setColor setDisabled setSelected setState showMenu update';
138 log('editor.controlManager.*');
144 tinymce.each(methods.split(' '), function(method) {
151 editor.controlManager = {
154 setDisabled: function(name, state) {
155 log("controlManager.setDisabled(..)");
157 if (this.buttons[name]) {
158 this.buttons[name].disabled(state);
162 setActive: function(name, state) {
163 log("controlManager.setActive(..)");
165 if (this.buttons[name]) {
166 this.buttons[name].active(state);
170 onAdd: new Dispatcher(),
171 onPostRender: new Dispatcher(),
173 add: function(obj) { return obj; },
174 createButton: cmNoop,
175 createColorSplitButton: cmNoop,
176 createControl: cmNoop,
177 createDropMenu: cmNoop,
178 createListBox: cmNoop,
179 createMenuButton: cmNoop,
180 createSeparator: cmNoop,
181 createSplitButton: cmNoop,
182 createToolbar: cmNoop,
183 createToolbarGroup: cmNoop,
186 setControlType: cmNoop
189 patchEditorEvents("PreInit BeforeRenderUI PostRender Load Init Remove Activate Deactivate", "editor");
190 patchEditorEvents("Click MouseUp MouseDown DblClick KeyDown KeyUp KeyPress ContextMenu Paste Submit Reset");
191 patchEditorEvents("BeforeExecCommand ExecCommand", "command ui value args"); // args.terminate not supported
192 patchEditorEvents("PreProcess PostProcess LoadContent SaveContent Change");
193 patchEditorEvents("BeforeSetContent BeforeGetContent SetContent GetContent", filterSelectionEvents(false));
194 patchEditorEvents("SetProgressState", "state time");
195 patchEditorEvents("VisualAid", "element hasVisual");
196 patchEditorEvents("Undo Redo", convertUndoEventArgs);
198 patchEditorEvents("NodeChange", function(type, e) {
200 editor.controlManager,
202 editor.selection.isCollapsed(),
207 var originalAddButton = editor.addButton;
208 editor.addButton = function(name, settings) {
209 var originalOnPostRender, string, translated;
211 function patchedPostRender() {
212 editor.controlManager.buttons[name] = this;
214 if (originalOnPostRender) {
215 return originalOnPostRender.call(this);
219 for (var key in settings) {
220 if (key.toLowerCase() === "onpostrender") {
221 originalOnPostRender = settings[key];
222 settings.onPostRender = patchedPostRender;
226 if (!originalOnPostRender) {
227 settings.onPostRender = patchedPostRender;
230 if ( settings.title ) {
232 string = (editor.settings.language || "en") + "." + settings.title;
233 translated = tinymce.i18n.translate(string);
235 if ( string !== translated ) {
236 settings.title = translated;
241 return originalAddButton.call(this, name, settings);
244 editor.on('init', function() {
245 var undoManager = editor.undoManager, selection = editor.selection;
247 undoManager.onUndo = new Dispatcher(editor, "Undo", convertUndoEventArgs, null, undoManager);
248 undoManager.onRedo = new Dispatcher(editor, "Redo", convertUndoEventArgs, null, undoManager);
249 undoManager.onBeforeAdd = new Dispatcher(editor, "BeforeAddUndo", null, undoManager);
250 undoManager.onAdd = new Dispatcher(editor, "AddUndo", null, undoManager);
252 selection.onBeforeGetContent = new Dispatcher(editor, "BeforeGetContent", filterSelectionEvents(true), selection);
253 selection.onGetContent = new Dispatcher(editor, "GetContent", filterSelectionEvents(true), selection);
254 selection.onBeforeSetContent = new Dispatcher(editor, "BeforeSetContent", filterSelectionEvents(true), selection);
255 selection.onSetContent = new Dispatcher(editor, "SetContent", filterSelectionEvents(true), selection);
258 editor.on('BeforeRenderUI', function() {
259 var windowManager = editor.windowManager;
261 windowManager.onOpen = new Dispatcher();
262 windowManager.onClose = new Dispatcher();
263 windowManager.createInstance = function(className, a, b, c, d, e) {
264 log("windowManager.createInstance(..)");
266 var constr = tinymce.resolve(className);
267 return new constr(a, b, c, d, e);
272 tinymce.on('SetupEditor', patchEditor);
273 tinymce.PluginManager.add("compat3x", patchEditor);
275 tinymce.addI18n = function(prefix, o) {
276 var I18n = tinymce.util.I18n, each = tinymce.each;
278 if (typeof(prefix) == "string" && prefix.indexOf('.') === -1) {
283 if (!tinymce.is(prefix, 'string')) {
284 each(prefix, function(o, lc) {
285 each(o, function(o, g) {
286 each(o, function(o, k) {
287 if (g === 'common') {
288 I18n.data[lc + '.' + k] = o;
290 I18n.data[lc + '.' + g + '.' + k] = o;
296 each(o, function(o, k) {
297 I18n.data[prefix + '.' + k] = o;