tinymce-3.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. (function($) {
  2. /**
  3. * Initialize editor instances.
  4. *
  5. * @todo Is the following note still valid for 3.x?
  6. * This function needs to be called before the page is fully loaded, as
  7. * calling tinyMCE.init() after the page is loaded breaks IE6.
  8. *
  9. * @param editorSettings
  10. * An object containing editor settings for each input format.
  11. */
  12. Drupal.wysiwyg.editor.init.tinymce = function(settings) {
  13. // Fix Drupal toolbar obscuring editor toolbar in fullscreen mode.
  14. var $drupalToolbar = $('#toolbar', Drupal.overlayChild ? window.parent.document : document);
  15. tinyMCE.onAddEditor.add(function (mgr, ed) {
  16. if (ed.id == 'mce_fullscreen') {
  17. $drupalToolbar.hide();
  18. }
  19. });
  20. tinyMCE.onRemoveEditor.add(function (mgr, ed) {
  21. if (ed.id == 'mce_fullscreen') {
  22. $drupalToolbar.show();
  23. }
  24. });
  25. // Initialize editor configurations.
  26. for (var format in settings) {
  27. if (Drupal.settings.wysiwyg.plugins[format]) {
  28. // Load native external plugins.
  29. // Array syntax required; 'native' is a predefined token in JavaScript.
  30. for (var plugin in Drupal.settings.wysiwyg.plugins[format]['native']) {
  31. tinymce.PluginManager.load(plugin, Drupal.settings.wysiwyg.plugins[format]['native'][plugin]);
  32. }
  33. // Load Drupal plugins.
  34. for (var plugin in Drupal.settings.wysiwyg.plugins[format].drupal) {
  35. Drupal.wysiwyg.editor.instance.tinymce.addPlugin(plugin, Drupal.settings.wysiwyg.plugins[format].drupal[plugin], Drupal.settings.wysiwyg.plugins.drupal[plugin]);
  36. }
  37. }
  38. }
  39. };
  40. /**
  41. * Attach this editor to a target element.
  42. *
  43. * See Drupal.wysiwyg.editor.attach.none() for a full desciption of this hook.
  44. */
  45. Drupal.wysiwyg.editor.attach.tinymce = function(context, params, settings) {
  46. // Configure editor settings for this input format.
  47. var ed = new tinymce.Editor(params.field, settings);
  48. // Reset active instance id on any event.
  49. ed.onEvent.add(function(ed, e) {
  50. Drupal.wysiwyg.activeId = ed.id;
  51. });
  52. // Indicate that the DOM has been loaded (in case of Ajax).
  53. tinymce.dom.Event.domLoaded = true;
  54. // Make toolbar buttons wrappable (required for IE).
  55. ed.onPostRender.add(function (ed) {
  56. var $toolbar = $('<div class="wysiwygToolbar"></div>');
  57. $('#' + ed.editorContainer + ' table.mceToolbar > tbody > tr > td').each(function () {
  58. $('<div></div>').addClass(this.className).append($(this).children()).appendTo($toolbar);
  59. });
  60. $('#' + ed.editorContainer + ' table.mceLayout td.mceToolbar').append($toolbar);
  61. $('#' + ed.editorContainer + ' table.mceToolbar').remove();
  62. });
  63. // Remove TinyMCE's internal mceItem class, which was incorrectly added to
  64. // submitted content by Wysiwyg <2.1. TinyMCE only temporarily adds the class
  65. // for placeholder elements. If preemptively set, the class prevents (native)
  66. // editor plugins from gaining an active state, so we have to manually remove
  67. // it prior to attaching the editor. This is done on the client-side instead
  68. // of the server-side, as Wysiwyg has no way to figure out where content is
  69. // stored, and the class only affects editing.
  70. $field = $('#' + params.field);
  71. $field.val($field.val().replace(/(<.+?\s+class=['"][\w\s]*?)\bmceItem\b([\w\s]*?['"].*?>)/ig, '$1$2'));
  72. // Attach editor.
  73. ed.render();
  74. };
  75. /**
  76. * Detach a single or all editors.
  77. *
  78. * See Drupal.wysiwyg.editor.detach.none() for a full desciption of this hook.
  79. */
  80. Drupal.wysiwyg.editor.detach.tinymce = function (context, params, trigger) {
  81. if (typeof params != 'undefined') {
  82. var instance = tinyMCE.get(params.field);
  83. if (instance) {
  84. instance.save();
  85. if (trigger != 'serialize') {
  86. instance.remove();
  87. }
  88. }
  89. }
  90. else {
  91. // Save contents of all editors back into textareas.
  92. tinyMCE.triggerSave();
  93. if (trigger != 'serialize') {
  94. // Remove all editor instances.
  95. for (var instance in tinyMCE.editors) {
  96. tinyMCE.editors[instance].remove();
  97. }
  98. }
  99. }
  100. };
  101. Drupal.wysiwyg.editor.instance.tinymce = {
  102. addPlugin: function(plugin, settings, pluginSettings) {
  103. if (typeof Drupal.wysiwyg.plugins[plugin] != 'object') {
  104. return;
  105. }
  106. tinymce.create('tinymce.plugins.' + plugin, {
  107. /**
  108. * Initialize the plugin, executed after the plugin has been created.
  109. *
  110. * @param ed
  111. * The tinymce.Editor instance the plugin is initialized in.
  112. * @param url
  113. * The absolute URL of the plugin location.
  114. */
  115. init: function(ed, url) {
  116. // Register an editor command for this plugin, invoked by the plugin's button.
  117. ed.addCommand(plugin, function() {
  118. if (typeof Drupal.wysiwyg.plugins[plugin].invoke == 'function') {
  119. var data = { format: 'html', node: ed.selection.getNode(), content: ed.selection.getContent() };
  120. // TinyMCE creates a completely new instance for fullscreen mode.
  121. var instanceId = ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id;
  122. Drupal.wysiwyg.plugins[plugin].invoke(data, pluginSettings, instanceId);
  123. }
  124. });
  125. // Register the plugin button.
  126. ed.addButton(plugin, {
  127. title : settings.iconTitle,
  128. cmd : plugin,
  129. image : settings.icon
  130. });
  131. // Load custom CSS for editor contents on startup.
  132. ed.onInit.add(function() {
  133. if (settings.css) {
  134. ed.dom.loadCSS(settings.css);
  135. }
  136. });
  137. // Attach: Replace plain text with HTML representations.
  138. ed.onBeforeSetContent.add(function(ed, data) {
  139. var editorId = (ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id);
  140. if (typeof Drupal.wysiwyg.plugins[plugin].attach == 'function') {
  141. data.content = Drupal.wysiwyg.plugins[plugin].attach(data.content, pluginSettings, editorId);
  142. data.content = Drupal.wysiwyg.editor.instance.tinymce.prepareContent(data.content);
  143. }
  144. });
  145. // Detach: Replace HTML representations with plain text.
  146. ed.onGetContent.add(function(ed, data) {
  147. var editorId = (ed.id == 'mce_fullscreen' ? ed.getParam('fullscreen_editor_id') : ed.id);
  148. if (typeof Drupal.wysiwyg.plugins[plugin].detach == 'function') {
  149. data.content = Drupal.wysiwyg.plugins[plugin].detach(data.content, pluginSettings, editorId);
  150. }
  151. });
  152. // isNode: Return whether the plugin button should be enabled for the
  153. // current selection.
  154. ed.onNodeChange.add(function(ed, command, node) {
  155. if (typeof Drupal.wysiwyg.plugins[plugin].isNode == 'function') {
  156. command.setActive(plugin, Drupal.wysiwyg.plugins[plugin].isNode(node));
  157. }
  158. });
  159. },
  160. /**
  161. * Return information about the plugin as a name/value array.
  162. */
  163. getInfo: function() {
  164. return {
  165. longname: settings.title
  166. };
  167. }
  168. });
  169. // Register plugin.
  170. tinymce.PluginManager.add(plugin, tinymce.plugins[plugin]);
  171. },
  172. openDialog: function(dialog, params) {
  173. var instanceId = this.getInstanceId();
  174. var editor = tinyMCE.get(instanceId);
  175. editor.windowManager.open({
  176. file: dialog.url + '/' + instanceId,
  177. width: dialog.width,
  178. height: dialog.height,
  179. inline: 1
  180. }, params);
  181. },
  182. closeDialog: function(dialog) {
  183. var editor = tinyMCE.get(this.getInstanceId());
  184. editor.windowManager.close(dialog);
  185. },
  186. prepareContent: function(content) {
  187. // Certain content elements need to have additional DOM properties applied
  188. // to prevent this editor from highlighting an internal button in addition
  189. // to the button of a Drupal plugin.
  190. var specialProperties = {
  191. img: { 'class': 'mceItem' }
  192. };
  193. var $content = $('<div>' + content + '</div>'); // No .outerHTML() in jQuery :(
  194. // Find all placeholder/replacement content of Drupal plugins.
  195. $content.find('.drupal-content').each(function() {
  196. // Recursively process DOM elements below this element to apply special
  197. // properties.
  198. var $drupalContent = $(this);
  199. $.each(specialProperties, function(element, properties) {
  200. $drupalContent.find(element).andSelf().each(function() {
  201. for (var property in properties) {
  202. if (property == 'class') {
  203. $(this).addClass(properties[property]);
  204. }
  205. else {
  206. $(this).attr(property, properties[property]);
  207. }
  208. }
  209. });
  210. });
  211. });
  212. return $content.html();
  213. },
  214. insert: function(content) {
  215. content = this.prepareContent(content);
  216. tinyMCE.execInstanceCommand(this.getInstanceId(), 'mceInsertContent', false, content);
  217. },
  218. setContent: function (content) {
  219. content = this.prepareContent(content);
  220. tinyMCE.execInstanceCommand(this.getInstanceId(), 'mceSetContent', false, content);
  221. },
  222. getContent: function () {
  223. return tinyMCE.get(this.getInstanceId()).getContent();
  224. },
  225. isFullscreen: function() {
  226. // TinyMCE creates a completely new instance for fullscreen mode.
  227. return tinyMCE.activeEditor.id == 'mce_fullscreen' && tinyMCE.activeEditor.getParam('fullscreen_editor_id') == this.field;
  228. },
  229. getInstanceId: function () {
  230. return this.isFullscreen() ? 'mce_fullscreen' : this.field;
  231. }
  232. };
  233. })(jQuery);