epiceditor.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. (function($) {
  2. /**
  3. * Attach this editor to a target element.
  4. */
  5. Drupal.wysiwyg.editor.attach.epiceditor = function (context, params, settings) {
  6. var $target = $('#' + params.field),
  7. containerId = params.field + '-epiceditor',
  8. defaultContent = $target.val(),
  9. $container = $('<div id="' + containerId + '" />');
  10. $target.hide().after($container);
  11. if (!settings.height) {
  12. settings.height = $('#' + params.field).height();
  13. }
  14. $container.height(settings.height);
  15. settings.container = containerId;
  16. settings.file = {
  17. defaultContent: defaultContent
  18. };
  19. settings.theme = {
  20. preview: '/themes/preview/preview-dark.css',
  21. editor: '/themes/editor/' + settings.theme + '.css'
  22. };
  23. var editor = new EpicEditor(settings).load();
  24. $target.data('epiceditor', editor);
  25. };
  26. /**
  27. * Detach a single edtor instance.
  28. */
  29. Drupal.wysiwyg.editor.detach.epiceditor = function (context, params, trigger) {
  30. var $target = $('#' + params.field, context);
  31. var editor = $target.data('epiceditor');
  32. if (!editor) {
  33. return;
  34. }
  35. // Save contents of the editor back into the textarea.
  36. $target.val(editor.exportFile());
  37. if (trigger !== 'serialize') {
  38. // Remove editor instance and container.
  39. editor.unload(function () {
  40. $target.show();
  41. $('#' + $target.attr('id') + '-epiceditor').remove();
  42. });
  43. $target.removeData('epiceditor');
  44. }
  45. };
  46. /**
  47. * Check if a DOM node is inside another or if they are the same.
  48. */
  49. function isInside (innerNode, outerNode) {
  50. var found = false;
  51. if (innerNode === outerNode) {
  52. return true;
  53. }
  54. $(innerNode).parents().each(function (index, parent) {
  55. if (parent === outerNode) {
  56. found = true;
  57. return false;
  58. }
  59. });
  60. return found;
  61. }
  62. /**
  63. * Converts HTML markup to plain text.
  64. *
  65. * EpicEditor isn't WYSIWYG and is meant to handle plain text though it does so
  66. * in a contentEditable element. This is taken from EpicEditor's internal
  67. * _setText() function in version 0.2.0.
  68. */
  69. function toPlainText (content) {
  70. content = content.replace(/</g, '&lt;');
  71. content = content.replace(/>/g, '&gt;');
  72. content = content.replace(/\n/g, '<br>');
  73. content = content.replace(/\s\s/g, ' &nbsp;')
  74. return content;
  75. }
  76. Drupal.wysiwyg.editor.instance.epiceditor = {
  77. insert: function (content) {
  78. var instance = this.getInstance();
  79. var editingArea = instance.getElement('editor').body;
  80. // IE.
  81. // @todo Can't test this, EpicEditor breaks in IE.
  82. if (document.selection) {
  83. var sel = editingArea.selection;
  84. range = sel.createRange();
  85. // If the caret is not in the editing area, just append the content.
  86. if (!isInside(range.parentElement(), editingArea)) {
  87. editingArea.innerHTML += toPlainText(content);
  88. }
  89. else {
  90. // Insert content and set the caret after it.
  91. range.pasteHTML(content);
  92. range.select();
  93. range.collapse(false);
  94. }
  95. }
  96. else {
  97. // The code below doesn't work in IE, but it never gets here.
  98. var sel = editingArea.ownerDocument.getSelection();
  99. // Convert selection to a range.
  100. // W3C compatible.
  101. if (sel.getRangeAt) {
  102. if (sel.rangeCount > 0) {
  103. range = sel.getRangeAt(0);
  104. }
  105. }
  106. // Safari.
  107. else {
  108. range = editingArea.ownerDocument.createRange();
  109. range.setStart(sel.anchorNode, sel.anchorOffset);
  110. range.setEnd(sel.focusNode, userSeletion.focusOffset);
  111. }
  112. // If the caret is not in the editing area, just append the content.
  113. if (sel.rangeCount == 0 || !isInside(range.commonAncestorContainer, editingArea)) {
  114. editingArea.innerHTML += toPlainText(content);
  115. return;
  116. }
  117. var fragment = editingArea.ownerDocument.createDocumentFragment();
  118. // Fragments don't support innerHTML.
  119. var wrapper = editingArea.ownerDocument.createElement('div');
  120. wrapper.innerHTML = toPlainText(content);
  121. while (wrapper.firstChild) {
  122. fragment.appendChild(wrapper.firstChild);
  123. }
  124. // Append a temporary node to control caret position.
  125. var tn = editingArea.ownerDocument.createElement('span');
  126. fragment.appendChild(tn);
  127. range.deleteContents();
  128. // Only fragment children are inserted.
  129. range.insertNode(fragment);
  130. // Move caret to temp node and remove it.
  131. range.setStartBefore(tn);
  132. range.setEndBefore(tn);
  133. sel.removeAllRanges();
  134. sel.addRange(range);
  135. tn.parentNode.removeChild(tn);
  136. }
  137. },
  138. setContent: function (content) {
  139. this.getInstance().importFile(null, content);
  140. },
  141. getContent: function () {
  142. return this.getInstance().exportFile();
  143. },
  144. isFullscreen: function () {
  145. return this.getInstance().is('fullscreen');
  146. },
  147. getInstance: function () {
  148. if (!this.editorInstance) {
  149. this.editorInstance = $('#' + this.field).data('epiceditor');
  150. }
  151. return this.editorInstance;
  152. }
  153. }
  154. })(jQuery);