lsiten 6 years ago
parent
commit
f865f8fd96

+ 1 - 1
src/js/command/index.js

@@ -37,7 +37,7 @@ Command.prototype = {
             // 默认 command
             // 修改菜单状态
             // 恢复选取
-            // editor.selection.restoreSelection()
+            editor.selection.restoreSelection()
             editor.menus.changeActive() 
             return this._execCommand(name, value)
         }

+ 2 - 2
src/js/menus/bold/index.js

@@ -28,8 +28,8 @@ Bold.prototype = {
         const editor = this.editor
         const isSeleEmpty = editor.selection.isSelectionEmpty()
         if (isSeleEmpty) {
-            // 选区是空的,插入并选中一个“空白”
-            editor.selection.createEmptyRange()
+          // 选区是空的,插入并选中一个“空白”
+          editor.selection.createEmptyRange()
         }
         // 执行 bold 命令
         editor.cmd.do('bold')

+ 0 - 1
src/js/menus/questionBorder/index.js

@@ -35,7 +35,6 @@ Questionborder.prototype = {
 
     // 执行命令
     _command: function (value) {
-        console.log(value)
         let funName = 'lsiten_' + value;
         if (this[funName]) {
           this[funName]();

+ 1 - 0
src/js/menus/questiontype/index.js

@@ -98,6 +98,7 @@ Questiontype.prototype = {
           proId: '1022',
           quId: '1656',
           quType: '解答题',
+          proData: {},
           score: 5,
           visible: true
         }

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

@@ -67,6 +67,8 @@ function objectBorder (editor, data) {
   }
 
   $para.append(border);
+  border.focus();
+  editor.page._updatePositionInfo(null, border);
 }
 
 // 主观题框
@@ -83,7 +85,8 @@ function subjectBorder (editor, data) {
   border.attr('data-type', 2);
   border.attr('data-sort', sortIndex);
   border.attr('tabindex', 1);
-  $(border[0].firstChild).append(gennerOneLine());
+  let newLine = gennerOneLine();
+  $(border[0].firstChild).append(newLine);
   // style start
   border.css('border', '1px solid #000')
   .css('padding', '10px 15px')
@@ -138,6 +141,8 @@ function subjectBorder (editor, data) {
     border[0].firstChild.insertBefore($optional[0], border[0].firstChild.firstChild);
   }
   $para.append(border);
+  newLine.focus();
+  editor.page._updatePositionInfo(null, newLine); 
 }
 let Border = function (params) {
   let editor = this.editor;

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

@@ -8,9 +8,8 @@ let Questiontype = function (params) {
   if (!visible) {
     return false;
   }
-  const selection = editor.selection;
-  let $selectionElem = selection.getSelectionContainerElem();
-  let border = getParentByClassname($selectionElem, 'js-lsiten-border');
+  const manage = editor.page;
+  let border = manage.editorPosition.currentBorder;
   if (!border) {
     editor.message.showMessage('请在题框中添加题!');
     return '';

+ 16 - 10
src/js/question/choice.js

@@ -1,5 +1,6 @@
 import $ from '../util/dom-core.js';
 import { getParentByClassname, isEmptyElement } from '../util/util.js';
+import { gennerOneLine } from '../util/lineUtil.js';
 const _mapOptionNum = [
   'A', 'B', 'C', 'D', 'E', 'F',
   'G', 'H', 'I', 'J', 'K', 'L',
@@ -102,22 +103,27 @@ let generateChoice = function ($border, data, editor) {
     $currentRow.find('.js-option-column').css('min-height', size.height + 'px');
   } else {
     // 在主观题内添加
-    let $selectionElem = editor.selection.getSelectionContainerElem();
-    let $borderContent = getParentByClassname($selectionElem, 'border-content');
+    let $currentLine = editor.page.editorPosition.currentLine;
+    if (!$currentLine) {
+      console.log("%c请在框内添加该题!", "color:red");
+      return '';
+    }
+    let $borderContent = getParentByClassname($currentLine, 'border-content');
     if (!$borderContent) {
       console.log("%c请在框内添加该题!", "color:red");
       return '';
     }
-    $borderContent.append($questionItem);
+    let $newLine = gennerOneLine();
+    $($newLine[0].firstChild).remove();
+    $newLine.append($questionItem);
+    $newLine.insertAfter($currentLine);
+
     if ( isEmptyElement($borderContent[0].firstChild) ) {
-      $borderContent[0].removeChild($borderContent[0].firstChild);
-    }
-    editor.selection.getRange().setStartAfter($questionItem[0]);
-    if (editor.selection.getRange()) {
-      editor.selection.restoreSelection();
+      $($borderContent[0].firstChild).remove();
     }
-    editor.selection.saveRange();
-    editor.selection.collapseRange();
+
+    $newLine.focus();
+    editor.page._updatePositionInfo(null, $newLine); 
   }
  }
  /**

+ 16 - 11
src/js/question/judge.js

@@ -1,5 +1,6 @@
 import $ from '../util/dom-core.js';
 import { getParentByClassname, isEmptyElement } from '../util/util.js';
+import { gennerOneLine } from '../util/lineUtil.js';
  /**
   * function 生成判断题
   * @param {DomElement} $border 需要添加题的框
@@ -90,24 +91,28 @@ import { getParentByClassname, isEmptyElement } from '../util/util.js';
     $currentRow.find('.js-option-column').css('min-height', size.height + 'px');
   } else {
     // 在主观题内添加
-    let $selectionElem = editor.selection.getSelectionContainerElem();
-    let $borderContent = getParentByClassname($selectionElem, 'border-content');
+    let $currentLine = editor.page.editorPosition.currentLine;
+    if (!$currentLine) {
+      console.log("%c请在框内添加该题!", "color:red");
+      return '';
+    }
+    let $borderContent = getParentByClassname($currentLine, 'border-content');
     if (!$borderContent) {
-      console.log("%c请在框内添加该题!", "color:red");      
+      console.log("%c请在框内添加该题!", "color:red");
       return '';
     }
 
-    $borderContent.append($questionItem);
+    let $newLine = gennerOneLine();
+    $($newLine[0].firstChild).remove();
+    $newLine.append($questionItem);
+    $newLine.insertAfter($currentLine);
 
     if ( isEmptyElement($borderContent[0].firstChild) ) {
-      $borderContent[0].removeChild($borderContent[0].firstChild);
+      $($borderContent[0].firstChild).remove();
     }
-    editor.selection.getRange().setStartAfter($questionItem[0]);
-    if (editor.selection.getRange()) {
-      editor.selection.restoreSelection();
-    }
-    editor.selection.saveRange();
-    editor.selection.collapseRange();
+
+    $newLine.focus();
+    editor.page._updatePositionInfo(null, $newLine); 
   }
  }
  /**

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

@@ -420,6 +420,11 @@ let generateQuestionHead = function (editor, key, $page) {
     $firstParagraph = currentPage.addParagraph();
   }
   $firstParagraph.append($header);
+
+  $header.find('.js-answer-header-title').focus();
+  setTimeout(() => {
+    editor.page._updatePositionInfo({}, $header);    
+  }, 0);
   return true;
 }
 

+ 17 - 12
src/js/question/subject.js

@@ -1,5 +1,6 @@
 import $ from '../util/dom-core.js';
 import { getParentByClassname, isEmptyElement } from '../util/util.js';
+import { gennerOneLine, gennerOneLines } from '../util/lineUtil.js';
 
 /**
  * function 生成主观题区
@@ -21,27 +22,31 @@ let generateSubjectBox = function ($border, data, editor) {
     pnum = mergePnum +''+ pnum;
   }
 
-  let $box = $('<div class = "lsiten-subject-box js-lsiten-question"><p>'+pnum+'、</p><p><br/></p><p><br/></p><p><br/></p></div>');
+  let $box = $('<div class = "lsiten-subject-box js-lsiten-question"></div>');
   $box.attr('data-type', 3);
-  let $selectionElem = editor.selection.getSelectionContainerElem();
-  let $borderContent = getParentByClassname($selectionElem, 'border-content');
+  gennerOneLines(4, $box, pnum);
+  // 在主观题内添加
+  let $currentLine = editor.page.editorPosition.currentLine;
+  if (!$currentLine) {
+    console.log("%c请在框内添加该题!", "color:red");
+    return '';
+  }
+  let $borderContent = getParentByClassname($currentLine, 'border-content');
   if (!$borderContent) {
     console.log("%c请在框内添加该题!", "color:red");
     return '';
   }
-
-  $borderContent.append($box);
-
+  let questionBox = getParentByClassname($currentLine, 'js-lsiten-question');
+  if (questionBox) {
+    $currentLine = parseInt(questionBox.attr('data-type')) > 2 ? questionBox : questionBox.parent();
+  }
+  $box.insertAfter($currentLine);
   if ( isEmptyElement($borderContent[0].firstChild) ) {
     $borderContent[0].removeChild($borderContent[0].firstChild);
   }
 
-  editor.selection.getRange().setStart($box[0], 0);
-  if (editor.selection.getRange()) {
-    editor.selection.restoreSelection();
-  }
-  editor.selection.saveRange();
-  editor.selection.collapseRange();
+  $box[0].firstChild.focus();
+  editor.page._updatePositionInfo(null, $($box[0].firstChild));
 }
 
 export default {

+ 17 - 12
src/js/question/writing.js

@@ -1,5 +1,6 @@
 import $ from '../util/dom-core.js';
 import { getParentByClassname, isEmptyElement } from '../util/util.js';
+import { gennerOneLines } from '../util/lineUtil.js';
 
 /**
  * 
@@ -21,31 +22,35 @@ let generateWriting = function ($border, data, editor) {
   $box.attr('data-pnum', pnum);
   $box.attr('data-total', total);
   // 1、生成题号区
-  let $title = $('<div class="lsiten-title"><p>' + pnum + '</p></div>');
+  let $title = $('<div class="lsiten-title"></div>');
   $title.css('padding', '0 15px');
+  gennerOneLines(1, $title, pnum);
   $box.append($title);
   // 2、生成格子区域
   let column = getColumnCount(editor);
   let $grid = generateGrid(column, total);
   $box.append($grid);
-  let $selectionElem = editor.selection.getSelectionContainerElem();
-  let $borderContent = getParentByClassname($selectionElem, 'border-content');
+  // 在主观题内添加
+  let $currentLine = editor.page.editorPosition.currentLine;
+  if (!$currentLine) {
+    console.log("%c请在框内添加该题!", "color:red");
+    return '';
+  }
+  let $borderContent = getParentByClassname($currentLine, 'border-content');
   if (!$borderContent) {
     console.log("%c请在框内添加该题!", "color:red");
     return '';
   }
-  $borderContent.append($box);
-
+  let questionBox = getParentByClassname($currentLine, 'js-lsiten-question');
+  if (questionBox) {
+    $currentLine = parseInt(questionBox.attr('data-type')) > 2 ? questionBox : questionBox.parent();
+  }
+  $box.insertAfter($currentLine);
   if ( isEmptyElement($borderContent[0].firstChild) ) {
     $borderContent[0].removeChild($borderContent[0].firstChild);
   }
-
-  editor.selection.getRange().setStart($box[0], 0);
-  if (editor.selection.getRange()) {
-    editor.selection.restoreSelection();
-  }
-  editor.selection.saveRange();
-  editor.selection.collapseRange();
+  $title[0].firstChild.focus();
+  editor.page._updatePositionInfo(null, $($title[0].firstChild));
 }
 
 /**

+ 38 - 25
src/js/selection/index.js

@@ -15,9 +15,7 @@
 */
 
 import $ from '../util/dom-core.js'
-import { UA, getParentByClassname, getParentNodeByClass } from '../util/util.js'
-import Jquery from 'jquery'
-import 'jquery.caret'
+import { UA, getParentByClassname, getParentNodeByClass, isEmptyElement } from '../util/util.js'
 
 // 构造函数
 function API(editor) {
@@ -30,6 +28,10 @@ function API(editor) {
 API.prototype = {
     constructor: API,
     fillChar: '\u200B',
+    // 置空 range 对象
+    setEmptyRange: function () {
+        this._currentRange = null;
+    },
     // 获取 range 对象
     getRange: function () {
         return this._currentRange
@@ -188,6 +190,9 @@ API.prototype = {
 
     // 恢复选区
     restoreSelection: function () {
+        if (!this._currentRange) {
+          return '';
+        }
         const selection = window.getSelection()
         selection.removeAllRanges()
         selection.addRange(this._currentRange)
@@ -250,30 +255,38 @@ API.prototype = {
         }
         // 存储 range
         this.saveRange(range)
+    },    
+    // 光标是否在最后
+    isCartEnd: function ($line, range) {
+      range = range || this._currentRange;
+      if (isEmptyElement($line[0])) {
+        return true;
+      }
+      let lastChild = $line[0].lastChild;      
+      if (lastChild.nodeType === 3) {
+        if (range.startOffset === range.endOffset && range.startOffset === lastChild.length) {
+          return true
+        }
+      } else {
+        return this.isEndDom(range, lastChild);
+      }
+      return false;
     },
-
-    getCaretPosition: function (editableDiv) {
-        let caretPos = 0, sel, range;
-        if (window.getSelection) {
-          sel = window.getSelection();
-          if (sel.rangeCount) {
-            range = sel.getRangeAt(0);
-            if (range.commonAncestorContainer.parentNode == editableDiv) {
-              caretPos = range.endOffset;
-            }
-          }
-        } else if (document.selection && document.selection.createRange) {
-          range = document.selection.createRange();
-          if (range.parentElement() == editableDiv) {
-            let tempEl = document.createElement("span");
-            editableDiv.insertBefore(tempEl, editableDiv.firstChild);
-            let tempRange = range.duplicate();
-            tempRange.moveToElementText(tempEl);
-            tempRange.setEndPoint("EndToEnd", range);
-            caretPos = tempRange.text.length;
-          }
+    // 递归判断光标是否在最后
+    isEndDom (range, dom) {
+      let lastChild = dom.lastChild;
+      if (isEmptyElement(dom)) {
+        return true;
+      }
+      if (lastChild.nodeType === 3) {
+        if (range.startOffset === range.endOffset && range.startOffset === lastChild.length) {
+            return true;
+        } else {
+            return false;
         }
-        return caretPos;
+      } else {
+        return isEndDom(range, lastChild);
+      }
     }
 
 }

+ 13 - 3
src/js/util/lineUtil.js

@@ -2,9 +2,19 @@
     工具
 */
 import $ from './dom-core'
-// 遍历类数组
-export function gennerOneLine() {
-  let line = $('<div class="js-lsiten-line" contenteditable="true"><br/></div>');
+// 生成行
+export function gennerOneLine(pnum) {
+  let content = pnum || '<br/>'
+  let line = $('<div class="js-lsiten-line" contenteditable="true">' + content + '</div>');
   line.css('outline', 'none').css('width', '100%').css('height', '25px').css('line-height', '25px').css('overflow', 'hidden').css('white-space', 'nowrap');
   return line;
+}
+
+/** 
+ * function 生成多行
+*/
+export function gennerOneLines(num, $content, pnum) {
+  for (let i =0; i < num; i++) {
+    i === 0 ? $content.append(gennerOneLine((pnum + '、'))) : $content.append(gennerOneLine());
+  }
 }

+ 127 - 3
src/js/yzPageManager.js

@@ -1,4 +1,5 @@
 import $ from './util/dom-core.js';
+import { gennerOneLine } from './util/lineUtil.js';
 import Jquery from 'jquery';
 import yzPage from './yzPage.js';
 import { UA, isFunction, replaceHtmlSymbol, getParentByClassname, trim, throttle, isEmptyElement, getParentNodeByClass } from './util/util.js';
@@ -86,6 +87,114 @@ yzPageManager.prototype = {
    */
   _initEvents: function () {
     this._realtimeSavePosition();
+    this._enterEvent();
+    this._backEvent();
+    this._delEvent();
+
+    this._contentchangeEvent();
+  },
+   /** 
+   * function 内容变化事件监听
+  */
+  _contentchangeEvent: function () {
+    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('DOMNodeRemoved', function (e) {
+      console.log('remove');
+    })
+  },
+  /** 
+   * function del键监听
+  */
+  _delEvent: function () {
+    const $textElem = this.$el;
+    const editor =this.editor;
+    let _this = this;
+    Jquery($textElem[0]).on('keydown', function (e) {       
+      if (e.keyCode !== 46) {
+        // 不是回车键
+        return '';
+      }
+      if (getParentByClassname($(e.target), 'js-answer-header-title')) {
+        return '';
+      }
+      let $currentLine = _this.editorPosition.currentLine;
+      if ($currentLine) {
+        let selection = _this.editor.selection;
+        if (selection.isCartEnd($currentLine)) {
+          let nextLine = $currentLine[0].nextSibling;
+          if (nextLine && nextLine.className && nextLine.className.indexOf('js-lsiten-line') > -1 && isEmptyElement(nextLine)) {
+            $(nextLine).remove();
+            return false;          
+          } else {
+            return false;
+          }
+        }
+      } else {
+        return false;
+      }
+    })
+  },
+  /** 
+   * function 退格键监听
+  */
+  _backEvent () {
+    const $textElem = this.$el;
+    const editor =this.editor;
+    let _this = this;
+    Jquery($textElem[0]).on('keydown', function (e) {       
+      if (e.keyCode !== 8) {
+        // 不是回车键
+        return '';
+      }
+      if (getParentByClassname($(e.target), 'js-answer-header-title')) {
+        return '';
+      }
+      let $currentLine = _this.editorPosition.currentLine;
+      if ($currentLine) {
+        if (isEmptyElement($currentLine[0])) {
+          let prevLine = $currentLine[0].previousSibling;
+          if (prevLine && prevLine.className && prevLine.className.indexOf('js-lsiten-line') > -1) {
+            $currentLine.remove();
+            prevLine.focus();
+            return false;            
+          } else {
+            return false;
+          }
+        }
+      } else {
+        return false;
+      }
+    })
+  },
+  /**
+   * function 监听enter键事件
+   */
+  _enterEvent: function () {
+    const $textElem = this.$el;
+    const editor =this.editor;
+    let _this = this;
+    Jquery($textElem[0]).on('keydown', function (e) {       
+      if (e.keyCode !== 13) {
+        // 不是回车键
+        return '';
+      }
+      if (getParentByClassname($(e.target), 'js-answer-header-title')) {
+        return '';
+      }
+      let $currentLine = _this.editorPosition.currentLine;
+      if ($currentLine) {
+        let $newLine = gennerOneLine();
+        $newLine.insertAfter($currentLine);
+        $newLine.focus();
+      }
+      return false;
+    })
   },
   /**
    * function 实时保存当前编辑信息
@@ -116,8 +225,10 @@ yzPageManager.prototype = {
   /**
    * 更新当前编辑信息
    */
-  _updatePositionInfo: function (e) {
-    let $target = $(e.target || e.toElement);
+  _updatePositionInfo: function (e, $ele) {
+    let $target = $ele || $(e.target || e.toElement);
+    let $border = getParentByClassname($target, 'js-lsiten-border');
+    let $line = getParentByClassname($target, 'js-lsiten-line');
     let $paragraph = getParentByClassname($target, 'js-paragraph-view');
     if (!$paragraph) {
       return false;
@@ -138,7 +249,20 @@ yzPageManager.prototype = {
     this.editorPosition = {
       currentParagraph: $paragraph,
       currentColumn: this.currentPage.$colums[this.currentPage.currentColumn],
-      currentPage: this.currentPage
+      currentPage: this.currentPage,
+      currentBorder: $border,
+      currentLine: $line
+    }
+
+    let selection = this.editor.selection;
+    if ($line) {
+      if (!selection.getRange() ||  !selection.getSelectionContainerElem()) {
+        selection.createRangeByElem($line, true);
+      } else {
+        selection.saveRange();
+      }
+    } else {
+      selection.setEmptyRange();
     }
   },
   _pagesWidth: {