ForceBlocks.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. /**
  2. * ForceBlocks.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. define("tinymce/ForceBlocks", [], function() {
  11. return function(editor) {
  12. var settings = editor.settings, dom = editor.dom, selection = editor.selection;
  13. var schema = editor.schema, blockElements = schema.getBlockElements();
  14. function addRootBlocks() {
  15. var node = selection.getStart(), rootNode = editor.getBody(), rng;
  16. var startContainer, startOffset, endContainer, endOffset, rootBlockNode;
  17. var tempNode, offset = -0xFFFFFF, wrapped, restoreSelection;
  18. var tmpRng, rootNodeName, forcedRootBlock;
  19. forcedRootBlock = settings.forced_root_block;
  20. if (!node || node.nodeType !== 1 || !forcedRootBlock) {
  21. return;
  22. }
  23. // Check if node is wrapped in block
  24. while (node && node != rootNode) {
  25. if (blockElements[node.nodeName]) {
  26. return;
  27. }
  28. node = node.parentNode;
  29. }
  30. // Get current selection
  31. rng = selection.getRng();
  32. if (rng.setStart) {
  33. startContainer = rng.startContainer;
  34. startOffset = rng.startOffset;
  35. endContainer = rng.endContainer;
  36. endOffset = rng.endOffset;
  37. try {
  38. restoreSelection = editor.getDoc().activeElement === rootNode;
  39. } catch (ex) {
  40. // IE throws unspecified error here sometimes
  41. }
  42. } else {
  43. // Force control range into text range
  44. if (rng.item) {
  45. node = rng.item(0);
  46. rng = editor.getDoc().body.createTextRange();
  47. rng.moveToElementText(node);
  48. }
  49. restoreSelection = rng.parentElement().ownerDocument === editor.getDoc();
  50. tmpRng = rng.duplicate();
  51. tmpRng.collapse(true);
  52. startOffset = tmpRng.move('character', offset) * -1;
  53. if (!tmpRng.collapsed) {
  54. tmpRng = rng.duplicate();
  55. tmpRng.collapse(false);
  56. endOffset = (tmpRng.move('character', offset) * -1) - startOffset;
  57. }
  58. }
  59. // Wrap non block elements and text nodes
  60. node = rootNode.firstChild;
  61. rootNodeName = rootNode.nodeName.toLowerCase();
  62. while (node) {
  63. // TODO: Break this up, too complex
  64. if (((node.nodeType === 3 || (node.nodeType == 1 && !blockElements[node.nodeName]))) &&
  65. schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase())) {
  66. // Remove empty text nodes
  67. if (node.nodeType === 3 && node.nodeValue.length === 0) {
  68. tempNode = node;
  69. node = node.nextSibling;
  70. dom.remove(tempNode);
  71. continue;
  72. }
  73. if (!rootBlockNode) {
  74. rootBlockNode = dom.create(forcedRootBlock, editor.settings.forced_root_block_attrs);
  75. node.parentNode.insertBefore(rootBlockNode, node);
  76. wrapped = true;
  77. }
  78. tempNode = node;
  79. node = node.nextSibling;
  80. rootBlockNode.appendChild(tempNode);
  81. } else {
  82. rootBlockNode = null;
  83. node = node.nextSibling;
  84. }
  85. }
  86. if (wrapped && restoreSelection) {
  87. if (rng.setStart) {
  88. rng.setStart(startContainer, startOffset);
  89. rng.setEnd(endContainer, endOffset);
  90. selection.setRng(rng);
  91. } else {
  92. // Only select if the previous selection was inside the document to prevent auto focus in quirks mode
  93. try {
  94. rng = editor.getDoc().body.createTextRange();
  95. rng.moveToElementText(rootNode);
  96. rng.collapse(true);
  97. rng.moveStart('character', startOffset);
  98. if (endOffset > 0) {
  99. rng.moveEnd('character', endOffset);
  100. }
  101. rng.select();
  102. } catch (ex) {
  103. // Ignore
  104. }
  105. }
  106. editor.nodeChanged();
  107. }
  108. }
  109. // Force root blocks
  110. if (settings.forced_root_block) {
  111. editor.on('NodeChange', addRootBlocks);
  112. }
  113. };
  114. });