plugin.js 9.2 KB

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