plugin.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /**
  2. * plugin.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. /*global tinymce:true, console:true */
  11. /*eslint no-console:0, new-cap:0 */
  12. /**
  13. * This plugin adds missing events form the 4.x API back. Not every event is
  14. * properly supported but most things should work.
  15. *
  16. * Unsupported things:
  17. * - No editor.onEvent
  18. * - Can't cancel execCommands with beforeExecCommand
  19. */
  20. (function(tinymce) {
  21. var reported;
  22. function noop() {}
  23. function log(apiCall) {
  24. if (!reported && window && window.console) {
  25. reported = true;
  26. console.log("Deprecated TinyMCE API call: " + apiCall);
  27. }
  28. }
  29. function Dispatcher(target, newEventName, argsMap, defaultScope) {
  30. target = target || this;
  31. if (!newEventName) {
  32. this.add = this.addToTop = this.remove = this.dispatch = noop;
  33. return;
  34. }
  35. this.add = function(callback, scope, prepend) {
  36. log('<target>.on' + newEventName + ".add(..)");
  37. // Convert callback({arg1:x, arg2:x}) -> callback(arg1, arg2)
  38. function patchedEventCallback(e) {
  39. var callbackArgs = [];
  40. if (typeof argsMap == "string") {
  41. argsMap = argsMap.split(" ");
  42. }
  43. if (argsMap && typeof argsMap != "function") {
  44. for (var i = 0; i < argsMap.length; i++) {
  45. callbackArgs.push(e[argsMap[i]]);
  46. }
  47. }
  48. if (typeof argsMap == "function") {
  49. callbackArgs = argsMap(newEventName, e, target);
  50. if (!callbackArgs) {
  51. return;
  52. }
  53. }
  54. if (!argsMap) {
  55. callbackArgs = [e];
  56. }
  57. callbackArgs.unshift(defaultScope || target);
  58. if (callback.apply(scope || defaultScope || target, callbackArgs) === false) {
  59. e.stopImmediatePropagation();
  60. }
  61. }
  62. target.on(newEventName, patchedEventCallback, prepend);
  63. return patchedEventCallback;
  64. };
  65. this.addToTop = function(callback, scope) {
  66. this.add(callback, scope, true);
  67. };
  68. this.remove = function(callback) {
  69. return target.off(newEventName, callback);
  70. };
  71. this.dispatch = function() {
  72. target.fire(newEventName);
  73. return true;
  74. };
  75. }
  76. tinymce.util.Dispatcher = Dispatcher;
  77. tinymce.onBeforeUnload = new Dispatcher(tinymce, "BeforeUnload");
  78. tinymce.onAddEditor = new Dispatcher(tinymce, "AddEditor", "editor");
  79. tinymce.onRemoveEditor = new Dispatcher(tinymce, "RemoveEditor", "editor");
  80. tinymce.util.Cookie = {
  81. get: noop, getHash: noop, remove: noop, set: noop, setHash: noop
  82. };
  83. function patchEditor(editor) {
  84. function patchEditorEvents(oldEventNames, argsMap) {
  85. tinymce.each(oldEventNames.split(" "), function(oldName) {
  86. editor["on" + oldName] = new Dispatcher(editor, oldName, argsMap);
  87. });
  88. }
  89. function convertUndoEventArgs(type, event, target) {
  90. return [
  91. event.level,
  92. target
  93. ];
  94. }
  95. function filterSelectionEvents(needsSelection) {
  96. return function(type, e) {
  97. if ((!e.selection && !needsSelection) || e.selection == needsSelection) {
  98. return [e];
  99. }
  100. };
  101. }
  102. if (editor.controlManager) {
  103. return;
  104. }
  105. function cmNoop() {
  106. var obj = {}, methods = 'add addMenu addSeparator collapse createMenu destroy displayColor expand focus ' +
  107. 'getLength hasMenus hideMenu isActive isCollapsed isDisabled isRendered isSelected mark ' +
  108. 'postRender remove removeAll renderHTML renderMenu renderNode renderTo select selectByIndex ' +
  109. 'setActive setAriaProperty setColor setDisabled setSelected setState showMenu update';
  110. log('editor.controlManager.*');
  111. function _noop() {
  112. return cmNoop();
  113. }
  114. tinymce.each(methods.split(' '), function(method) {
  115. obj[method] = _noop;
  116. });
  117. return obj;
  118. }
  119. editor.controlManager = {
  120. buttons: {},
  121. setDisabled: function(name, state) {
  122. log("controlManager.setDisabled(..)");
  123. if (this.buttons[name]) {
  124. this.buttons[name].disabled(state);
  125. }
  126. },
  127. setActive: function(name, state) {
  128. log("controlManager.setActive(..)");
  129. if (this.buttons[name]) {
  130. this.buttons[name].active(state);
  131. }
  132. },
  133. onAdd: new Dispatcher(),
  134. onPostRender: new Dispatcher(),
  135. add: function(obj) { return obj; },
  136. createButton: cmNoop,
  137. createColorSplitButton: cmNoop,
  138. createControl: cmNoop,
  139. createDropMenu: cmNoop,
  140. createListBox: cmNoop,
  141. createMenuButton: cmNoop,
  142. createSeparator: cmNoop,
  143. createSplitButton: cmNoop,
  144. createToolbar: cmNoop,
  145. createToolbarGroup: cmNoop,
  146. destroy: noop,
  147. get: noop,
  148. setControlType: cmNoop
  149. };
  150. patchEditorEvents("PreInit BeforeRenderUI PostRender Load Init Remove Activate Deactivate", "editor");
  151. patchEditorEvents("Click MouseUp MouseDown DblClick KeyDown KeyUp KeyPress ContextMenu Paste Submit Reset");
  152. patchEditorEvents("BeforeExecCommand ExecCommand", "command ui value args"); // args.terminate not supported
  153. patchEditorEvents("PreProcess PostProcess LoadContent SaveContent Change");
  154. patchEditorEvents("BeforeSetContent BeforeGetContent SetContent GetContent", filterSelectionEvents(false));
  155. patchEditorEvents("SetProgressState", "state time");
  156. patchEditorEvents("VisualAid", "element hasVisual");
  157. patchEditorEvents("Undo Redo", convertUndoEventArgs);
  158. patchEditorEvents("NodeChange", function(type, e) {
  159. return [
  160. editor.controlManager,
  161. e.element,
  162. editor.selection.isCollapsed(),
  163. e
  164. ];
  165. });
  166. var originalAddButton = editor.addButton;
  167. editor.addButton = function(name, settings) {
  168. var originalOnPostRender;
  169. function patchedPostRender() {
  170. editor.controlManager.buttons[name] = this;
  171. if (originalOnPostRender) {
  172. return originalOnPostRender.call(this);
  173. }
  174. }
  175. for (var key in settings) {
  176. if (key.toLowerCase() === "onpostrender") {
  177. originalOnPostRender = settings[key];
  178. settings.onPostRender = patchedPostRender;
  179. }
  180. }
  181. if (!originalOnPostRender) {
  182. settings.onPostRender = patchedPostRender;
  183. }
  184. if (settings.title) {
  185. settings.title = tinymce.i18n.translate((editor.settings.language || "en") + "." + settings.title);
  186. }
  187. return originalAddButton.call(this, name, settings);
  188. };
  189. editor.on('init', function() {
  190. var undoManager = editor.undoManager, selection = editor.selection;
  191. undoManager.onUndo = new Dispatcher(editor, "Undo", convertUndoEventArgs, null, undoManager);
  192. undoManager.onRedo = new Dispatcher(editor, "Redo", convertUndoEventArgs, null, undoManager);
  193. undoManager.onBeforeAdd = new Dispatcher(editor, "BeforeAddUndo", null, undoManager);
  194. undoManager.onAdd = new Dispatcher(editor, "AddUndo", null, undoManager);
  195. selection.onBeforeGetContent = new Dispatcher(editor, "BeforeGetContent", filterSelectionEvents(true), selection);
  196. selection.onGetContent = new Dispatcher(editor, "GetContent", filterSelectionEvents(true), selection);
  197. selection.onBeforeSetContent = new Dispatcher(editor, "BeforeSetContent", filterSelectionEvents(true), selection);
  198. selection.onSetContent = new Dispatcher(editor, "SetContent", filterSelectionEvents(true), selection);
  199. });
  200. editor.on('BeforeRenderUI', function() {
  201. var windowManager = editor.windowManager;
  202. windowManager.onOpen = new Dispatcher();
  203. windowManager.onClose = new Dispatcher();
  204. windowManager.createInstance = function(className, a, b, c, d, e) {
  205. log("windowManager.createInstance(..)");
  206. var constr = tinymce.resolve(className);
  207. return new constr(a, b, c, d, e);
  208. };
  209. });
  210. }
  211. tinymce.on('SetupEditor', patchEditor);
  212. tinymce.PluginManager.add("compat3x", patchEditor);
  213. tinymce.addI18n = function(prefix, o) {
  214. var I18n = tinymce.util.I18n, each = tinymce.each;
  215. if (typeof(prefix) == "string" && prefix.indexOf('.') === -1) {
  216. I18n.add(prefix, o);
  217. return;
  218. }
  219. if (!tinymce.is(prefix, 'string')) {
  220. each(prefix, function(o, lc) {
  221. each(o, function(o, g) {
  222. each(o, function(o, k) {
  223. if (g === 'common') {
  224. I18n.data[lc + '.' + k] = o;
  225. } else {
  226. I18n.data[lc + '.' + g + '.' + k] = o;
  227. }
  228. });
  229. });
  230. });
  231. } else {
  232. each(o, function(o, k) {
  233. I18n.data[prefix + '.' + k] = o;
  234. });
  235. }
  236. };
  237. })(tinymce);