lsiten 6 年之前
父節點
當前提交
37f9ef0817

File diff suppressed because it is too large
+ 11624 - 0
package-lock.json


+ 2 - 1
package.json

@@ -43,7 +43,8 @@
     "html-withimg-loader": "^0.1.16",
     "jquery": "^3.3.1",
     "jquery.caret": "^0.3.1",
-    "jr-qrcode": "^1.1.4"
+    "jr-qrcode": "^1.1.4",
+    "uuid": "^3.3.2"
   },
   "repository": {
     "type": "git",

+ 4 - 0
src/js/plugin/commands/answerHeader.js

@@ -1,4 +1,5 @@
 import questionGenerate from '../../question/index.js';
+import Jquery from 'jquery';
 let AnswerHeader = function ($page) {
   let editor = this.editor;
   let type = editor.layoutMode;
@@ -14,6 +15,9 @@ let AnswerHeader = function ($page) {
   } else {
     key += 1;
   }
+  if (editor.page) {
+    Jquery(editor.page.$el[0]).trigger('addContent');
+  }
   return questionGenerate.generateQuestionHead(editor, key, $page);
 }
 

+ 6 - 0
src/js/plugin/commands/border.js

@@ -1,5 +1,7 @@
 import $ from '../../util/dom-core.js';
 import { gennerOneLine } from '../../util/lineUtil.js';
+import Jquery from 'jquery';
+import uuid from 'uuid';
 function _addParagraph (editor) {
   let currentPage = editor.page.currentPage;
   if (!currentPage) {
@@ -22,6 +24,7 @@ function objectBorder (editor, data) {
   border.attr('data-sort', sortIndex);
   border.attr('tabindex', 1);
   border.attr('data-current-row', 0);
+  border.attr('data-id', uuid());  
   border.attr('contenteditable', false);
   // style start
   border.css('border', '1px solid #000')
@@ -50,6 +53,7 @@ function objectBorder (editor, data) {
         .css('height', 'auto')
         .css('width', '100%');
     $row.attr('data-current-column', 0);
+    $row.attr('data-id', uuid());      
     i > 0 && ($row.css('border-top', '1px solid #000').css('box-sizing', 'border-box'));
     for (let j = 0; j < column; j++) {
       let $column = $('<div class = "js-option-column"><div style="padding: 12px 0"></div></div>');
@@ -85,6 +89,7 @@ function subjectBorder (editor, data) {
   border.attr('data-type', 2);
   border.attr('data-sort', sortIndex);
   border.attr('tabindex', 1);
+  border.attr('data-id', uuid());
   let newLine = gennerOneLine();
   $(border[0].firstChild).append(newLine);
   // style start
@@ -156,6 +161,7 @@ let Border = function (params) {
     subjectBorder(editor, data);
     break;
   }
+  Jquery(editor.page.$el[0]).trigger('addContent');
  }
  export default {
    _border: Border

+ 2 - 1
src/js/plugin/commands/questiontype.js

@@ -1,5 +1,6 @@
 import { getParentByClassname } from '../../util/util.js';
 import questionGenerate from '../../question/index.js';
+import Jquery from 'jquery';
 let Questiontype = function (params) {
   let editor = this.editor;
   let type = params.type;
@@ -28,7 +29,7 @@ let Questiontype = function (params) {
     questionGenerate.generateWriting(border, data, editor);
     break;
   }
-
+  Jquery(editor.page.$el[0]).trigger('addContent');
  }
  export default {
    _questiontype: Questiontype

+ 6 - 1
src/js/question/choice.js

@@ -113,6 +113,11 @@ let generateChoice = function ($border, data, editor) {
       console.log("%c请在框内添加该题!", "color:red");
       return '';
     }
+
+    let questionBox = getParentByClassname($currentLine, 'js-lsiten-question');
+    if (questionBox) {
+      $currentLine = parseInt(questionBox.attr('data-type')) > 2 ? questionBox : questionBox.parent();
+    }
     let $newLine = gennerOneLine();
     $($newLine[0].firstChild).remove();
     $newLine.append($questionItem);
@@ -123,7 +128,7 @@ let generateChoice = function ($border, data, editor) {
     }
 
     $newLine.focus();
-    editor.page._updatePositionInfo(null, $newLine); 
+    editor.page._updatePositionInfo(null, $newLine);
   }
  }
  /**

+ 5 - 0
src/js/question/judge.js

@@ -102,6 +102,11 @@ import { gennerOneLine } from '../util/lineUtil.js';
       return '';
     }
 
+    let questionBox = getParentByClassname($currentLine, 'js-lsiten-question');
+    if (questionBox) {
+      $currentLine = parseInt(questionBox.attr('data-type')) > 2 ? questionBox : questionBox.parent();
+    }
+
     let $newLine = gennerOneLine();
     $($newLine[0].firstChild).remove();
     $newLine.append($questionItem);

+ 7 - 3
src/js/question/questionhead.js

@@ -422,9 +422,13 @@ let generateQuestionHead = function (editor, key, $page) {
   $firstParagraph.append($header);
 
   $header.find('.js-answer-header-title').focus();
-  setTimeout(() => {
-    editor.page._updatePositionInfo({}, $header);    
-  }, 0);
+  if (editor.page) {
+    editor.page._updatePositionInfo({}, $header);
+  } else {
+    setTimeout(() => {
+      editor.page._updatePositionInfo({}, $header);      
+    },0)
+  }
   return true;
 }
 

+ 2 - 0
src/js/question/subject.js

@@ -1,6 +1,7 @@
 import $ from '../util/dom-core.js';
 import { getParentByClassname, isEmptyElement } from '../util/util.js';
 import { gennerOneLine, gennerOneLines } from '../util/lineUtil.js';
+import uuid from 'uuid';
 
 /**
  * function 生成主观题区
@@ -40,6 +41,7 @@ let generateSubjectBox = function ($border, data, editor) {
   if (questionBox) {
     $currentLine = parseInt(questionBox.attr('data-type')) > 2 ? questionBox : questionBox.parent();
   }
+  $box.attr('data-id', uuid());  
   $box.insertAfter($currentLine);
   if ( isEmptyElement($borderContent[0].firstChild) ) {
     $borderContent[0].removeChild($borderContent[0].firstChild);

+ 2 - 0
src/js/question/writing.js

@@ -1,6 +1,7 @@
 import $ from '../util/dom-core.js';
 import { getParentByClassname, isEmptyElement } from '../util/util.js';
 import { gennerOneLines } from '../util/lineUtil.js';
+import uuid from 'uuid';
 
 /**
  * 
@@ -20,6 +21,7 @@ let generateWriting = function ($border, data, editor) {
   let $box = $('<div class="lsiten-question-writing js-lsiten-question"></div>');
   $box.attr('data-type', 4);
   $box.attr('data-pnum', pnum);
+  $box.attr('data-id', uuid());
   $box.attr('data-total', total);
   // 1、生成题号区
   let $title = $('<div class="lsiten-title"></div>');

+ 138 - 264
src/js/util/question.js

@@ -1,5 +1,6 @@
 import $ from './dom-core';
 import {isEmptyElement} from './util.js'
+import {gennerOneLine} from './lineUtil.js'
 let questionUtils = function () {
 
 }
@@ -37,7 +38,7 @@ questionUtils.prototype = {
         let row = childs[i];
         let $row = $(row);
         let $nextRow = $row.clone(false);
-        if (bSizeBorder.bottom > csize.bottom) {
+        if (bSizeBorder.bottom >= csize.bottom) {
           this._splitObjectRow($nextRow, $row, $border, csize);
           if ($nextRow.childNodes().length > 0) {
             if ($nextBorder.childNodes().length > 0) {
@@ -137,13 +138,24 @@ questionUtils.prototype = {
       $item.find('.js-option-column').css('min-height', contentSize.height + 'px');
     }
     let bSizeBorder = $border.getSizeData();
-    if (bSizeBorder.bottom > csize.bottom) {
+    if (bSizeBorder.bottom >= csize.bottom) {
       this._splitObjectRow($nextDiv, $item, $border, csize);
     }
 
   },
-
-
+  /**
+   * function 插入dom
+   * @param {DomElement}  $nextDom 下一栏暂存
+   * @param {DomElement}  $dom 需要插入的dom
+   */
+  insertDom($nextDom, $dom) {
+    let firstChild = $nextDom[0].firstChild;
+    if (firstChild) {
+      $dom.insertBefore($(firstChild));
+    } else {
+      $nextDom.append($dom);
+    }
+  },
     /**
    * function 切分主观题框
    * @param {DomElement} $border 题框
@@ -155,277 +167,129 @@ questionUtils.prototype = {
     if ($content.attr('class') === 'border-content') {
       let childrens = $content.childNodes();
       let $nextContent = $content.clone(false);
-      let html = $content.html().toLowerCase();     
-      if (childrens.length < 1 || html === '' || html === '<p></p>' || html === '<p><br></p>' || html === '<p><br/></p>' || html === '<br/>' || html === '<br>') {
-        $nextBorder.append($content);
-      } else {
-        for (let i =(childrens.length -1); i >= 0; i--) {
-          let item = childrens[i];
-          let bSize = $border.getSizeData();
-          if (bSize.bottom > csize.bottom) {
-            if (item.nodeType === 3) {
-              this._handerText($nextBorder, item, csize, $border);
-            } else {
-              let $item = $(item);
-              let className = $item.attr('class');
-              if (className && className.indexOf('js-lsiten-question') > -1) {
-                let type = parseInt($item.attr('data-type'));
-                let nextDivFirstDiv = $nextContent[0].firstChild;
-                switch (type) {
-                  case 1:
-                  let $nextChoice = this._handleChoice($item, csize, $border);
-                  nextDivFirstDiv = $nextContent[0].firstChild;
-                  if (nextDivFirstDiv) {
-                    $nextContent[0].insertBefore($nextChoice[0].firstChild, nextDivFirstDiv);
-                  } else {
-                    $nextContent[0].appendChild($nextChoice[0].firstChild);
-                  }
-
-                  break;
-                  case 2:
-                  let $nextJudge = this._handleJudge($item, csize, $border);
-                  nextDivFirstDiv = $nextContent[0].firstChild;
-                  if (nextDivFirstDiv) {
-                    $nextContent[0].insertBefore($nextJudge[0].firstChild, nextDivFirstDiv);
-                  } else {
-                    $nextContent[0].appendChild($nextJudge[0].firstChild);
-                  }
-                  break;
-                  case 3:
-                  let $nextsubject = this._handleSubject($item, csize, $border);
-                  if ($nextsubject) {
-                    nextDivFirstDiv = $nextContent[0].firstChild;
-                    if (nextDivFirstDiv) {
-                      $nextContent[0].insertBefore($nextsubject[0], nextDivFirstDiv);
-                    } else {
-                      $nextContent.append($nextsubject);
-                    }
-                    $nextsubject.addClass('js-split-problem');
-                    $item.addClass('js-split-problem');
-                    $nextsubject.attr('data-rm', 0);
-                    if (isEmptyElement($item[0])) {
-                      $item.remove();
-                      $nextsubject.attr('data-rm', 1);
-                    }
-                  }
-                  break;
-                  case 4:
-                  let $nextWritting = this._handleWritting($item, csize, $border);
-                  if ($nextWritting) {
-                    nextDivFirstDiv = $nextContent[0].firstChild;
-                    if (nextDivFirstDiv) {
-                      $nextContent[0].insertBefore($nextWritting[0], nextDivFirstDiv);
-                    } else {
-                      $nextContent.append($nextWritting);
-                    }
-                    $nextWritting.addClass('js-split-writting-problem');
-                    $item.addClass('js-split-writting-problem');
-                    $nextWritting.attr('data-rm', 0);
-                    if (isEmptyElement($item[0])) {
-                      $item.remove();
-                      $nextWritting.attr('data-rm', 1);
-                    }
-                  }
-                  break;
-                }
-              } else if (className && className.indexOf('js-lsiten-options-box') > -1) {
-                // 选做题处理
-                let $nextOption = this._handleOptions($item, csize, $border);
-                let nextDivFirstDiv = $nextContent[0].firstChild;
-                if (nextDivFirstDiv) {
-                  $nextContent[0].insertBefore($nextOption[0].firstChild, nextDivFirstDiv);
-                } else {
-                  $nextContent[0].appendChild($nextOption[0].firstChild);
-                }
-              } else {
-                let $nextDiv = this._handerDiv($item, csize, $border);
-                if ($nextDiv.childNodes().length > 0) {
-                  let nextDivFirstDiv = $nextContent[0].firstChild;
-                  if (nextDivFirstDiv) {
-                    $nextContent[0].insertBefore($nextDiv[0], nextDivFirstDiv);
-                  } else {
-                    $nextContent.append($nextDiv)
-                  }
-                }
-
-                if (isEmptyElement($item[0])) {
-                  $item.remove();
-                }
-              }
+      let index = childrens.length - 1;
+      while (index >= 0 ) {
+        let line = childrens[index];
+        if (line && line.className) {
+          if (line.className.indexOf('js-lsiten-line') > -1) {
+            // 普通一行或者是单选题可判断题
+            let $line = $(line);
+            let borderSize = $border.getSizeData();
+            if (borderSize.bottom >= csize.bottom) {
+              this.insertDom($nextContent, $line);
+            }
+          } else if (line.className.indexOf('js-lsiten-question') > -1) {
+            let $line = $(line);
+            let questionType = parseInt($line.attr('data-type'));
+            switch (questionType) {
+              case 1:
+              this._handleChoice($line, $nextContent, csize);
+              break;
+              case 2:
+              this._handleJudge($line, $nextContent, csize);              
+              break;
+              case 3:
+              this._handleSubject($line, $nextContent, $border, csize);              
+              break;
+              case 4:
+              this._handleWritting($line, $nextContent, $border, csize);              
+              break;
             }
           }
+        } else {
+          line && $content[0].removeChild(line);
         }
-
-        if ($nextContent.childNodes().length > 0) {
-          $nextBorder.append($nextContent);
-        }
+        index--;
+      }
+      if ($nextContent.childNodes().length > 0) {
+        $nextBorder.append($nextContent);
+        $border.addClass('js-split-border');
+        $nextBorder.addClass('js-split-border');
+        return $nextBorder;
+      } else {
+        return false;
       }
-      return $nextBorder.childNodes().length > 0 ? $nextBorder: false;
     } else {
       $border.remove();
       return false;
     }
   },
   /**
-   * function 处理纯文字
-   * @param {DomElement} $nextDiv 下一段的div
-   * @param {DomElement} item 文本节点
-   * @param {Object} csize 栏size
-   * @param {DomElement} $border 所在框
-   */
-  _handerText: function ($nextDiv, item, csize, $border) {
-    let text = item.nodeValue;
-    let nextNode = item.nextSibling;
-    let parentNode = item.parentNode;
-    let span = document.createElement('span');
-    span.appendChild(item);
-    if (nextNode) {
-      parentNode.insertBefore(span, nextNode);
-    } else {
-      parentNode.appendChild(span);
-    }
-    let $span =  $(span);
-    let textSize = $span.getSizeData();
-    if (textSize.top > csize.bottom) {
-      $nextDiv[0].appendChild(item);
-      $span.remove();
-    } else {
-      let textLength = text.length;
-      let i = 0;
-      while(--textLength) {
-        span.innerHTML = text.substr(0, textLength);
-        // 要看框的底部是否在栏内
-        textSize = $border.getSizeData();
-        if (textSize.bottom < csize.bottom) {
-          break;
-        }
-      }
-      let prevText = text.substr(0, textLength);
-      let nextText = text.substring(textLength);
-      span.outerHTML = prevText;
-      $(parentNode).addClass('js-split-item');
-      $nextDiv[0].appendChild(document.createTextNode(nextText));
-      $nextDiv.addClass('js-split-item');
-    }
-  },
-  /**
-   * function 处理纯普通div
-   * @param {DomElement} $item 纯普通div
-   * @param {Object} csize 栏size
-   *  @param {DomElement} $border 所在框
-   */
-  _handerDiv: function ($item, csize, $border) {
-    let $nextDiv = $item.clone(false);
-    this._splitNormalDiv($nextDiv,$item, csize, $border);
-    return $nextDiv;
-  },
-  /**
-   * function 切分纯普通div
-   * @param {DomElement} $nextDiv 纯普通div
-   * @param {Node} $item 纯普通div
-   * @param {Object} csize 栏size
-   * @param {DomElement} $border 所在框
-   */
-  _splitNormalDiv: function ($nextDiv, $item, csize, $border) {
-    let bSize = $border.getSizeData();
-    if (bSize.bottom < csize.bottom) {
-      return false;
-    }
-    let childs = $item.childNodes();
-    let cLength = childs.length;
-    if (cLength > 0) {
-      for (let i =(cLength -1); i >= 0; i--) {
-        let child = childs[i];
-        if (child.nodeType === 3) {
-          this._handerText($nextDiv, child, csize, $border);
-        } else {
-          let tName = child.tagName.toLowerCase();
-          if (tName === 'br') {
-            let nextFirstChild = $nextDiv[0].firstChild;
-            if (nextFirstChild) {
-              $nextDiv[0].insertBefore(child, nextFirstChild);
-            } else {
-              $nextDiv[0].appendChild(child);
-            }
-          } else if (tName === 'img') {
-            let nextFirstChild = $nextDiv[0].firstChild;
-            if (nextFirstChild) {
-              $nextDiv[0].insertBefore(child, nextFirstChild);
-            } else {
-              $nextDiv[0].appendChild(child);
-            }
-          } else {
-            let $child = $(child);
-            let $nextChild = $child.clone(false);
-            this._splitNormalDiv($nextChild, $child, csize, $border);
-            if ($nextChild.childNodes().length > 0) {
-              let nextDivFirstDiv = $nextDiv[0].firstChild;
-              if (nextDivFirstDiv) {
-                $nextDiv[0].insertBefore($nextChild[0], nextDivFirstDiv);
-              } else {
-                $nextDiv.append($nextChild)
-              }
-            }
-            if ($child[0].innerHTML === '') {
-              $child.remove();
-            }
-          }
-        }
-      }
-    }
-  },
-  /**
-   * function 处理选择题div
-   * @param {DomElement} $item 纯普通div
-   * @param {Object} csize 栏size
-   * @param {DomElement} $border 所在框
-   */
-  _handleOptions: function ($item, csize, $border) {
-    let $nextNext = $('<div></div>');
-    $nextNext.append($item);
-    return $nextNext;
-  },
-  /**
    * function 处理选择题div
    * @param {DomElement} $item 纯普通div
+   * @param {DomElement} $nextContent 下一个框暂存
    * @param {Object} csize 栏size
-   * @param {DomElement} $border 所在框
    */
-  _handleChoice: function ($item, csize, $border) {
-    let $nextNext = $('<div></div>');
-    $nextNext.append($item);
-    return $nextNext;
+  _handleChoice: function ($item, $nextContent, csize) {
+    let lineSize = $item.getSizeData();
+    if (lineSize.top >= csize.bottom) {
+      let newLine = gennerOneLine();
+      newLine.append($item);
+      $nextContent.append(newLine);
+    }
   },
   /**
    * function 处理判断题div
    * @param {DomElement} $item 纯普通div
+   * @param {DomElement} $nextContent 下一个框暂存
    * @param {Object} csize 栏size
-   * @param {DomElement} $border 所在框
    */
-  _handleJudge: function ($item, csize, $border) {
-    let $nextNext = $('<div></div>');
-    $nextNext.append($item);
-    return $nextNext;
+  _handleJudge: function ($item, $nextContent, csize) {
+    let lineSize = $item.getSizeData();
+    if (lineSize.top >= csize.bottom) {
+      let newLine = gennerOneLine();
+      newLine.append($item);
+      $nextContent.append(newLine);
+    }
   },
   /**
    * function 处理客观题Div
    * @param {DomElement} $item 纯普通div
-   * @param {Object} csize 栏size
+   * @param {DomElement} $nextContent 下个框暂存
    * @param {DomElement} $border 所在框
+   * @param {Object} csize 栏size
    */
-  _handleSubject: function ($item, csize, $border) {
+  _handleSubject: function ($item, $nextContent, $border, csize) {
     let $nextSubject = $item.clone(false);
-    this._splitNormalDiv($nextSubject, $item, csize, $border);
-    !$item.childNodes().length && $item.remove();
-    return $nextSubject.childNodes().length > 0 ? $nextSubject : false;
+    let childs = $item.childNodes();
+    let index = childs.length - 1;
+    while (index >= 0 ) {
+      let line = childs[index];
+      if (line && line.className) {
+        if (line.className.indexOf('js-lsiten-line') > -1) {
+          // 普通一行
+          let $line = $(line);
+          let bSize = $border.getSizeData();
+          if (bSize.bottom >= csize.bottom) {
+            this.insertDom($nextSubject, $line);
+          }
+        } else {
+          $(line).remove();
+        }
+      } else {
+        line && $paragraph[0].removeChild(line);
+      }
+      index--;
+    }
+
+    if (isEmptyElement($item[0])) {
+      $item.remove();
+    }
+
+    if ($nextSubject.childNodes().length > 0) {
+      this.insertDom($nextContent, $nextSubject);
+      $nextSubject.addClass('js-split-question');
+      $item.addClass('js-split-question');
+    }
   },
   /**
    * function 处理作文题Div
    * @param {DomElement} $item 纯普通div
-   * @param {Object} csize 栏size
+   * @param {DomElement} $nextContent 下个框暂存
    * @param {DomElement} $border 所在框
+   * @param {Object} csize 栏size
    */
-  _handleWritting: function ($item, csize, $border) {
+  _handleWritting: function ($item, $nextContent, $border, csize) {
     let childs = $item.childNodes();
     let cLength = childs.length;
     let $nextWritting = $item.clone(false);
@@ -435,20 +299,33 @@ questionUtils.prototype = {
         let bSize = $border.getSizeData();
         let child = childs[i];
         let $child = $(child);
-        if (bSize.bottom > csize.bottom) {
+        if (bSize.bottom >= csize.bottom) {
           if (child.className.indexOf('lsiten-title') > -1) {
             if (!isEmptyElement(child)) { 
               // 作文标题
               let $nextLsitenTitle = $child.clone(false);
-              this._splitNormalDiv($nextLsitenTitle, $child, csize, $border);
-              if ( $nextLsitenTitle.childNodes().length > 0 ) {
-                let nextDivFirstDiv = $nextWritting[0].firstChild;
-                if (nextDivFirstDiv) {
-                  $nextWritting[0].insertBefore($nextLsitenTitle[0], nextDivFirstDiv);
+              let titleChilds = $child.childNodes();
+              let titleIndex = titleChilds.length - 1;
+              while(titleIndex >= 0) {
+                let line = titleChilds[titleIndex];
+                if (line && line.className) {
+                  if (line.className.indexOf('js-lsiten-line') > -1) {
+                    // 普通一行
+                    let $line = $(line);
+                    bSize = $border.getSizeData();
+                    if (bSize.bottom >= csize.bottom) {
+                      this.insertDom($nextLsitenTitle, $line);
+                    }
+                  } else {
+                    $(line).remove();
+                  }
                 } else {
-                  $nextWritting.append($nextLsitenTitle);
+                  line && $paragraph[0].removeChild(line);
                 }
-                $nextLsitenTitle.addClass('js-split-writting-title');
+                titleIndex--;
+              }
+              if ($nextLsitenTitle.childNodes().length > 0) {
+                this.insertDom($nextWritting, $nextLsitenTitle);
               }
             } else {
               $child.remove();
@@ -462,14 +339,9 @@ questionUtils.prototype = {
               let k = rowLength - 1;
               while ( k >= 0 ) {
                 let bSizeBorder = $border.getSizeData();
-                if (bSizeBorder.bottom > csize.bottom) {
+                if (bSizeBorder.bottom >= csize.bottom) {
                   let $rowItem = $(rows[k]);
-                  let nextDivFirstDiv = $nextLsitenBorder[0].firstChild;
-                  if (nextDivFirstDiv) {
-                    $nextLsitenBorder[0].insertBefore($rowItem[0], nextDivFirstDiv);
-                  } else {
-                    $nextLsitenBorder.append($rowItem);
-                  }
+                  this.insertDom($nextLsitenBorder, $rowItem);
                 }
                 k--;
               }
@@ -478,21 +350,23 @@ questionUtils.prototype = {
             }
 
             if ($nextLsitenBorder.childNodes().length > 0) {
-              let nextDivFirstDiv = $nextWritting[0].firstChild;
-              if (nextDivFirstDiv) {
-                $nextWritting[0].insertBefore($nextLsitenBorder[0], nextDivFirstDiv);
-              } else {
-                $nextWritting.append($nextLsitenBorder);
-              }
+              this.insertDom($nextWritting, $nextLsitenBorder);
               $nextLsitenBorder.addClass('js-split-writting-border');
             } 
+          } else {
+            $child.remove();
           }
         }
         i--;
         isEmptyElement($child[0]) && $child.remove();
       }
     }
-    return $nextWritting.childNodes().length > 0 ? $nextWritting : false;
+
+    if ($nextWritting.childNodes().length > 0) {
+      this.insertDom($nextContent, $nextWritting);
+      $nextWritting.addClass('js-split-question');
+      $item.addClass('js-split-question');
+    }
   }
 }
 

+ 471 - 3
src/js/yzPage.js

@@ -13,6 +13,7 @@ let yzPage = function (manage, $page) {
   this.paragraphIndex = 0;
   // 已经初始化后的内容
   this.$page = $page;
+  this.lineHeight = 25;
   this._init();
   manage.$el.append(this.$textElem);
 }
@@ -26,7 +27,6 @@ yzPage.prototype = {
     // this._initPAndNPlaceholder();
     this.questionTools = new QuestionTools();
     this.questionPrevTools = new QuestionPrevTools();
-    this._addHeader();
   },
   /**
    * function 初始化样式
@@ -74,7 +74,7 @@ yzPage.prototype = {
   /**
    * function 添加表头
    */
-  _addHeader: function () {
+  addHeader: function () {
     this.editor.cmd.do('answerHeader', this);
   },
 
@@ -97,7 +97,11 @@ yzPage.prototype = {
     if (!$currentParagraph && !$column[0].childNodes.length) {
       $column.append($paragraph);
     } else {
-      $paragraph.insertAfter($currentParagraph);
+      if (this.manage.editorPosition.currentParagraph !== this.$el) {
+        $column.append($paragraph);
+      } else {
+        $paragraph.insertAfter($currentParagraph);
+      }
     }
     return $paragraph;
   },
@@ -151,6 +155,470 @@ yzPage.prototype = {
   _updateCrossColumn: function ($column) {
   },
   
+  /** 
+   * @param {DomElement} $column 栏dom
+  */
+  _checkColumnOut($column) {
+    let $paragraphs = $column.find('.js-paragraph-view');
+      let cSize = $column.getSizeData();
+      let i = $paragraphs.length - 1;
+      if(!i || i < 0) {
+        return false;
+      }
+      let $moves = [];
+      while (i >=0 ) {
+        let $paragraph = $($paragraphs[i]);
+        let pSize = $paragraph.getSizeData();
+        if (pSize.top >= cSize.bottom) {
+          $moves.push($paragraph);
+        } else if (pSize.bottom >= cSize.bottom) {
+          this._splitParagraph($moves, $paragraph, cSize, $column);
+        }
+        i--;
+      }
+      if ($moves.length > 0) {
+        let nextColumn = this._getNextColumn($column, true);
+        if (nextColumn.column) {
+          let $firsParagraph = this._getFirstPargraph(nextColumn.column);
+          if ($firsParagraph) {
+            $moves.forEach(item => {
+              this._insertParagraph(item, $firsParagraph);
+            })
+          } else {
+            let moveIndex = $moves.length - 1;
+            while (moveIndex >=0 ) {
+              nextColumn.column.append($moves[moveIndex]);
+              moveIndex--;
+            }
+          }
+          nextColumn.page._checkColumnOut(nextColumn.column);
+        }
+      }
+  },
+  /**
+   * function 插入段落
+  * @param {DomElement}  $insertParagraph 需要插入的段落
+   * @param {DomElement}  $firsParagraph 插入该段之前
+   */
+  _insertParagraph: function ($insertParagraph, $firsParagraph) {
+    let insertClass = $insertParagraph.attr('class');
+    let firstClass = $firsParagraph.attr('class');
+    if (insertClass && firstClass && insertClass.indexOf('js-split-paragraph') >-1 && firstClass.indexOf('js-split-paragraph') >-1) {
+      let insertLast = $insertParagraph[0].lastChild;
+      let firstFirst = $firsParagraph[0].firstChild;
+      this._mergeSplitParagraph(insertLast, firstFirst, $insertParagraph);
+    } else {
+      $insertParagraph.insertBefore($firsParagraph);
+    }
+  },
+  /**
+   * function 插入内容在该dom之前
+   * @param {DomElement}
+   */
+  _insertDomBeforeByFirst: function ($paragraph, first) {
+    $paragraph.childNodes().forEach(child => {
+      $(child).insertBefore($(first));
+    })
+  },
+  /**
+   * function 合并拆分过的段落
+   * @param {node} 上一段最后一个dom
+   * @param {node} 下一段第一个dom
+   * @param {DomElement} 需要插入的段落
+   */
+  _mergeSplitParagraph: function (insertLast, firstFirst, $Allparagraph) {
+    if (!insertLast) {
+      return false;
+    }
+    if (insertLast.className && insertLast.className.indexOf('js-lsiten-line') > -1) {
+      // 普通行处理
+      this._insertDomBeforeByFirst($Allparagraph, firstFirst);
+    } else if (insertLast.className && insertLast.className.indexOf('js-lsiten-border') > -1) {
+      // 框处理
+      if (firstFirst.className && firstFirst.className.indexOf('js-lsiten-border') > -1) {
+        // 如果下一段第一个dom是框
+        let borderId = insertLast.getAttribute('data-id');
+        let nextBorderId = firstFirst.getAttribute('data-id');
+        if (borderId === nextBorderId) {
+          // 如果两个框是同一个框
+          let insertLastQuestion = insertLast.firstChild.lastChild;
+          let firstFirstQuestion = firstFirst.firstChild.firstChild;
+          this._mergeSplitBorder(insertLastQuestion, firstFirstQuestion, $(insertLast));
+          this._insertDomBeforeByFirst($Allparagraph, firstFirst);
+        } else {
+          // 如果不是同一个框
+          this._insertDomBeforeByFirst($Allparagraph, firstFirst);               
+        }
+      } else {
+        // 如果下一段第一个dom不是框
+        this._insertDomBeforeByFirst($Allparagraph, firstFirst);
+      }
+      
+    } else {
+      let parentNode = insertLast.parentNode;
+      $(insertLast).remove();
+      this._mergeSplitParagraph(parentNode.lastChild, firstFirst);
+    }
+  },
+  /**
+   * function 合并框
+   * @param {node} lQuestion 上一段最后一个问题
+   * @param {node} fQuestion 下一段第一个问题
+   * @param {DomElement} $Allborder 该框所有dom
+   */
+  _mergeSplitBorder: function (lQuestion, fQuestion, $Allborder) {
+    if (!lQuestion) {
+      return false;
+    }
+    if (lQuestion.className && lQuestion.className.indexOf('js-lsiten-line') > -1) {
+      // 普通行处理
+      this._insertDomBeforeByFirst($Allborder, fQuestion);
+      $Allborder.remove();
+    } else if (lQuestion.className && lQuestion.className.indexOf('js-lsiten-question') > -1) {
+      // 主观题才需要合并
+      let type = parseInt(lQuestion.getAttribute('data-type'));
+      if (type > 2) {
+        if (fQuestion.className && fQuestion.className.indexOf('js-lsiten-question') > -1) {
+          let questionId = lQuestion.getAttribute('data-id');
+          let nextQuestionId = fQuestion.getAttribute('data-id');
+          if (questionId === nextQuestionId) {
+            // 不是同一个题
+            if (type === 3) {
+              // 客观题
+              let $lquestion = $(lQuestion);
+              let fQuestionFirst = fQuestion.firstChild;
+              this._insertDomBeforeByFirst($lquestion, fQuestionFirst);
+              $lquestion.remove();
+              this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
+              $Allborder.remove();
+            } else if (type === 4) {
+              // 作文题
+              let questionContent = lQuestion.lastChild;
+              let firstContent = fQuestion.firstChild;
+              if (questionContent.className && questionContent.className.indexOf('lsiten-title') > -1) {
+                if (firstContent.className && firstContent.className.indexOf('lsiten-title') > -1) {
+                  let $writtingTitle = $(questionContent);
+                  this._insertDomBeforeByFirst($writtingTitle, firstContent.firstChild);
+                  $writtingTitle.remove();
+                  this._insertDomBeforeByFirst($(lQuestion), firstContent);
+                  $(lQuestion).remove();
+                  this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
+                  $Allborder.remove();
+                } else {
+                  this._insertDomBeforeByFirst($(lQuestion), firstContent);
+                  $(lQuestion).remove();
+                  this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
+                  $Allborder.remove();
+                }
+              } else if (questionContent.className && questionContent.className.indexOf('lsiten-border-box') > -1) {
+                if (firstContent.className && firstContent.className.indexOf('lsiten-border-box') > -1) {
+                  let $writtingRows = $(questionContent);
+                  this._insertDomBeforeByFirst($writtingRows, firstContent.firstChild);
+                  $writtingRows.remove();
+                  this._insertDomBeforeByFirst($(lQuestion), firstContent);
+                  $(lQuestion).remove();
+                  this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
+                  $Allborder.remove();
+                } else {
+                  this._insertDomBeforeByFirst($(lQuestion), firstContent);
+                  $(lQuestion).remove();
+                  this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
+                  $Allborder.remove();
+                }
+              } else {
+                questionContent && questionContent.parentNode.removeChild(questionContent);
+              }
+            }
+          } else {
+            // 不是同一个题
+            this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
+            $Allborder.remove();
+          }
+        } else {
+          // 下一段第一个不是一个问题
+          this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
+          $Allborder.remove();
+        }
+      } else {
+        // 客观题处理
+        this._insertDomBeforeByFirst($($Allborder[0].firstChild), fQuestion);
+        $Allborder.remove();
+      }
+    } else {
+      let parentNode = lQuestion.parentNode;
+      $(lQuestion).remove();
+      this._mergeSplitBorder(parentNode.lastChild, fQuestion, $Allborder);
+    }
+  },
+   /**
+   * function 检测内容是否需要回退
+   */
+  _checkContentBack: function () {
+    let $columns = this.$colums;
+    // 备用
+    let maxHeight = parseInt(this._pagesHeight[this.editor.pageSize]);
+    $columns.forEach($column => {
+      this._checkColumnBack($column);   
+    });
+  },
+  /**
+   * function 检测该段落是否为答题卡头
+   * @param {DomElement} 需要检测的段落
+   */
+  isHeadParagraph: function ($paragraph) {
+    let firstChild = $paragraph[0].firstChild;
+    return firstChild && firstChild.className && firstChild.className.indexOf('js-answer-header') > -1;
+  },
+  /**
+   * function 检测栏是否需要回退
+   * @param {DomElement} $column 需要检测的栏
+   */
+  _checkColumnBack: function ($column) {
+    let $paragraphs = $column.find('.js-paragraph-view');
+    let cSize = $column.getSizeData();
+    let i = $paragraphs.length - 1;
+    if(!i || i < 0) {
+      return false;
+    }
+    let $moves = [];
+    let $lastParagraph = $($paragraphs[i]);
+    let lastSize = $lastParagraph.getSizeData();
+    let diff = cSize.bottom - lastSize.bottom;
+    if (diff > this.lineHeight) {
+      let nextColumn = this._getNextColumn($column, false);
+      // 如果有下一页,进行检测
+      if (nextColumn.column) {
+        let $nextParagraphs = nextColumn.column.find('.js-paragraph-view');
+        while (i >=0 ) {
+          let $paragraph = $($nextParagraphs[i]);
+          if (!this.isHeadParagraph($paragraph)) {
+            let pSize = $paragraph.getSizeData();
+            if (pSize.height < diff) {
+              $moves.push($paragraph);
+            } else {
+              this._prevParagraph($moves, $paragraph, diff, $lastParagraph);
+            }
+          }
+          i--;
+        }
+      }
+    }
+  },
+
+  /**
+   * function 检测段落是否需要上移
+   * @param {array} $moves 需要移动的段落数组
+   * @param {DomElement} $paragraph  需要检测的段落
+   * @param {number} diff  可以上移的空间
+   * @param {DomElement} $lastParagraph  该段最后一段
+   */
+  _prevParagraph: function ($moves, $paragraph, diff, $lastParagraph) {
+    let lastClass = $lastParagraph.attr('class');
+    let currentClass = $paragraph.attr('class');
+    let lastPid = $lastParagraph.attr('data-index');
+    let currentPid = $paragraph.attr('data-index');
+    if (lastClass && lastClass.indexOf('js-split-paragraph') > -1) {
+      if (currentClass && currentClass.indexOf('js-split-paragraph') > -1 && lastPid === currentPid) {
+        // 如果两个段落需要合并
+        let $prevParagraph = $paragraph.clone(false);
+        $paragraph.childNodes().forEach(item => {
+          if (item.nodeType === 3) {
+            $paragraph[0].removeChild(item);
+          } else {
+            let $item = $(item);
+            let itemClass = $item.attr('class');
+            if (itemClass && itemClass.indexOf('js-lsiten-line') > -1) {
+              // 普通行
+              let height = $item.getSizeData().height;
+              if (height < diff) {
+                $prevParagraph.append($item);
+                diff -= height;
+              }
+            } else if (itemClass && itemClass.indexOf('js-lsiten-border') > -1) {
+              // 框处理
+              this._prevBorder($prevParagraph, diff, $item, $lastParagraph);
+            } else {
+              $item.remove();
+            }
+          }
+        })
+        if (!isEmptyElement($prevParagraph[0])) {
+          $moves.push($prevParagraph);
+        }
+      } else {
+
+      }
+    } else {
+
+    }
+  },
+
+  /**
+   * function 处理需要上移的框
+   * @param {DomElement} $prevParagraph 前移段落暂存
+   * @param {number} diff 可移空间
+   * @param {DomElement} $border 需要处理的框
+   * @param {DomElement} $lastParagraph 最后一段dom
+   */
+  _prevBorder: function ($prevParagraph, diff, $border, $lastParagraph) {
+    let lastCentent = $lastParagraph[0].lastChild;
+    if (lastCentent.className && lastCentent.className.indexOf('js-lsiten-border') > -1) {
+      let prevBid = $border.attr('data-id');
+      let bid = $(lastCentent).attr('data-id');
+      if (prevBid === bid) {
+        let $prevBorder = $border.clone(false);
+        this._prevQuestions($prevParagraph, diff, $border, $(lastCentent));
+      } else {
+        let borderSize= $border.getSizeData();
+        if (borderSize.height < diff) {
+          $prevParagraph.append($border);
+          diff -= borderSize.height;          
+        }
+      }
+    } else {
+      let borderSize= $border.getSizeData();
+      if (borderSize.height < diff) {
+        $prevParagraph.append($border);
+        diff -= borderSize.height;
+      }
+    }
+  },
+  /**
+   * function 前移问题
+   * @param {DomElement} $prevParagraph 前移段落暂存
+   * @param {number} diff 前移段落暂存
+   * @param {DomElement} $border 前移段落暂存
+   * @param {DomElement} $lastQuestion 前移段落暂存
+   * 
+   */
+  _prevQuestions: function ($prevParagraph, diff, $border, $lastQuestion) {
+    
+  },
+  /**
+   * function 检测内容是否超出
+   */
+  _checkContentOut: function () {
+    let $columns = this.$colums;
+    // 备用
+    let maxHeight = parseInt(this._pagesHeight[this.editor.pageSize]);
+    $columns.forEach($column => {
+      this._checkColumnOut($column);   
+    });
+  },
+  /**
+   * function 获取第一段 
+   */
+  _getFirstPargraph: function (column) {
+    let $paragraphs = column.find('.js-paragraph-view');
+    let firstParagraph = $paragraphs[0];
+    let firstChild = firstParagraph.firstChild;
+    if (firstChild && firstChild.className && firstChild.className.indexOf('js-answer-header') > -1) {
+      firstParagraph = $paragraphs[1];
+    }
+    return firstParagraph ? $(firstParagraph): false;
+  },
+  /**
+   * function 插入dom
+   * @param {DomElement}  $nextDom 下一栏暂存
+   * @param {DomElement}  $dom 需要插入的dom
+   */
+  insertDom($nextDom, $dom) {
+    let firstChild = $nextDom[0].firstChild;
+    if (firstChild) {
+      $dom.insertBefore($(firstChild));
+    } else {
+      $nextDom.append($dom);
+    }
+  },
+  /**
+   * function 拆分段落
+   * @param $moves {Array} 需要移动的数组
+   * @param $paragraph {DomElement} 需要切分的段落
+   * @param cSize {Object} 段落尺寸数据
+   * @param $column {DomElement} 当前栏
+   */
+  _splitParagraph: function ($moves, $paragraph, cSize, $column) {
+    let $nextParagraph = $paragraph.clone(false);
+    let childs = $paragraph[0].childNodes;
+    let index = childs.length - 1;
+    while (index >= 0) {
+      let line = childs[index];
+      if (line && line.className) {
+        if (line.className.indexOf('js-lsiten-line') > -1) {
+          // 普通一行
+          let $line = $(line);
+          let lineSize = $line.getSizeData();
+          if (lineSize.top >= cSize.bottom) {
+            this.insertDom($nextParagraph, $line);
+          }
+        } else if (line.className.indexOf('js-lsiten-border') > -1) {
+          // 题框
+          this._splitBorder($nextParagraph, $(line), cSize);
+        } else {
+          $(line).remove();
+        }
+      } else {
+        line && $paragraph[0].removeChild(line);
+      }
+      index--;
+    }
+    if ($nextParagraph.childNodes().length > 0) {
+      $paragraph.addClass('js-split-paragraph');
+      $nextParagraph.addClass('js-split-paragraph');
+      $moves.push($nextParagraph);
+    }
+  },
+
+  /**
+   * function 获取下一栏
+   * @param {DomElement} $column 当前栏
+   * @param {boolean} isAddpage 是否需要新增页
+   */
+  _getNextColumn: function ($column, isAddPage) {
+    let nextColumnIndex = parseInt($column.attr('data-column-i')) + 1;
+    let $nextColumn = this.$colums[nextColumnIndex];
+    if ($nextColumn) {
+      return {
+        page: this,
+        column: $nextColumn
+      };
+    } else {
+      let page = this._getNextPage(isAddPage);
+      if (page) {
+        $nextColumn = page.$colums[0];
+        return {
+          page: page,
+          column: $nextColumn
+        };
+      } else {
+        return {
+          page: false,
+          column: false
+        };
+      }
+    }
+  },
+  /**
+   * function 获取下一页对象
+   * @param {Boolean} isAddPage 如果没有是否添加一页
+   */
+  _getNextPage: function (isAddPage) {
+    let nextPageIndex = this.pageIndex + 1;
+    let page = this.manage.getNextPageByKey(nextPageIndex, isAddPage)
+    return page;
+  },
+  /**
+   * function 拆分框
+   * @param $nextParagraph {DomElement} 下一段暂存
+   * @param $border {DomElement} 需要切分的框
+   * @param cSize {Object} 段落尺寸数据
+   */
+  _splitBorder: function ($nextParagraph, $border, cSize) {
+    let $splitBorder = this.questionTools._splitBorder($border, cSize);
+    if ($splitBorder) {
+      this.insertDom($nextParagraph, $splitBorder);
+    }
+  },
   
   _pagesHeight: {
     'A4': '970px',

+ 55 - 8
src/js/yzPageManager.js

@@ -12,6 +12,8 @@ let yzPageManager = function (editor) {
   this.pages = [];
   // enter键状态
   this._event = null;
+  this._checkPageOutStatus = false;  
+  this._checkPageBackStatus = false;  
 
   // 输入法监听 
   this.inputType = false;
@@ -29,8 +31,6 @@ yzPageManager.prototype = {
   _init: function () {
     this._initStyles();
     this._addPage();
-    this.pageIndex++;
-
     this._initEvents();
   },
   /**
@@ -56,6 +56,25 @@ yzPageManager.prototype = {
     let page = new yzPage(this, '');
     this.pages.push(page);
     this.pageIndex++;
+    page.addHeader();
+    return page;
+  },
+  /**
+   * function 通过key值获取下一页
+   * @param {number} key page的key值
+   * @param {Boolean} isAddPage 如果没有是否添加一页
+   */
+  getNextPageByKey: function (key, isAddPage) {
+    let page = this.pages[key];
+    if (page) {
+      return page;
+    } else {
+      if (isAddPage) {
+        return this._addPage();
+      } else {
+        return false;
+      }
+    }
   },
   _addBreakPlaceholder: function () {
     if (this.pageIndex < 1) {
@@ -82,6 +101,30 @@ yzPageManager.prototype = {
     let height = this.pages.length * this._pagesBreakHeight[this.editor.pageSize] + parseInt(this._pagesHeight[this.editor.pageSize]);
     this.$el.css('height', height + 'px');
   },
+
+  _checkEveryPageOut: function () {
+    if (this._checkPageOutStatus) {
+      return false;
+    }
+    this._checkPageOutStatus = true;
+    let pages = this.pages;
+    pages.forEach(page => {
+      page._checkContentOut();
+    });
+    this._checkPageOutStatus = false;
+  },
+
+  _checkEveryPageBack: function () {
+    if (this._checkPageBackStatus) {
+      return false;
+    }
+    this._checkPageBackStatus = true;
+    let pages = this.pages;
+    pages.forEach(page => {
+      page._checkContentBack();
+    });
+    this._checkPageBackStatus = false;
+  },
   /**
    * function 添加事件监听 
    */
@@ -100,12 +143,12 @@ yzPageManager.prototype = {
     const $textElem = this.$el;
     const editor =this.editor;
     let _this = this;
-    Jquery($textElem[0]).on('DOMNodeInserted', function (e) {
-      console.log('insert');
+    Jquery($textElem[0]).on('addContent', function (e) {
+      _this._checkEveryPageOut();
     })
 
-    Jquery($textElem[0]).on('DOMNodeRemoved', function (e) {
-      console.log('remove');
+    Jquery($textElem[0]).on('removeContent', function (e) {
+      _this._checkEveryPageBack();
     })
   },
   /** 
@@ -130,6 +173,7 @@ yzPageManager.prototype = {
           let nextLine = $currentLine[0].nextSibling;
           if (nextLine && nextLine.className && nextLine.className.indexOf('js-lsiten-line') > -1 && isEmptyElement(nextLine)) {
             $(nextLine).remove();
+            Jquery($textElem[0]).trigger('removeContent');
             return false;          
           } else {
             return false;
@@ -162,6 +206,7 @@ yzPageManager.prototype = {
           if (prevLine && prevLine.className && prevLine.className.indexOf('js-lsiten-line') > -1) {
             $currentLine.remove();
             prevLine.focus();
+            Jquery($textElem[0]).trigger('removeContent');
             return false;            
           } else {
             return false;
@@ -193,6 +238,8 @@ yzPageManager.prototype = {
         $newLine.insertAfter($currentLine);
         $newLine.focus();
       }
+
+      Jquery($textElem[0]).trigger('addContent');
       return false;
     })
   },
@@ -236,12 +283,12 @@ yzPageManager.prototype = {
 
     let $currentColumn = getParentByClassname($paragraph, 'js-column');
     if (!$currentColumn) {
-      console.log($selectionElem, console.log("%c数据错误!", "color:red"));
+      console.log($target, console.log("%c数据错误!", "color:red"));
       return false;
     }
     this.currentPage = this.pages[parseInt($currentColumn.attr('data-column-page'))];
     if (!this.currentPage) {
-      console.log($selectionElem, console.log("%c数据错误!", "color:red"));
+      console.log($target, $currentColumn, $paragraph, console.log("%c数据错误!", "color:red"));
       return false;
     }
     this.currentPage.currentColumn = parseInt($currentColumn.attr('data-column-i'));

+ 0 - 1
src/js/yzWebeditor.js

@@ -86,7 +86,6 @@ yzWebeditor.prototype = {
   // 添加页面 
   _addPage: function() {
     this.page = new yzPageManager(this);
-    this.$textElem = this.page.$textElem;
     this.$editorArea.append(this.page.$el);
   },
   // 封装 command API