yzPage.js 61 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539
  1. import $ from './util/dom-core.js';
  2. import {getParentByClassname, getParentNodeByClass, isEmptyElement, trim} from './util/util.js';
  3. import QuestionTools from './util/question';
  4. import JQuery from 'jquery';
  5. let yzPage = function (manage, $page) {
  6. this.manage = manage;
  7. this.editor = manage.editor;
  8. this.pageIndex = this.manage.pageIndex;
  9. this.id = ('lsiten_editor_page_'+Math.random()).replace('.','_') + this.pageIndex;
  10. this.$textElem = $('<div class="js-page-content" id = "' +this.id+ '"></div>');
  11. this.$colums = [];
  12. this.paragraphIndex = 0;
  13. // 已经初始化后的内容
  14. this.$page = $page;
  15. this.lineHeight = 25;
  16. this._init();
  17. manage.$el.append(this.$textElem);
  18. }
  19. yzPage.prototype = {
  20. constructor: yzPage,
  21. _init: function () {
  22. this._initStyles();
  23. this._initColumn();
  24. this._initPositionPlaceholder();
  25. this._initPAndNPlaceholder();
  26. this.questionTools = new QuestionTools();
  27. },
  28. /**
  29. * function 初始化样式
  30. */
  31. _initStyles: function () {
  32. this.$textElem.css('position', 'relative')
  33. .css('outline', 'none')
  34. .css('word-wrap', 'break-word')
  35. .css('font-size', '14px')
  36. .css('-webkit-line-break', 'after-white-space')
  37. .css('height', this._pagesHeight[this.editor.pageSize])
  38. },
  39. /**
  40. * function 初始化栏
  41. */
  42. _initColumn: function () {
  43. let colums = this.editor.columnNumber;
  44. let height = this._pagesHeight[this.editor.pageSize];
  45. let widthColumn = 100 / colums + '%';
  46. // 初始化栏数据
  47. let $columnData = [];
  48. if (this.$page) {
  49. $columnData = this.$page.find('.js-column');
  50. }
  51. for (let i = 0; i < colums; i++) {
  52. let $columItem = null;
  53. if ($columnData[i]) {
  54. $columItem = $($columnData[i]);
  55. } else {
  56. $columItem = $('<div class="lsiten-colum-' + this.pageIndex + '-' + i + ' js-column"></div>');
  57. $columItem.attr('data-column-i', i);
  58. $columItem.attr('data-column-page', this.pageIndex);
  59. // $columItem.attr('contenteditable', true);
  60. $columItem.css('height', height);
  61. $columItem.css('position', 'relative');
  62. $columItem.css('overflow', 'hidden');
  63. $columItem.css('float', 'left');
  64. $columItem.css('width', widthColumn);
  65. }
  66. this.$colums.push($columItem);
  67. this.$textElem.append($columItem);
  68. }
  69. this.currentColumn = 0;
  70. },
  71. /**
  72. * function 添加表头
  73. */
  74. addHeader: function () {
  75. this.editor.cmd.do('answerHeader', this);
  76. },
  77. /**
  78. * function 添加段落
  79. */
  80. addParagraph: function () {
  81. let $column = this.$colums[this.currentColumn];
  82. let $paragraph = $('<div class="js-paragraph-view"></div>');
  83. $paragraph.css('margin', 0)
  84. .css('padding', '0 25px')
  85. .css('outline', 'none')
  86. .css('box-sizing', 'border-box')
  87. .css('white-space', 'pre-wrap')
  88. .css('line-height', '1.75')
  89. .css('text-align', 'left');
  90. let index = this.pageIndex + '-' + this.paragraphIndex++;
  91. $paragraph.attr('data-index', index);
  92. let $currentParagraph = this.manage.editorPosition.currentParagraph;
  93. if (!$currentParagraph && !$column[0].childNodes.length) {
  94. $column.append($paragraph);
  95. } else {
  96. if (this.manage.editorPosition.currentParagraph !== this.$el) {
  97. $column.append($paragraph);
  98. } else {
  99. $paragraph.insertAfter($currentParagraph);
  100. }
  101. }
  102. return $paragraph;
  103. },
  104. // 更新头部
  105. updateHeader: function () {
  106. },
  107. _placeholderTemplate: function () {
  108. let $postionDom = $('<div></div>');
  109. $postionDom.css('background-color', '#000');
  110. $postionDom.css('position', 'absolute');
  111. $postionDom.attr('contenteditable', false);
  112. $postionDom.html('&#8203;');
  113. $postionDom.css('width', '25px');
  114. $postionDom.css('height', '16px');
  115. return $postionDom;
  116. },
  117. /**
  118. * function 生成正反面定位符
  119. */
  120. _initPAndNPlaceholder: function () {
  121. let count = this.pageIndex + 2;
  122. for (let i = 0; i < count; i++) {
  123. let template = this._placeholderTemplate();
  124. let top = i * 22 - 16;
  125. template.css('width', '25px').css('height', '16px').css('left', '-25px').css('top', top + 'px');
  126. this.$textElem.append(template);
  127. }
  128. },
  129. /**
  130. * function 初始化占位符
  131. */
  132. _initPositionPlaceholder: function () {
  133. let $columns = this.$colums;
  134. let clength = $columns.length;
  135. let cwidth = this._pagesWidth[this.editor.pageSize] / clength;
  136. let lastIndex = clength - 1;
  137. for (let i = 0; i < clength; i++) {
  138. let $template = this._placeholderTemplate();
  139. let $templateb = this._placeholderTemplate();
  140. let left = i * cwidth - 25;
  141. if (i > 0) {
  142. left += 15
  143. $template.css('left', left + 'px').css('top', '-16px');
  144. this.$textElem.append($template);
  145. }
  146. $templateb.css('left', left + 'px').css('bottom', '-16px');
  147. this.$textElem.append($templateb);
  148. if (i === lastIndex) {
  149. let $template1 = this._placeholderTemplate();
  150. let $template1b = this._placeholderTemplate();
  151. $template1.css('right', '-25px').css('top', '-16px');
  152. $template1b.css('right', '-25px').css('bottom', '-16px');
  153. this.$textElem.append($template1);
  154. this.$textElem.append($template1b);
  155. }
  156. }
  157. },
  158. /**
  159. * function 更新跨栏符
  160. */
  161. _updateCrossColumn: function ($column) {
  162. let index =parseInt($column.attr('data-column-i'));
  163. if (index === 0) {
  164. return '';
  165. }
  166. let column = $column[0];
  167. let firstParagh = column.firstChild;
  168. firstParagh = this._cycleFindParagraph(firstParagh);
  169. if (firstParagh) {
  170. let page = column.parentNode;
  171. if (page) {
  172. let $page = $(page);
  173. let columnIndex = parseInt(column.getAttribute('data-column-i'));
  174. let crossPlaceholder = '.js-cross-placeholder-' + columnIndex;
  175. let classname = 'js-cross-placeholder-' + columnIndex;
  176. let $placeholder = $page.find(crossPlaceholder);
  177. let firstBorder = firstParagh.firstChild;
  178. if (firstParagh.className && firstParagh.className.indexOf('js-split-paragraph') > -1) {
  179. if (firstBorder && firstBorder.className && firstBorder.className.indexOf('js-lsiten-border') > -1) {
  180. if (!$placeholder.length) {
  181. // 添加跨栏符
  182. // 判断是否有该栏跨栏符
  183. let $template = this._placeholderTemplate();
  184. let cwidth = this._pagesWidth[this.editor.pageSize] / parseInt(this.editor.columnNumber);
  185. let left = columnIndex * cwidth + 20;
  186. $template.css('left', left + 'px').css('top', '-15px').css('width', '12px').css('height', '12px');
  187. $template.addClass(classname);
  188. $page.append($template);
  189. }
  190. }
  191. } else {
  192. if (firstBorder && firstBorder.className && firstBorder.className.indexOf('js-lsiten-border') > -1) {
  193. if ($placeholder.length > 0) {
  194. // 删除跨栏符
  195. $placeholder.remove();
  196. }
  197. }
  198. }
  199. }
  200. } else {
  201. let page = column.parentNode;
  202. if (page) {
  203. let $page = $(page);
  204. let columnIndex = parseInt(column.getAttribute('data-column-i'));
  205. let crossPlaceholder = '.js-cross-placeholder-' + columnIndex;
  206. let classname = 'js-cross-placeholder-' + columnIndex;
  207. let $placeholder = $page.find(crossPlaceholder);
  208. if ($placeholder.length > 0) {
  209. // 删除跨栏符
  210. $placeholder.remove();
  211. }
  212. }
  213. }
  214. },
  215. /**
  216. * function 循环查找段落
  217. */
  218. _cycleFindParagraph: function (paragraph) {
  219. if (!paragraph) {
  220. return null;
  221. }
  222. let i = 0;
  223. while (i < 100 && (!paragraph.className || paragraph.className.indexOf('js-paragraph-view') < 0)) {
  224. let temp = paragraph.nextSibling;
  225. paragraph.parentNode.removeChild(paragraph);
  226. paragraph = temp;
  227. i++;
  228. }
  229. let firstContent = paragraph.firstChild;
  230. if (firstContent && firstContent.className && firstContent.className.indexOf('js-answer-header') > -1) {
  231. let temp = paragraph.nextSibling;
  232. paragraph = temp;
  233. return this._cycleFindParagraph(paragraph);
  234. }
  235. return paragraph || null;
  236. },
  237. /**
  238. * @param {DomElement} $column 栏dom
  239. */
  240. _checkColumnOut($column) {
  241. let $paragraphs = $column.find('.js-paragraph-view');
  242. let cSize = $column.getSizeData();
  243. let i = $paragraphs.length - 1;
  244. let $moves = [];
  245. while (i >=0 ) {
  246. let $paragraph = $($paragraphs[i]);
  247. let pSize = $paragraph.getSizeData();
  248. if (pSize.top >= cSize.bottom) {
  249. $moves.push($paragraph);
  250. } else if (pSize.bottom >= cSize.bottom) {
  251. this._splitParagraph($moves, $paragraph, cSize, $column);
  252. }
  253. i--;
  254. }
  255. if ($moves.length > 0) {
  256. let nextColumn = this._getNextColumn($column, true);
  257. if (nextColumn.column) {
  258. let $firsParagraph = this._getFirstPargraph(nextColumn.column);
  259. if ($firsParagraph) {
  260. $moves.forEach(item => {
  261. this._insertParagraph(item, $firsParagraph);
  262. })
  263. } else {
  264. let moveIndex = $moves.length - 1;
  265. while (moveIndex >=0 ) {
  266. nextColumn.column.append($moves[moveIndex]);
  267. moveIndex--;
  268. }
  269. }
  270. nextColumn.page._checkColumnOut(nextColumn.column);
  271. // 跨栏符检测
  272. let $lastParagraph = $paragraphs[$paragraphs.length - 1];
  273. if (isEmptyElement($lastParagraph)) {
  274. $lastParagraph.remove();
  275. }
  276. this._checkIsCross($firsParagraph, nextColumn.column);
  277. this._updateCrossColumn(nextColumn.column);
  278. this._updateObjectColumnHeight(nextColumn.column[0]);
  279. }
  280. // 跨栏符检测
  281. this._checkIsCross($($paragraphs[$paragraphs.length - 1]), $column);
  282. this._updateCrossColumn($column);
  283. }
  284. },
  285. /**
  286. * function 更新客观题栏高
  287. */
  288. _updateObjectColumnHeight: function (checkColumn) {
  289. let updateNextPara = this._cycleFindParagraph(checkColumn.firstChild);
  290. if (updateNextPara) {
  291. this._updateObjectColumnHeightByBorder(updateNextPara);
  292. // 更新栏高 结束
  293. this._updateObjectColumnBorder(updateNextPara);
  294. }
  295. },
  296. /**
  297. * function 更新客观题栏行线
  298. */
  299. _updateObjectColumnHeightByBorder: function (border) {
  300. let cententHeight = 0;
  301. $(border).find('.js-option-column').forEach(column => {
  302. let contentSize = $(column.firstChild).getSizeData();
  303. cententHeight = contentSize.height;
  304. $(column).css('min-height', cententHeight + 'px');
  305. });
  306. },
  307. /**
  308. * function 更新客观题栏行线
  309. */
  310. _updateObjectColumnBorder: function (border) {
  311. let rowIndex = 0;
  312. $(border).find('.js-options-row').forEach(row => {
  313. if (rowIndex > 0) {
  314. $(row).css('border-top', '1px solid #000');
  315. }
  316. rowIndex++;
  317. })
  318. },
  319. /**
  320. * function 插入段落
  321. * @param {DomElement} $insertParagraph 需要插入的段落
  322. * @param {DomElement} $firsParagraph 插入该段之前
  323. */
  324. _insertParagraph: function ($insertParagraph, $firsParagraph) {
  325. let insertClass = $insertParagraph.attr('class');
  326. let firstClass = $firsParagraph.attr('class');
  327. if (insertClass && firstClass && insertClass.indexOf('js-split-paragraph') >-1 && firstClass.indexOf('js-split-paragraph') >-1) {
  328. let insertLast = $insertParagraph[0].lastChild;
  329. let firstFirst = $firsParagraph[0].firstChild;
  330. this._mergeSplitParagraph(insertLast, firstFirst, $insertParagraph);
  331. } else {
  332. $insertParagraph.insertBefore($firsParagraph);
  333. }
  334. },
  335. /**
  336. * function 检测最后一段是否需要跨栏
  337. * @param {DomElement} $lastParagraph 该栏最后一段
  338. * @param {DomElement} $column 该栏
  339. */
  340. _checkIsCross: function ($lastParagraph, $column) {
  341. if (!$lastParagraph || !$lastParagraph[0]) {
  342. return false;
  343. }
  344. let $prevColumn = this._getPrevColumn_v2($column);
  345. let $nextColumn = this._getNextColumn_v2($column);
  346. let currentIndex = $lastParagraph.attr('data-index');
  347. let prevIndex = '';
  348. let nextIndex = '';
  349. if ($prevColumn) {
  350. let $paragraphs = $prevColumn.find('.js-paragraph-view');
  351. let lastIndex = $paragraphs.length - 1;
  352. if (lastIndex) {
  353. prevIndex = $paragraphs[lastIndex].getAttribute('data-index');
  354. }
  355. }
  356. if ($nextColumn) {
  357. let $nextParagraphs = $nextColumn.find('.js-paragraph-view');
  358. let nextLastIndex = $nextParagraphs.length - 1;
  359. if (nextLastIndex) {
  360. nextIndex = $nextParagraphs[nextLastIndex].getAttribute('data-index');
  361. }
  362. }
  363. if (currentIndex === prevIndex || currentIndex === nextIndex) {
  364. $lastParagraph.addClass('js-split-paragraph');
  365. } else {
  366. $lastParagraph.removeClass('js-split-paragraph');
  367. }
  368. },
  369. /**
  370. * function 获取该栏上一栏
  371. * @param {DomElement} $column 该栏
  372. */
  373. _getPrevColumn_v2: function ($column) {
  374. let prev = $column[0].previousSibling;
  375. if (prev && prev.className && prev.className.indexOf('js-column') > -1) {
  376. return $(prev);
  377. }
  378. let prevIndex = this.pageIndex - 1;
  379. if (prevIndex < 0) {
  380. return false;
  381. }
  382. let prevPage = this.manage.pages[prevIndex];
  383. let lastColumnIndex = prevPage.$colums.length - 1;
  384. return prevPage.$colums[lastColumnIndex] || false;
  385. },
  386. /**
  387. * function 获取该栏下一栏
  388. * @param {DomElement} $column 该栏
  389. */
  390. _getNextColumn_v2: function ($column) {
  391. let next = $column[0].nextSibling;
  392. if (next && next.className && next.className.indexOf('js-column') > -1) {
  393. return $(next);
  394. }
  395. let nextIndex = this.pageIndex + 1;
  396. if (nextIndex < 0) {
  397. return false;
  398. }
  399. let nextPage = this.manage.pages[nextIndex];
  400. if (!nextPage) {
  401. return false;
  402. }
  403. return nextPage.$colums[0] || false;
  404. },
  405. /**
  406. * function 插入内容在该dom之前
  407. * @param {DomElement}
  408. */
  409. _insertDomBeforeByFirst: function ($paragraph, first) {
  410. $paragraph.childNodes().forEach(child => {
  411. $(child).insertBefore($(first));
  412. })
  413. },
  414. /**
  415. * function 合并拆分过的段落
  416. * @param {node} 上一段最后一个dom
  417. * @param {node} 下一段第一个dom
  418. * @param {DomElement} 需要插入的段落
  419. */
  420. _mergeSplitParagraph: function (insertLast, firstFirst, $Allparagraph) {
  421. if (!insertLast) {
  422. return false;
  423. }
  424. if (insertLast.className && insertLast.className.indexOf('js-lsiten-line') > -1) {
  425. // 普通行处理
  426. this._insertDomBeforeByFirst($Allparagraph, firstFirst);
  427. } else if (insertLast.className && insertLast.className.indexOf('js-lsiten-border') > -1) {
  428. // 框处理
  429. if (firstFirst && firstFirst.className && firstFirst.className.indexOf('js-lsiten-border') > -1) {
  430. // 如果下一段第一个dom是框
  431. let borderId = insertLast.getAttribute('data-id');
  432. let nextBorderId = firstFirst.getAttribute('data-id');
  433. if (borderId === nextBorderId) {
  434. // 如果两个框是同一个框
  435. let borderType = parseInt(firstFirst.getAttribute('data-type'));
  436. if (borderType === 1) {
  437. let objectLastRow = insertLast.lastChild;
  438. let objectFirstRow = firstFirst.firstChild;
  439. let lastRowId = objectLastRow.getAttribute('data-id');
  440. let firstRowId = objectFirstRow.getAttribute('data-id');
  441. if (lastRowId === firstRowId) {
  442. let lastRowColumns = $(objectLastRow).find('.js-option-column');
  443. let firstRowColumns = $(objectFirstRow).find('.js-option-column');
  444. let rowColumnLength = lastRowColumns.length;
  445. for (let rowColumnIndex = 0; rowColumnIndex < rowColumnLength; rowColumnIndex++) {
  446. if (firstRowColumns[rowColumnIndex].firstChild && firstRowColumns[rowColumnIndex].firstChild.firstChild) {
  447. this._insertDomBeforeByFirst($(lastRowColumns[rowColumnIndex].firstChild), firstRowColumns[rowColumnIndex].firstChild.firstChild);
  448. } else {
  449. if (lastRowColumns[rowColumnIndex].firstChild && firstRowColumns[rowColumnIndex].firstChild) {
  450. let lastRowColumnsChilds = $(lastRowColumns[rowColumnIndex].firstChild).childNodes();
  451. let lastRowColumnsChildsIndex = lastRowColumnsChilds.length - 1;
  452. while(lastRowColumnsChildsIndex >= 0) {
  453. firstRowColumns[rowColumnIndex].firstChild.appendChild(lastRowColumnsChilds[lastRowColumnsChildsIndex]);
  454. lastRowColumnsChildsIndex--;
  455. }
  456. }
  457. }
  458. }
  459. $(objectLastRow).remove();
  460. this._insertDomBeforeByFirst($(insertLast), objectFirstRow);
  461. } else {
  462. if (!this.isObjectEmpty(insertLast)) {
  463. this._insertDomBeforeByFirst($(insertLast), objectFirstRow);
  464. }
  465. }
  466. } else if (borderType === 2) {
  467. let insertLastQuestion = insertLast.firstChild.lastChild;
  468. let firstFirstQuestion = firstFirst.firstChild.firstChild;
  469. this._mergeSplitBorder(insertLastQuestion, firstFirstQuestion, $(insertLast));
  470. this._insertDomBeforeByFirst($Allparagraph, firstFirst);
  471. }
  472. } else {
  473. // 如果不是同一个框
  474. this._insertDomBeforeByFirst($Allparagraph, firstFirst);
  475. }
  476. } else {
  477. // 如果下一段第一个dom不是框
  478. this._insertDomBeforeByFirst($Allparagraph, firstFirst);
  479. }
  480. } else {
  481. let parentNode = insertLast.parentNode;
  482. $(insertLast).remove();
  483. this._mergeSplitParagraph(parentNode.lastChild, firstFirst);
  484. }
  485. },
  486. /**
  487. * function 判断客观题框是否为空
  488. * @param {node} object 客观题框
  489. */
  490. isObjectEmpty: function (object) {
  491. let $object = $(object);
  492. $object.childNodes().forEach(row => {
  493. if(this.isObjectRowEmpty(row)) {
  494. $(row).remove();
  495. }
  496. })
  497. return isEmptyElement(object);
  498. },
  499. /**
  500. * function 判断客观题框行是否为空
  501. * @param {node} objectRow 客观题行
  502. */
  503. isObjectRowEmpty: function (objectRow) {
  504. let $objectRow = $(objectRow);
  505. let status = true;
  506. $objectRow.childNodes().forEach(colum => {
  507. if (!isEmptyElement(colum.firstChild)) {
  508. status = false;
  509. }
  510. })
  511. return status;
  512. },
  513. /**
  514. * function 合并框
  515. * @param {node} lQuestion 上一段最后一个问题
  516. * @param {node} fQuestion 下一段第一个问题
  517. * @param {DomElement} $Allborder 该框所有dom
  518. */
  519. _mergeSplitBorder: function (lQuestion, fQuestion, $Allborder) {
  520. if (!lQuestion) {
  521. return false;
  522. }
  523. if (lQuestion.className && lQuestion.className.indexOf('js-lsiten-line') > -1) {
  524. // 普通行处理
  525. this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
  526. $Allborder.remove();
  527. } else if (lQuestion.className && lQuestion.className.indexOf('js-lsiten-options-box') > -1) {
  528. // 选作题组
  529. this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
  530. $Allborder.remove();
  531. } else if (lQuestion.className && lQuestion.className.indexOf('js-lsiten-question') > -1) {
  532. // 主观题才需要合并
  533. let type = parseInt(lQuestion.getAttribute('data-type'));
  534. if (type > 2) {
  535. if (fQuestion.className && fQuestion.className.indexOf('js-lsiten-question') > -1) {
  536. let questionId = lQuestion.getAttribute('data-id');
  537. let nextQuestionId = fQuestion.getAttribute('data-id');
  538. if (questionId === nextQuestionId) {
  539. // 不是同一个题
  540. if (type === 3) {
  541. // 客观题
  542. let $lquestion = $(lQuestion);
  543. let fQuestionFirst = fQuestion.firstChild;
  544. this._insertDomBeforeByFirst($lquestion, fQuestionFirst);
  545. $lquestion.remove();
  546. this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
  547. $Allborder.remove();
  548. } else if (type === 4) {
  549. // 作文题
  550. let questionContent = lQuestion.lastChild;
  551. let firstContent = fQuestion.firstChild;
  552. if (questionContent.className && questionContent.className.indexOf('lsiten-title') > -1) {
  553. if (firstContent.className && firstContent.className.indexOf('lsiten-title') > -1) {
  554. let $writtingTitle = $(questionContent);
  555. this._insertDomBeforeByFirst($writtingTitle, firstContent.firstChild);
  556. $writtingTitle.remove();
  557. this._insertDomBeforeByFirst($(lQuestion), firstContent);
  558. $(lQuestion).remove();
  559. this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
  560. $Allborder.remove();
  561. } else {
  562. this._insertDomBeforeByFirst($(lQuestion), firstContent);
  563. $(lQuestion).remove();
  564. this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
  565. $Allborder.remove();
  566. }
  567. } else if (questionContent.className && questionContent.className.indexOf('lsiten-border-box') > -1) {
  568. if (firstContent.className && firstContent.className.indexOf('lsiten-border-box') > -1) {
  569. let $writtingRows = $(questionContent);
  570. this._insertDomBeforeByFirst($writtingRows, firstContent.firstChild);
  571. $writtingRows.remove();
  572. this._insertDomBeforeByFirst($(lQuestion), firstContent);
  573. $(lQuestion).remove();
  574. this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
  575. $Allborder.remove();
  576. } else {
  577. this._insertDomBeforeByFirst($(lQuestion), firstContent);
  578. $(lQuestion).remove();
  579. this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
  580. $Allborder.remove();
  581. }
  582. } else {
  583. questionContent && questionContent.parentNode.removeChild(questionContent);
  584. }
  585. }
  586. } else {
  587. // 不是同一个题
  588. this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
  589. $Allborder.remove();
  590. }
  591. } else {
  592. // 下一段第一个不是一个问题
  593. this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
  594. $Allborder.remove();
  595. }
  596. } else {
  597. // 客观题处理
  598. this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
  599. $Allborder.remove();
  600. }
  601. } else {
  602. let parentNode = lQuestion.parentNode;
  603. $(lQuestion).remove();
  604. this._mergeSplitBorder(parentNode.lastChild, fQuestion, $Allborder);
  605. }
  606. },
  607. /**
  608. * function 检测内容是否需要回退
  609. */
  610. _checkContentBack: function () {
  611. let $columns = this.$colums;
  612. // 备用
  613. let maxHeight = parseInt(this._pagesHeight[this.editor.pageSize]);
  614. $columns.forEach($column => {
  615. this._checkColumnBack($column);
  616. });
  617. this.manage._checkRemovePage();
  618. },
  619. /**
  620. * function 检测该段落是否为答题卡头
  621. * @param {DomElement} 需要检测的段落
  622. */
  623. isHeadParagraph: function ($paragraph) {
  624. if (!$paragraph || !$paragraph[0]) {
  625. return false;
  626. }
  627. let firstChild = $paragraph[0].firstChild;
  628. return firstChild && firstChild.className && firstChild.className.indexOf('js-answer-header') > -1;
  629. },
  630. /**
  631. * function 检测栏是否需要回退
  632. * @param {DomElement} $column 需要检测的栏
  633. */
  634. _checkColumnBack: function ($column) {
  635. let $paragraphs = $column.find('.js-paragraph-view');
  636. let cSize = $column.getSizeData();
  637. let i = $paragraphs.length - 1;
  638. let $moves = [];
  639. if (!$paragraphs[i]) {
  640. return false;
  641. }
  642. let $lastParagraph = $($paragraphs[i]);
  643. let lastSize = $lastParagraph.getSizeData();
  644. let diff = cSize.bottom - lastSize.bottom;
  645. if (diff > this.lineHeight) {
  646. let nextColumn = this._getNextColumn($column, false);
  647. // 如果有下一页,进行检测
  648. if (nextColumn.column) {
  649. let $nextParagraphs = nextColumn.column.find('.js-paragraph-view');
  650. let j = 0;
  651. let nextParagraphLength = $nextParagraphs.length || 0;
  652. while (j < nextParagraphLength) {
  653. if (j > 0) {
  654. let prevIndex = j - 1;
  655. if ($nextParagraphs[prevIndex] && !isEmptyElement($nextParagraphs[prevIndex]) && !this.isHeadParagraph($($nextParagraphs[prevIndex]))) {
  656. j++;
  657. continue;
  658. }
  659. }
  660. if ($nextParagraphs[j]) {
  661. let $paragraph = $($nextParagraphs[j]);
  662. if ($paragraph && !this.isHeadParagraph($paragraph)) {
  663. let pSize = $paragraph.getSizeData();
  664. if (pSize.height < diff) {
  665. $moves.push($paragraph);
  666. } else {
  667. let size = {
  668. diff: diff
  669. }
  670. this._prevParagraph($moves, $paragraph, size, $lastParagraph);
  671. }
  672. }
  673. }
  674. j++;
  675. }
  676. let lastPid = $lastParagraph.attr('data-index');
  677. let lastBorderItem = $lastParagraph[0].lastChild;
  678. let lastIsBorder = lastBorderItem && lastBorderItem.className && lastBorderItem.className.indexOf('js-lsiten-border') > -1;
  679. $moves.forEach($paragraphITem => {
  680. let currentPid = $paragraphITem.attr('data-index');
  681. if (lastPid === currentPid) {
  682. $paragraphITem.childNodes().forEach(item => {
  683. if (item.nodeType === 3) {
  684. $paragraph[0].removeChild(item);
  685. } else {
  686. let $item = $(item);
  687. let itemClass = $item.attr('class');
  688. if (itemClass && itemClass.indexOf('js-lsiten-line') > -1) {
  689. // 普通行
  690. $lastParagraph.append($item);
  691. } else if (itemClass && itemClass.indexOf('js-lsiten-border') > -1) {
  692. // 框处理
  693. if (lastIsBorder) {
  694. let borderId = lastBorderItem.getAttribute('data-id');
  695. let currentBorderId = $item.attr('data-id');
  696. if (currentBorderId === borderId) {
  697. let borderType = parseInt($item.attr('data-type'));
  698. if (borderType === 1) {
  699. // 客观题处理
  700. $item.childNodes().forEach(objectRow => {
  701. if (!objectRow.previousSibling) {
  702. let lastRow = lastBorderItem.lastChild;
  703. let firstRowId = objectRow.getAttribute('data-id');
  704. let lastRowId = lastRow.getAttribute('data-id');
  705. if (firstRowId === lastRowId) {
  706. let objectColumns = $(objectRow).find('.js-option-column');
  707. // 以第一栏的为基准
  708. let objectFirstColumn = objectColumns[0];
  709. $(objectFirstColumn.firstChild).childNodes().forEach(objectQuestion => {
  710. if (!objectQuestion.previousSibling) {
  711. this._mergeObjectRow(objectColumns, lastRow);
  712. }
  713. })
  714. } else {
  715. lastBorderItem.appendChild(objectRow);
  716. }
  717. }
  718. })
  719. $item.remove();
  720. this._updateObjectColumnBorder(lastBorderItem);
  721. this._updateObjectColumnHeightByBorder(lastBorderItem);
  722. } else if (borderType === 2) {
  723. $($item[0].firstChild).childNodes().forEach(borderItem => {
  724. if (borderItem.className) {
  725. if (borderItem.className.indexOf('js-lsiten-question') > -1) {
  726. let qustionType = parseInt(borderItem.getAttribute('data-type'));
  727. let lastQuestionItem = lastBorderItem.lastChild;
  728. let lastQuestionId = lastQuestionItem.getAttribute('data-id');
  729. let currentQuestionId = borderItem.getAttribute('data-id');
  730. if (lastQuestionId && currentQuestionId && currentQuestionId === lastQuestionId) {
  731. if (qustionType === 3) {
  732. $(borderItem).childNodes().forEach(subjectItem => {
  733. lastQuestionItem.appendChild(subjectItem);
  734. })
  735. } else if (qustionType === 4) {
  736. $(borderItem).childNodes().forEach(writtingItem => {
  737. if (writtingItem.className.indexOf('lsiten-title') > -1) {
  738. let $prevWrittingTitleItem = $(lastQuestionItem).find('.lsiten-title');
  739. let needMergeItem = true;
  740. if (!$prevWrittingTitleItem.length) {
  741. needMergeItem = false;
  742. $prevWrittingTitleItem = $($prevWrittingTitleItem);
  743. } else {
  744. needMergeItem = false;
  745. $prevWrittingTitleItem = $(writtingItem).clone(false);
  746. }
  747. $(writtingItem).childNodes().forEach(writtingTitleItem => {
  748. $prevWrittingTitleItem[0].appendChild(writtingTitleItem);
  749. })
  750. if (needMergeItem && !isEmptyElement($prevWrittingTitleItem[0])) {
  751. lastQuestionItem.appendChild($prevWrittingTitleItem[0]);
  752. }
  753. } else if (writtingItem.className.indexOf('lsiten-border-box') > -1) {
  754. let $prevWrittingRowsItem = $(lastQuestionItem).find('.lsiten-border-box');
  755. let needMergeItem = true;
  756. if (!$prevWrittingRowsItem.length) {
  757. needMergeItem = false;
  758. $prevWrittingRowsItem = $($prevWrittingRowsItem);
  759. } else {
  760. needMergeItem = false;
  761. $prevWrittingRowsItem = $(writtingItem).clone(false);
  762. }
  763. $(writtingItem).childNodes().forEach(writtingRowItem => {
  764. $prevWrittingRowsItem[0].appendChild(writtingRowItem);
  765. })
  766. if (needMergeItem && !isEmptyElement($prevWrittingRowsItem[0])) {
  767. lastQuestionItem.appendChild($prevWrittingRowsItem[0]);
  768. }
  769. }
  770. })
  771. } else {
  772. $(borderItem).remove();
  773. }
  774. $(borderItem).remove();
  775. } else {
  776. lastBorderItem.firstChild.appendChild(borderItem);
  777. }
  778. } else if (itemClass && itemClass.indexOf('js-lsiten-options-box') > -1) {
  779. // 选作题组【回退】
  780. lastBorderItem.firstChild.appendChild(borderItem);
  781. } else if (borderItem.className.indexOf('js-lsiten-line') > -1) {
  782. lastBorderItem.firstChild.appendChild(borderItem);
  783. } else {
  784. $(borderItem).remove();
  785. }
  786. }
  787. })
  788. $item.remove();
  789. }
  790. } else {
  791. $lastParagraph.append($item);
  792. }
  793. } else {
  794. $lastParagraph.append($item);
  795. }
  796. } else {
  797. $item.remove();
  798. }
  799. }
  800. })
  801. $paragraphITem.remove();
  802. } else {
  803. $paragraphITem.insertAfter($lastParagraph);
  804. }
  805. })
  806. // 跨栏符检测
  807. this._checkIsCross($($paragraphs[$paragraphs.length - 1]), $column);
  808. this._checkIsCross($($nextParagraphs[0]), nextColumn.column);
  809. this._updateCrossColumn($column);
  810. this._updateCrossColumn(nextColumn.column);
  811. this._updateObjectColumnHeight(nextColumn.column[0]);
  812. }
  813. }
  814. },
  815. /**
  816. * function 检测段落是否需要上移
  817. * @param {array} $moves 需要移动的段落数组
  818. * @param {DomElement} $paragraph 需要检测的段落
  819. * @param {object} size 可以上移的空间
  820. * @param {DomElement} $lastParagraph 该段最后一段
  821. */
  822. _prevParagraph: function ($moves, $paragraph, size, $lastParagraph) {
  823. let lastClass = $lastParagraph.attr('class');
  824. let currentClass = $paragraph.attr('class');
  825. let lastPid = $lastParagraph.attr('data-index');
  826. let currentPid = $paragraph.attr('data-index');
  827. if (lastClass && lastClass.indexOf('js-split-paragraph') > -1) {
  828. if (currentClass && currentClass.indexOf('js-split-paragraph') > -1 && lastPid === currentPid) {
  829. // 如果两个段落需要合并
  830. let $prevParagraph = $lastParagraph;
  831. $paragraph.childNodes().forEach(item => {
  832. if (item.nodeType === 3) {
  833. $paragraph[0].removeChild(item);
  834. } else {
  835. let $item = $(item);
  836. let itemClass = $item.attr('class');
  837. if (itemClass && itemClass.indexOf('js-lsiten-line') > -1) {
  838. // 普通行
  839. let height = $item.getSizeData().height;
  840. if (height < size.diff) {
  841. $prevParagraph.append($item);
  842. size.diff -= height;
  843. }
  844. } else if (itemClass && itemClass.indexOf('js-lsiten-border') > -1) {
  845. // 框处理
  846. let borderType = parseInt($item.attr('data-type'));
  847. if (borderType === 1) {
  848. // 客观题处理
  849. this._prevObjectBorder($prevParagraph, size, $item, $lastParagraph, true);
  850. } else if (borderType === 2) {
  851. // 主观观题处理
  852. this._prevBorder($prevParagraph, size, $item, $lastParagraph, true);
  853. }
  854. } else {
  855. $item.remove();
  856. }
  857. }
  858. })
  859. } else {
  860. // 两段落不需要合并
  861. let $prevParagraph = $paragraph.clone(false);
  862. $paragraph.childNodes().forEach(item => {
  863. if (item.nodeType === 3) {
  864. $paragraph[0].removeChild(item);
  865. } else {
  866. let $item = $(item);
  867. let itemClass = $item.attr('class');
  868. if (itemClass && itemClass.indexOf('js-lsiten-line') > -1) {
  869. let height = $item.getSizeData().height;
  870. if (height < size.diff) {
  871. $prevParagraph.append($item);
  872. size.diff -= height;
  873. }
  874. } else if (itemClass && itemClass.indexOf('js-lsiten-border') > -1) {
  875. // 框处理
  876. let borderType = parseInt($item.attr('data-type'));
  877. if (borderType === 1) {
  878. // 客观题处理
  879. this._prevObjectBorder($prevParagraph, size, $item, $lastParagraph, false);
  880. } else if (borderType === 2) {
  881. this._prevBorder($prevParagraph, size, $item, $lastParagraph, false);
  882. }
  883. } else {
  884. $item.remove();
  885. }
  886. }
  887. })
  888. if (!isEmptyElement($prevParagraph[0])) {
  889. $moves.push($prevParagraph);
  890. }
  891. }
  892. } else {
  893. // 两段落不需要合并
  894. let $prevParagraph = $paragraph.clone(false);
  895. $paragraph.childNodes().forEach(item => {
  896. if (item.nodeType === 3) {
  897. $paragraph[0].removeChild(item);
  898. } else {
  899. let $item = $(item);
  900. let itemClass = $item.attr('class');
  901. if (itemClass && itemClass.indexOf('js-lsiten-line') > -1) {
  902. let height = $item.getSizeData().height;
  903. if (height < size.diff) {
  904. $prevParagraph.append($item);
  905. size.diff -= height;
  906. }
  907. } else if (itemClass && itemClass.indexOf('js-lsiten-border') > -1) {
  908. // 框处理
  909. let borderType = parseInt($item.attr('data-type'));
  910. if (borderType === 1) {
  911. // 客观题处理
  912. this._prevObjectBorder($prevParagraph, size, $item, $lastParagraph, false);
  913. } else if (borderType === 2) {
  914. this._prevBorder($prevParagraph, size, $item, $lastParagraph, false);
  915. }
  916. } else {
  917. $item.remove();
  918. }
  919. }
  920. })
  921. if (!isEmptyElement($prevParagraph[0])) {
  922. $moves.push($prevParagraph);
  923. }
  924. }
  925. if (isEmptyElement($paragraph[0])) {
  926. $paragraph.remove();
  927. }
  928. },
  929. /**
  930. * function 处理需要上移的框
  931. * @param {DomElement} $prevParagraph 前移段落暂存
  932. * @param {object} size 可移空间
  933. * @param {DomElement} $border 需要处理的框
  934. * @param {DomElement} $lastParagraph 最后一段dom
  935. * @param {boolean} 是否需要合并
  936. */
  937. _prevObjectBorder: function ($prevParagraph, size, $border, $lastParagraph, isMerge) {
  938. let lastCentent = $lastParagraph[0].lastChild;
  939. if (lastCentent && lastCentent.className && lastCentent.className.indexOf('js-lsiten-border') > -1) {
  940. let prevBid = $border.attr('data-id');
  941. let bid = $(lastCentent).attr('data-id');
  942. if (prevBid === bid) {
  943. let $prevBorder = $border.clone(false);
  944. if (isMerge) {
  945. $prevBorder = $($prevParagraph[0].lastChild);
  946. }
  947. $border.childNodes().forEach(row => {
  948. if (!row.previousSibling) {
  949. let lastRow = lastCentent.lastChild;
  950. let firstRowId = row.getAttribute('data-id');
  951. let lastRowId = lastRow.getAttribute('data-id');
  952. if (firstRowId === lastRowId) {
  953. let columns = $(row).find('.js-option-column');
  954. // 以第一栏的为基准计算
  955. let firstColumn = columns[0];
  956. $(firstColumn.firstChild).childNodes().forEach(question => {
  957. if (!question.previousSibling) {
  958. let height = $(question).getSizeData().height + 16;
  959. if (height < size.diff) {
  960. this._mergeObjectRow(columns, lastRow);
  961. size.diff -= height;
  962. }
  963. }
  964. })
  965. if (isEmptyElement(firstColumn.firstChild)) {
  966. $(row).remove();
  967. }
  968. } else {
  969. // 客观题每一个row的高度
  970. let rowOutsize = 24;
  971. size.diff -= rowOutsize;
  972. let columns = $(row).find('.js-option-column');
  973. // 以第一栏的为基准计算
  974. let firstColumn = columns[0];
  975. let prevRow = row.cloneNode(false)
  976. $(firstColumn.firstChild).childNodes().forEach(question => {
  977. if (!question.previousSibling) {
  978. let height = $(question).getSizeData().height + 16;
  979. if (height < size.diff) {
  980. this._mergeObjectRow(columns, prevRow);
  981. size.diff -= height;
  982. }
  983. }
  984. })
  985. if (!isEmptyElement(prevRow)) {
  986. $prevBorder[0].appendChild(prevRow);
  987. }
  988. size.diff += rowOutsize;
  989. if (isEmptyElement(firstColumn.firstChild)) {
  990. $(row).remove();
  991. }
  992. }
  993. }
  994. })
  995. if (!isMerge && !isEmptyElement($prevBorder[0])) {
  996. $prevParagraph.append($prevBorder);
  997. }
  998. if (isEmptyElement($border[0])) {
  999. $border.remove();
  1000. }
  1001. this._updateObjectColumnBorder(lastCentent);
  1002. this._updateObjectColumnHeightByBorder(lastCentent);
  1003. }
  1004. }
  1005. },
  1006. /**
  1007. * function 合并主观题行
  1008. * @param {Array} columns 需要处理的栏
  1009. * @param {node} lastRow 上一段最后一框最后一行
  1010. */
  1011. _mergeObjectRow: function (columns, lastRow) {
  1012. let lastColumns = $(lastRow).find('.js-option-column');
  1013. let length = columns.length;
  1014. for (let i =0; i < length; i++) {
  1015. if (columns[i].firstChild.childNodes[0]) {
  1016. if (lastColumns[i]) {
  1017. lastColumns[i].firstChild.appendChild(columns[i].firstChild.childNodes[0]);
  1018. } else {
  1019. let prevColumn = columns[i].cloneNode(false);
  1020. let prevColumnContent = columns[i].firstChild.cloneNode(false);
  1021. prevColumn.appendChild(prevColumnContent);
  1022. prevColumnContent.appendChild(columns[i].firstChild.childNodes[0]);
  1023. lastRow.appendChild(prevColumn);
  1024. }
  1025. }
  1026. }
  1027. },
  1028. /**
  1029. * function 处理需要上移的框
  1030. * @param {DomElement} $prevParagraph 前移段落暂存
  1031. * @param {object} size 可移空间
  1032. * @param {DomElement} $border 需要处理的框
  1033. * @param {DomElement} $lastParagraph 最后一段dom
  1034. * @param {boolean} 是否需要合并
  1035. */
  1036. _prevBorder: function ($prevParagraph, size, $border, $lastParagraph, isMerge) {
  1037. let lastCentent = $lastParagraph[0].lastChild;
  1038. if (lastCentent && lastCentent.className && lastCentent.className.indexOf('js-lsiten-border') > -1) {
  1039. let prevBid = $border.attr('data-id');
  1040. let bid = $(lastCentent).attr('data-id');
  1041. if (prevBid === bid) {
  1042. let $prevBorder = $border.clone(false);
  1043. let $prevBorderContent = $($border[0].firstChild).clone(false);
  1044. $prevBorder.append($prevBorderContent);
  1045. if (isMerge) {
  1046. $prevBorder = $($prevParagraph[0].lastChild);
  1047. $prevBorderContent = $prevBorder[0].firstChild;
  1048. }
  1049. this._prevQuestions($prevBorder, size, $border, $(lastCentent));
  1050. if (!isMerge && !isEmptyElement($prevBorderContent[0])) {
  1051. $prevParagraph.append($prevBorder);
  1052. }
  1053. } else {
  1054. let borderSize= $border.getSizeData();
  1055. if (borderSize.height < size.diff) {
  1056. $prevParagraph.append($border);
  1057. size.diff -= borderSize.height;
  1058. } else {
  1059. // 框的padding+margin+border
  1060. let borderOutSize = 22;
  1061. let $prevBorder = $border.clone(false);
  1062. let $borderContent = $($border[0].firstChild);
  1063. let $prevBorderContent = $borderContent.clone(false);
  1064. $prevBorder.append($prevBorderContent);
  1065. size.diff -= borderOutSize;
  1066. $borderContent.childNodes().forEach(item => {
  1067. if (!item.previousSibling) {
  1068. if (item.className) {
  1069. if (item.className.indexOf('js-lsiten-question') > -1) {
  1070. let qustionType = parseInt(item.getAttribute('data-type'));
  1071. if (qustionType === 3) {
  1072. let $prevSubject = $(item).clone(false);
  1073. this._prevSubjectQuestion($prevSubject, size, $(item), false);
  1074. if (!isEmptyElement($prevSubject)) {
  1075. $prevBorderContent[0].appendChild($prevSubject[0]);
  1076. }
  1077. } else if (qustionType === 4) {
  1078. let $prevWritting = $(item).clone(false);
  1079. this._prevWrittingQuestion($prevWritting, size, $(item), false);
  1080. if (!isEmptyElement($prevWritting)) {
  1081. $prevBorderContent[0].appendChild($prevWritting[0]);
  1082. }
  1083. } else {
  1084. let height = $(item).getSizeData().height;
  1085. if (height < size.diff) {
  1086. $prevBorderContent[0].appendChild(item);
  1087. size.diff -= height;
  1088. }
  1089. }
  1090. } else if (item.className.indexOf('js-lsiten-line') > -1) {
  1091. let height = $(item).getSizeData().height;
  1092. if (height < size.diff) {
  1093. $prevBorderContent[0].appendChild(item);
  1094. size.diff -= height;
  1095. }
  1096. } else if (item.className.indexOf('js-lsiten-options-box') > -1) {
  1097. // 选作题组【回退】
  1098. let height = $(item).getSizeData().height;
  1099. if (height < size.diff) {
  1100. $prevBorderContent[0].appendChild(item);
  1101. size.diff -= height;
  1102. }
  1103. } else {
  1104. $(item).remove();
  1105. }
  1106. } else {
  1107. item && item.parentNode.removeChild(item);
  1108. }
  1109. }
  1110. })
  1111. size.diff += borderOutSize;
  1112. if (!isEmptyElement($prevBorderContent[0])) {
  1113. $prevParagraph.append($prevBorder);
  1114. }
  1115. }
  1116. }
  1117. } else {
  1118. // 框的padding+margin+border
  1119. let borderOutSize = 22;
  1120. let $prevBorder = $border.clone(false);
  1121. let $borderContent = $($border[0].firstChild);
  1122. let $prevBorderContent = $borderContent.clone(false);
  1123. $prevBorder.append($prevBorderContent);
  1124. size.diff -= borderOutSize;
  1125. $borderContent.childNodes().forEach(item => {
  1126. if (!item.previousSibling) {
  1127. if (item.className) {
  1128. if (item.className.indexOf('js-lsiten-question') > -1) {
  1129. let qustionType = parseInt(item.getAttribute('data-type'));
  1130. if (qustionType === 3) {
  1131. let $prevSubject = $(item).clone(false);
  1132. this._prevSubjectQuestion($prevSubject, size, $(item), false);
  1133. if (!isEmptyElement($prevSubject)) {
  1134. $prevBorderContent.appendChild($prevSubject[0]);
  1135. }
  1136. } else if (qustionType === 4) {
  1137. let $prevWritting = $(item).clone(false);
  1138. this._prevWrittingQuestion($prevWritting, size, $(item), false);
  1139. if (!isEmptyElement($prevWritting)) {
  1140. $prevBorderContent.appendChild($prevWritting[0]);
  1141. }
  1142. } else {
  1143. let height = $(item).getSizeData().height;
  1144. if (height < size.diff) {
  1145. $prevBorderContent.appendChild(item);
  1146. size.diff -= height;
  1147. }
  1148. }
  1149. } else if (item.className.indexOf('js-lsiten-line') > -1) {
  1150. let height = $(item).getSizeData().height;
  1151. if (height < size.diff) {
  1152. $prevBorderContent[0].appendChild(item);
  1153. size.diff -= height;
  1154. }
  1155. } else if (item.className.indexOf('js-lsiten-options-box') > -1) {
  1156. // 选作题组【回退】
  1157. let height = $(item).getSizeData().height;
  1158. if (height < size.diff) {
  1159. $prevBorderContent[0].appendChild(item);
  1160. size.diff -= height;
  1161. }
  1162. } else {
  1163. $(item).remove();
  1164. }
  1165. } else {
  1166. item && item.parentNode.removeChild(item);
  1167. }
  1168. }
  1169. })
  1170. size.diff += borderOutSize;
  1171. if (!isEmptyElement($prevBorderContent[0])) {
  1172. $prevParagraph.append($prevBorder);
  1173. }
  1174. }
  1175. if (isEmptyElement($border[0].firstChild)) {
  1176. $border.remove();
  1177. }
  1178. },
  1179. /**
  1180. * function 前移问题
  1181. * @param {DomElement} $prevBorder 前移框暂存
  1182. * @param {object} size 前移段落暂存
  1183. * @param {DomElement} $border 前移段落暂存
  1184. * @param {DomElement} $lastBorder 前段落最后一个框
  1185. *
  1186. */
  1187. _prevQuestions: function ($prevBorder, size, $border, $lastBorder) {
  1188. let lastQuestion = $lastBorder[0].firstChild.lastChild;
  1189. let $borderContent = $($border[0].firstChild);
  1190. $borderContent.childNodes().forEach(item => {
  1191. if (!item.previousSibling) {
  1192. if (item.className) {
  1193. if (item.className.indexOf('js-lsiten-question') > -1) {
  1194. let qustionType = parseInt(item.getAttribute('data-type'));
  1195. let questionId = item.getAttribute('data-id');
  1196. if (lastQuestion.className && lastQuestion.className.indexOf('js-lsiten-question') > -1) {
  1197. let lastQuestionId = lastQuestion.getAttribute('data-id');
  1198. if (questionId && lastQuestionId && lastQuestionId === questionId) {
  1199. // 需要合并2个小问
  1200. if (qustionType === 3) {
  1201. this._prevSubjectQuestion($(lastQuestion), size, $(item), true);
  1202. } else if (qustionType === 4) {
  1203. this._prevWrittingQuestion($(lastQuestion), size, $(item), true);
  1204. } else {
  1205. let height = $(item).getSizeData().height;
  1206. if (height < size.diff) {
  1207. $prevBorder[0].firstChild.appendChild(item);
  1208. size.diff -= height;
  1209. }
  1210. }
  1211. } else {
  1212. if (qustionType === 3) {
  1213. let $prevSubject = $(item).clone(false);
  1214. this._prevSubjectQuestion($prevSubject, size, $(item), false);
  1215. if (!isEmptyElement($prevSubject[0])) {
  1216. $prevBorder[0].firstChild.appendChild($prevSubject[0]);
  1217. }
  1218. } else if (qustionType === 4) {
  1219. let $prevWritting = $(item).clone(false);
  1220. this._prevWrittingQuestion($prevWritting, size, $(item), false);
  1221. if (!isEmptyElement($prevWritting[0])) {
  1222. $prevBorder[0].firstChild.appendChild($prevWritting[0]);
  1223. }
  1224. } else {
  1225. let height = $(item).getSizeData().height;
  1226. if (height < size.diff) {
  1227. $prevBorder[0].firstChild.appendChild(item);
  1228. size.diff -= height;
  1229. }
  1230. }
  1231. }
  1232. } else {
  1233. if (qustionType === 3) {
  1234. let $prevSubject = $(item).clone(false);
  1235. this._prevSubjectQuestion($prevSubject, size, $(item), false);
  1236. if (!isEmptyElement($prevSubject[0])) {
  1237. $prevBorder[0].firstChild.appendChild($prevSubject[0]);
  1238. }
  1239. } else if (qustionType === 4) {
  1240. let $prevWritting = $(item).clone(false);
  1241. this._prevWrittingQuestion($prevWritting, size, $(item), false);
  1242. if (!isEmptyElement($prevWritting[0])) {
  1243. $prevBorder[0].firstChild.appendChild($prevWritting[0]);
  1244. }
  1245. } else {
  1246. let height = $(item).getSizeData().height;
  1247. if (height < size.diff) {
  1248. $prevBorder[0].firstChild.appendChild(item);
  1249. size.diff -= height;
  1250. }
  1251. }
  1252. }
  1253. } else if (item.className.indexOf('js-lsiten-line') > -1) {
  1254. let height = $(item).getSizeData().height;
  1255. if (height < size.diff) {
  1256. $prevBorder[0].firstChild.appendChild(item);
  1257. size.diff -= height;
  1258. }
  1259. } else {
  1260. $(item).remove();
  1261. }
  1262. } else {
  1263. item && item.parentNode.removeChild(item);
  1264. }
  1265. }
  1266. })
  1267. },
  1268. /**
  1269. * function 前移主观题框
  1270. * @param {DomElement} $prevSubject 前移框暂存
  1271. * @param {object} size 可移动空间
  1272. * @param {DomElement} $subject 需要前移客观题处理
  1273. * @param {boolean} isMerge 是否需要合并
  1274. */
  1275. _prevSubjectQuestion: function ($prevSubject, size, $subject, isMerge) {
  1276. $subject.childNodes().forEach(item => {
  1277. let height = $(item).getSizeData().height;
  1278. if (height < size.diff) {
  1279. $prevSubject[0].appendChild(item);
  1280. size.diff -= height;
  1281. }
  1282. if (isEmptyElement($subject[0])) {
  1283. $subject.remove();
  1284. }
  1285. })
  1286. },
  1287. /**
  1288. * function 前移主观题框
  1289. * @param {DomElement} $prevWritting 前移框暂存
  1290. * @param {number} size 可移动空间
  1291. * @param {DomElement} $Writting 需要前移客观题处理
  1292. * @param {boolean} isMerge 是否需要合并
  1293. */
  1294. _prevWrittingQuestion: function ($prevWritting, size, $Writting, isMerge) {
  1295. $Writting.childNodes().forEach(item => {
  1296. if (item.className) {
  1297. if (item.className.indexOf('lsiten-title') > -1) {
  1298. let $prevWrittingTitle = null;
  1299. let needApppend = true;
  1300. if (isMerge) {
  1301. $prevWrittingTitle = $prevWritting.find('.lsiten-title');
  1302. if ($prevWrittingTitle.length) {
  1303. $prevWrittingTitle = $($prevWrittingTitle);
  1304. needApppend = false;
  1305. } else {
  1306. $prevWrittingTitle = null;
  1307. let needApppend = true;
  1308. }
  1309. }
  1310. let $writtingTitle = $(item);
  1311. $prevWrittingTitle = $prevWrittingTitle || $writtingTitle.clone(false);
  1312. $writtingTitle.childNodes().forEach(titleItem => {
  1313. if (titleItem.className && titleItem.className.indexOf('js-lsiten-line') > -1) {
  1314. let height = $(titleItem).getSizeData().height;
  1315. if (height < size.diff) {
  1316. $prevWrittingTitle[0].appendChild(titleItem);
  1317. size.diff -= height;
  1318. }
  1319. } else {
  1320. titleItem && item.removeChild(titleItem);
  1321. }
  1322. })
  1323. if (needApppend && !isEmptyElement($prevWrittingTitle[0])) {
  1324. $prevWritting.append($prevWrittingTitle);
  1325. }
  1326. if (isEmptyElement($writtingTitle[0])) {
  1327. $writtingTitle.remove();
  1328. }
  1329. } else if (item.className.indexOf('lsiten-border-box') > -1) {
  1330. let $prevWrittingRows = null;
  1331. let needApppend = true;
  1332. if (isMerge) {
  1333. $prevWrittingRows = $prevWritting.find('.lsiten-border-box');
  1334. if ($prevWrittingRows.length) {
  1335. $prevWrittingRows = $($prevWrittingRows);
  1336. needApppend = false;
  1337. } else {
  1338. $prevWrittingRows = null;
  1339. needApppend = true;
  1340. }
  1341. }
  1342. let $writtingRows = $(item);
  1343. $prevWrittingRows = $prevWrittingRows || $writtingRows.clone(false);
  1344. // 行的margin值
  1345. let rowOutSize = 8;
  1346. $writtingRows.childNodes().forEach(rowItem => {
  1347. if (rowItem.className && rowItem.className.indexOf('js-lsiten-writting-row') > -1) {
  1348. let height = $(rowItem).getSizeData().height + rowOutSize;
  1349. if (height < size.diff) {
  1350. $prevWrittingRows[0].appendChild(rowItem);
  1351. size.diff -= height;
  1352. }
  1353. } else {
  1354. rowItem && item.removeChild(rowItem);
  1355. }
  1356. })
  1357. if (needApppend && !isEmptyElement($prevWrittingRows[0])) {
  1358. $prevWritting.append($prevWrittingRows);
  1359. }
  1360. if (isEmptyElement($writtingRows[0])) {
  1361. $writtingRows.remove();
  1362. }
  1363. }
  1364. }
  1365. })
  1366. if (isEmptyElement($Writting[0])) {
  1367. $Writting.remove();
  1368. }
  1369. },
  1370. /**
  1371. * function 检测内容是否超出
  1372. */
  1373. _checkContentOut: function () {
  1374. let $columns = this.$colums;
  1375. // 备用
  1376. let maxHeight = parseInt(this._pagesHeight[this.editor.pageSize]);
  1377. $columns.forEach($column => {
  1378. this._checkColumnOut($column);
  1379. });
  1380. },
  1381. /**
  1382. * function 获取第一段
  1383. */
  1384. _getFirstPargraph: function (column) {
  1385. let $paragraphs = column.find('.js-paragraph-view');
  1386. let firstParagraph = $paragraphs[0];
  1387. if (!firstParagraph) {
  1388. return false;
  1389. }
  1390. let firstChild = firstParagraph.firstChild;
  1391. if (firstChild && firstChild.className && firstChild.className.indexOf('js-answer-header') > -1) {
  1392. firstParagraph = $paragraphs[1];
  1393. }
  1394. return firstParagraph ? $(firstParagraph): false;
  1395. },
  1396. /**
  1397. * function 插入dom
  1398. * @param {DomElement} $nextDom 下一栏暂存
  1399. * @param {DomElement} $dom 需要插入的dom
  1400. */
  1401. insertDom($nextDom, $dom) {
  1402. let firstChild = $nextDom[0].firstChild;
  1403. if (firstChild) {
  1404. $dom.insertBefore($(firstChild));
  1405. } else {
  1406. $nextDom.append($dom);
  1407. }
  1408. },
  1409. /**
  1410. * function 拆分段落
  1411. * @param $moves {Array} 需要移动的数组
  1412. * @param $paragraph {DomElement} 需要切分的段落
  1413. * @param cSize {Object} 段落尺寸数据
  1414. * @param $column {DomElement} 当前栏
  1415. */
  1416. _splitParagraph: function ($moves, $paragraph, cSize, $column) {
  1417. let $nextParagraph = $paragraph.clone(false);
  1418. let childs = $paragraph[0].childNodes;
  1419. let index = childs.length - 1;
  1420. while (index >= 0) {
  1421. let line = childs[index];
  1422. if (line && line.className) {
  1423. if (line.className.indexOf('js-lsiten-line') > -1) {
  1424. // 普通一行
  1425. let $line = $(line);
  1426. let lineSize = $line.getSizeData();
  1427. if (lineSize.top >= cSize.bottom) {
  1428. this.insertDom($nextParagraph, $line);
  1429. }
  1430. } else if (line.className.indexOf('js-lsiten-border') > -1) {
  1431. // 题框
  1432. this._splitBorder($nextParagraph, $(line), cSize);
  1433. } else {
  1434. $(line).remove();
  1435. }
  1436. } else {
  1437. line && $paragraph[0].removeChild(line);
  1438. }
  1439. index--;
  1440. }
  1441. if ($nextParagraph.childNodes().length > 0) {
  1442. $paragraph.addClass('js-split-paragraph');
  1443. $nextParagraph.addClass('js-split-paragraph');
  1444. $moves.push($nextParagraph);
  1445. }
  1446. },
  1447. /**
  1448. * function 获取下一栏
  1449. * @param {DomElement} $column 当前栏
  1450. * @param {boolean} isAddpage 是否需要新增页
  1451. */
  1452. _getNextColumn: function ($column, isAddPage) {
  1453. let nextColumnIndex = parseInt($column.attr('data-column-i')) + 1;
  1454. let $nextColumn = this.$colums[nextColumnIndex];
  1455. if ($nextColumn) {
  1456. return {
  1457. page: this,
  1458. column: $nextColumn
  1459. };
  1460. } else {
  1461. let page = this._getNextPage(isAddPage);
  1462. if (page) {
  1463. $nextColumn = page.$colums[0];
  1464. return {
  1465. page: page,
  1466. column: $nextColumn
  1467. };
  1468. } else {
  1469. return {
  1470. page: false,
  1471. column: false
  1472. };
  1473. }
  1474. }
  1475. },
  1476. /**
  1477. * function 获取下一页对象
  1478. * @param {Boolean} isAddPage 如果没有是否添加一页
  1479. */
  1480. _getNextPage: function (isAddPage) {
  1481. let nextPageIndex = this.pageIndex + 1;
  1482. let page = this.manage.getNextPageByKey(nextPageIndex, isAddPage)
  1483. return page;
  1484. },
  1485. /**
  1486. * function 拆分框
  1487. * @param $nextParagraph {DomElement} 下一段暂存
  1488. * @param $border {DomElement} 需要切分的框
  1489. * @param cSize {Object} 段落尺寸数据
  1490. */
  1491. _splitBorder: function ($nextParagraph, $border, cSize) {
  1492. let $splitBorder = this.questionTools._splitBorder($border, cSize);
  1493. if ($splitBorder) {
  1494. this.insertDom($nextParagraph, $splitBorder);
  1495. }
  1496. },
  1497. _pagesHeight: {
  1498. 'A4': '970px',
  1499. 'A3': '970px'
  1500. },
  1501. _pagesWidth: {
  1502. 'A4': 653,
  1503. 'A3': 1447
  1504. }
  1505. }
  1506. export default yzPage