section.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /**
  2. * 目录大纲支持插件
  3. * @file
  4. * @since 1.3.0
  5. */
  6. UE.plugin.register("section", function() {
  7. /* 目录节点对象 */
  8. function Section(option) {
  9. this.tag = "";
  10. (this.level = -1), (this.dom = null);
  11. this.nextSection = null;
  12. this.previousSection = null;
  13. this.parentSection = null;
  14. this.startAddress = [];
  15. this.endAddress = [];
  16. this.children = [];
  17. }
  18. function getSection(option) {
  19. var section = new Section();
  20. return utils.extend(section, option);
  21. }
  22. function getNodeFromAddress(startAddress, root) {
  23. var current = root;
  24. for (var i = 0; i < startAddress.length; i++) {
  25. if (!current.childNodes) return null;
  26. current = current.childNodes[startAddress[i]];
  27. }
  28. return current;
  29. }
  30. var me = this;
  31. return {
  32. bindMultiEvents: {
  33. type: "aftersetcontent afterscencerestore",
  34. handler: function() {
  35. me.fireEvent("updateSections");
  36. }
  37. },
  38. bindEvents: {
  39. /* 初始化、拖拽、粘贴、执行setcontent之后 */
  40. ready: function() {
  41. me.fireEvent("updateSections");
  42. domUtils.on(me.body, "drop paste", function() {
  43. me.fireEvent("updateSections");
  44. });
  45. },
  46. /* 执行paragraph命令之后 */
  47. afterexeccommand: function(type, cmd) {
  48. if (cmd == "paragraph") {
  49. me.fireEvent("updateSections");
  50. }
  51. },
  52. /* 部分键盘操作,触发updateSections事件 */
  53. keyup: function(type, e) {
  54. var me = this,
  55. range = me.selection.getRange();
  56. if (range.collapsed != true) {
  57. me.fireEvent("updateSections");
  58. } else {
  59. var keyCode = e.keyCode || e.which;
  60. if (keyCode == 13 || keyCode == 8 || keyCode == 46) {
  61. me.fireEvent("updateSections");
  62. }
  63. }
  64. }
  65. },
  66. commands: {
  67. getsections: {
  68. execCommand: function(cmd, levels) {
  69. var levelFn = levels || ["h1", "h2", "h3", "h4", "h5", "h6"];
  70. for (var i = 0; i < levelFn.length; i++) {
  71. if (typeof levelFn[i] == "string") {
  72. levelFn[i] = (function(fn) {
  73. return function(node) {
  74. return node.tagName == fn.toUpperCase();
  75. };
  76. })(levelFn[i]);
  77. } else if (typeof levelFn[i] != "function") {
  78. levelFn[i] = function(node) {
  79. return null;
  80. };
  81. }
  82. }
  83. function getSectionLevel(node) {
  84. for (var i = 0; i < levelFn.length; i++) {
  85. if (levelFn[i](node)) return i;
  86. }
  87. return -1;
  88. }
  89. var me = this,
  90. Directory = getSection({ level: -1, title: "root" }),
  91. previous = Directory;
  92. function traversal(node, Directory) {
  93. var level,
  94. tmpSection = null,
  95. parent,
  96. child,
  97. children = node.childNodes;
  98. for (var i = 0, len = children.length; i < len; i++) {
  99. child = children[i];
  100. level = getSectionLevel(child);
  101. if (level >= 0) {
  102. var address = me.selection
  103. .getRange()
  104. .selectNode(child)
  105. .createAddress(true).startAddress,
  106. current = getSection({
  107. tag: child.tagName,
  108. title: child.innerText || child.textContent || "",
  109. level: level,
  110. dom: child,
  111. startAddress: utils.clone(address, []),
  112. endAddress: utils.clone(address, []),
  113. children: []
  114. });
  115. previous.nextSection = current;
  116. current.previousSection = previous;
  117. parent = previous;
  118. while (level <= parent.level) {
  119. parent = parent.parentSection;
  120. }
  121. current.parentSection = parent;
  122. parent.children.push(current);
  123. tmpSection = previous = current;
  124. } else {
  125. child.nodeType === 1 && traversal(child, Directory);
  126. tmpSection &&
  127. tmpSection.endAddress[tmpSection.endAddress.length - 1]++;
  128. }
  129. }
  130. }
  131. traversal(me.body, Directory);
  132. return Directory;
  133. },
  134. notNeedUndo: true
  135. },
  136. movesection: {
  137. execCommand: function(cmd, sourceSection, targetSection, isAfter) {
  138. var me = this,
  139. targetAddress,
  140. target;
  141. if (!sourceSection || !targetSection || targetSection.level == -1)
  142. return;
  143. targetAddress = isAfter
  144. ? targetSection.endAddress
  145. : targetSection.startAddress;
  146. target = getNodeFromAddress(targetAddress, me.body);
  147. /* 判断目标地址是否被源章节包含 */
  148. if (
  149. !targetAddress ||
  150. !target ||
  151. isContainsAddress(
  152. sourceSection.startAddress,
  153. sourceSection.endAddress,
  154. targetAddress
  155. )
  156. )
  157. return;
  158. var startNode = getNodeFromAddress(
  159. sourceSection.startAddress,
  160. me.body
  161. ),
  162. endNode = getNodeFromAddress(sourceSection.endAddress, me.body),
  163. current,
  164. nextNode;
  165. if (isAfter) {
  166. current = endNode;
  167. while (
  168. current &&
  169. !(
  170. domUtils.getPosition(startNode, current) &
  171. domUtils.POSITION_FOLLOWING
  172. )
  173. ) {
  174. nextNode = current.previousSibling;
  175. domUtils.insertAfter(target, current);
  176. if (current == startNode) break;
  177. current = nextNode;
  178. }
  179. } else {
  180. current = startNode;
  181. while (
  182. current &&
  183. !(
  184. domUtils.getPosition(current, endNode) &
  185. domUtils.POSITION_FOLLOWING
  186. )
  187. ) {
  188. nextNode = current.nextSibling;
  189. target.parentNode.insertBefore(current, target);
  190. if (current == endNode) break;
  191. current = nextNode;
  192. }
  193. }
  194. me.fireEvent("updateSections");
  195. /* 获取地址的包含关系 */
  196. function isContainsAddress(startAddress, endAddress, addressTarget) {
  197. var isAfterStartAddress = false,
  198. isBeforeEndAddress = false;
  199. for (var i = 0; i < startAddress.length; i++) {
  200. if (i >= addressTarget.length) break;
  201. if (addressTarget[i] > startAddress[i]) {
  202. isAfterStartAddress = true;
  203. break;
  204. } else if (addressTarget[i] < startAddress[i]) {
  205. break;
  206. }
  207. }
  208. for (var i = 0; i < endAddress.length; i++) {
  209. if (i >= addressTarget.length) break;
  210. if (addressTarget[i] < startAddress[i]) {
  211. isBeforeEndAddress = true;
  212. break;
  213. } else if (addressTarget[i] > startAddress[i]) {
  214. break;
  215. }
  216. }
  217. return isAfterStartAddress && isBeforeEndAddress;
  218. }
  219. }
  220. },
  221. deletesection: {
  222. execCommand: function(cmd, section, keepChildren) {
  223. var me = this;
  224. if (!section) return;
  225. function getNodeFromAddress(startAddress) {
  226. var current = me.body;
  227. for (var i = 0; i < startAddress.length; i++) {
  228. if (!current.childNodes) return null;
  229. current = current.childNodes[startAddress[i]];
  230. }
  231. return current;
  232. }
  233. var startNode = getNodeFromAddress(section.startAddress),
  234. endNode = getNodeFromAddress(section.endAddress),
  235. current = startNode,
  236. nextNode;
  237. if (!keepChildren) {
  238. while (
  239. current &&
  240. domUtils.inDoc(endNode, me.document) &&
  241. !(
  242. domUtils.getPosition(current, endNode) &
  243. domUtils.POSITION_FOLLOWING
  244. )
  245. ) {
  246. nextNode = current.nextSibling;
  247. domUtils.remove(current);
  248. current = nextNode;
  249. }
  250. } else {
  251. domUtils.remove(current);
  252. }
  253. me.fireEvent("updateSections");
  254. }
  255. },
  256. selectsection: {
  257. execCommand: function(cmd, section) {
  258. if (!section && !section.dom) return false;
  259. var me = this,
  260. range = me.selection.getRange(),
  261. address = {
  262. startAddress: utils.clone(section.startAddress, []),
  263. endAddress: utils.clone(section.endAddress, [])
  264. };
  265. address.endAddress[address.endAddress.length - 1]++;
  266. range.moveToAddress(address).select().scrollToView();
  267. return true;
  268. },
  269. notNeedUndo: true
  270. },
  271. scrolltosection: {
  272. execCommand: function(cmd, section) {
  273. if (!section && !section.dom) return false;
  274. var me = this,
  275. range = me.selection.getRange(),
  276. address = {
  277. startAddress: section.startAddress,
  278. endAddress: section.endAddress
  279. };
  280. address.endAddress[address.endAddress.length - 1]++;
  281. range.moveToAddress(address).scrollToView();
  282. return true;
  283. },
  284. notNeedUndo: true
  285. }
  286. }
  287. };
  288. });