Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dom.js can't be documented due to errors. #128

Open
crocket opened this issue Oct 4, 2013 · 1 comment
Open

dom.js can't be documented due to errors. #128

crocket opened this issue Oct 4, 2013 · 1 comment

Comments

@crocket
Copy link

crocket commented Oct 4, 2013

The errors were
! Failed to parse doc tags /blah/blah/dom.js: Cannot read property '1' of null
TypeError: Cannot read property '1' of null
at Object.module.exports.DOC_TAGS.return.parseValue (/home/elisa/repos/others/winternote/node_modules/groc/lib/doc_tags.coffee:180:23)
at Object.module.exports.Utils.parseDocTags (/home/elisa/repos/others/winternote/node_modules/groc/lib/utils.coffee:472:41)
at Default.module.exports.Base.renderFile (/home/elisa/repos/others/winternote/node_modules/groc/lib/styles/base.coffee:31:20)
at /home/elisa/repos/others/winternote/node_modules/groc/lib/project.coffee:74:24
at fs.js:266:14
at Object.oncomplete (fs.js:107:15)

The content of dom.js is shown below.

"use strict";

// > # [Document Object Model](https://developer.mozilla.org/en-US/docs/DOM/About_the_Document_Object_Model)
define('dom', ['underscore', 'iter', 'assert'], function(_, iter, assert) {
  /* ------------------------------------------------------------------------------- */
  // dom predicate

  // ### isBlock
  // > 크기를 갖는 컨테이너 여부 리턴 ex) P, DIV, IMG(float)
  // > [HTML Display property](http://www.w3schools.com/cssref/pr_class_display.asp)
  var isBlock = function(el) {
    if (el && (isBodyContainer(el) || isPara(el) || isList(el) || isHR(el) || isDiv(el) || isTable(el)) ) {
      return true;
    }

    if (el && el.style && el.style["float"] && el.style["float"] !== '' && el.style["float"] !== 'none'
        || (el && el.style && el.style.cssText && el.style.cssText.toLowerCase().indexOf('float') > -1)) {
      return true;
    }

    return false;
  };

  // ### isTable
  // > 테이블 여부 판단
  var isTable = function(el) {
    return el && el.nodeName === "TABLE";
  };

  // ### isTBody
  // > TBody 여부 판단
  var isTBody = function(el) {
    return el && el.nodeName === "TBODY";
  };

  // ### isTHead
  // > THead 여부 판단
  var isTHead = function(el) {
    return el && el.nodeName === "THEAD";
  };

  // ### isTR
  // > TR 여부 판단
  // * `el` HTMLElement -> bool
  var isTR = function(el) {
    return el && el.nodeName === 'TR';
  };

  // ### isTD
  // > TD 여부 판단
  // * `el` HTMLElement -> bool
  var isTD = function(el) {
    return el && el.nodeName === 'TD';
  };

  // ### isCell
  // > 테이블셀 여부 판단
  // * `el` HTMLElement -> bool
  var isCell = function(el) {
    return el && (el.nodeName === 'TD' || el.nodeName === 'TH');
  };

  // ### isContainer
  // > 컨테이너 객체 여부 판단: 다른 객체(UL, DIV 등)을 담을 수 있는 객체
  var isContainer = function(el) {
    return !isData(el);
  };

  // ### isFirstContainerChild
  // > 부모의 첫번째 컨테이너 객체인지 여부 판단
  var isFirstContainerChild = function(el) {
    var aChild = _.filter(_.map(el.parentNode.childNodes), isContainer);
    return aChild.length > 0 && _.first(aChild) === el;
  };

  // ### isLastContainerChild
  // > 부모의 마지막 컨테이너 객체인지 여부 판단
  var isLastContainerChild = function(el) {
    var aChild = _.filter(_.map(el.parentNode.childNodes), isContainer);
    return aChild.length > 0 && _.last(aChild) === el;
  };

  // ###isDataBlock
  // > hr이나 float된 image등 커서가 위치할 수 있는 객체
  var isDataBlock = function(el) {
    return isHR(el) || isIMG(el) || isBR(el);
  };

  // ###isDocumentFragment
  var isDocumentFragment = function(el) {
    return el && el.nodeName === "#document-fragment";
  };

  // ### isInlineContainer
  // > 인라인을 가질 수 있는 노드 여부 판단
  var isInlineContainer = function(el) {
    return isPara(el) || isBodyContainer(el) || isDocumentFragment(el) || isNoteEditable(el);
  };

  // ### isIMG
  // > 이미지 노드 여부 판단
  var isIMG = function(el) {
    return el && el.nodeName === "IMG";
  };

  // ### isData
  // > 인라인 노드 여부 판단
  var isData = function(el) {
    return el && (el.nodeName === "#text" ||
                  el.nodeName === "IMG" ||
                  el.nodeName === "HR" ||
                  el.nodeName === "INPUT" ||
                  el.nodeName === "BR") ;
  };

  // ### isText
  // > 텍스트 노드 여부 판단
  var isText = function(el) {
    return el && (el.nodeName === "#text");
  };

  var isFont = function(el) {
    return el && (el.nodeName === "FONT");
  };

  var isStrike = function(el) {
    return el && (el.nodeName === "STRIKE" || el.nodeName === "S" || el.nodeName === "DEL");
  };

  var isBold = function(el) {
    return el && (el.nodeName === "BOLD" || el.nodeName === "B" || el.nodeName === "STRONG");
  };

  var isItalic = function(el) {
    return el && (el.nodeName === "ITALIC" || el.nodeName === "I");
  };

  var isUnderline = function(el) {
    return el && (el.nodeName === "UNDERLINE" || el.nodeName === "U");
  };

  var isDiv = function(el) {
    return el && el.nodeName === "DIV";
  };

  var isBlockquote = function(el) {
    return el && el.nodeName === "BLOCKQUOTE";
  };

  var isNoteEditor = function(el){
    return el && $(el).hasClass('note-editor');
  };

  var isNoteEditable = function(el){
    return el && $(el).hasClass('note-editable');
  };

  var isFirstParaTextnode = function(el) {
    var elPara = ancestor(el, function(el){ return isPara(el) || isCell(el); });
    if (!elPara) { return false; }

    var aAncestor =  _.reject(listAncestor(elPara), isCell);
    return _.all(aAncestor, isFirstContainerChild);
  };

  var isLastParaTextnode = function(el) {
    var elPara = ancestor(el, function(el){ return isPara(el) || isCell(el); });
    if (!elPara) { return false; }

    var aAncestor = _.reject(listAncestor(elPara), isCell);
    return _.all(aAncestor, isLastContainerChild);
  };

  var isBodyContainer = function(el) {
    return isNoteEditable(el) || isCell(el) || isTR(el) || isTD(el) || isBlockquote(el) || isTHead(el) || isTBody(el) || isDiv(el);
  };

  // ### isEdgeOf
  // > 입력 받은 위치의 구석(왼쪽 혹은 오른쪽 위치) 여부 리턴
  var isEdgeOf = function(el, offset) {
    if (isEmpty(el)) { return true; }
    return offset === 0 || length(el) === offset;
  };

  // ### isLeftEdge
  // > 입력 받은 위치의 왼쪽구석 여부 리턴
  var isLeftEdge = function(el, offset) {
    return offset === 0;
  };

  // ### isRightEdge
  // > 입력 받은 위치의 오른쪽구석 여부 리턴
  var isRightEdge = function(el, offset) {
    return offset === length(el);
  };

  // ### isLeftEdgeOf
  // > 입력 받은 위치의 root로 부터의 왼쪽구석 여부 리턴
  var isLeftEdgeOf = function(elRoot, el) {
    while (el && el !== elRoot) {
      if (position(el) !== 0) { return false; }
      el = el.parentNode;
    }

    assert.ok(el !== null); // el이 root에 포함되지 않는 경우...
    return true;
  };

  // ### isRightEdgeOf
  // > 입력 받은 위치의 root로 부터의 오른쪽구석 여부 리턴
  var isRightEdgeOf = function(elRoot, el) {
    while (el && el !== elRoot) {
      if (position(el) !== length(el.parentNode)-1) { return false; }
      el = el.parentNode;
    }

    assert.ok(el !== null); // el이 root에 포함되지 않는 경우...
    return true;
  };

  // ### isEmpty
  // > 노드가 비어 있는 노드인지 판단
  var isEmpty = function(el) {
    if (isData(el)) {
      return false;
    }

    return el.childNodes.length === 0;
  };

  // ### isSiblingOf
  // > elSrc 가 elTarget에 형재 노드인지 검사
  var isSiblingOf = function(elSrc, elTarget) {
    var aChild = elSrc.parentNode.childNodes;
    for (var i=0, len=aChild.length; i < len; i++) {
      if (aChild[i] === elTarget) {
        return true;
      }
    }
    return false;
  };

  // ### contains
  // > elSrc가 elParent에 자식 여부인지 판단
  var contains = function(elSrc, elParent) {
    return !!ancestor(elSrc, function(el) {
      return el === elParent;
    });
  };

  // ### isAdjacent
  // > 인접노드 여부 리턴
  var isAdjacent = function(elA, elB) {
    return elA.nextSibling === elB || elB.nextSibling === elA;
  };

  // ### isNBSP
  // > non breakable space 판단
  var isNBSP = function(el) {
    return isText(el) && NBSP === el.nodeValue;
  };

  // ### isFEFF
  // > no width non breakable space 판단
  var isFEFF = function(el) {
    return isText(el) && FEFF === el.nodeValue;
  };

  // ### isHeading
  // > 머리글여부 리턴
  // * `el` HTMLElement -> bool
  var isHeading = function(el) {
    return el && /^H[1-7]/.test(el.nodeName);
  };

  // ### isPara
  // > 문단 여부 판단
  // * `el` HTMLElement -> bool
  var isPara = function(el) {
    return el && (/^P|^LI/.test(el.nodeName) || /^H[1-7]/.test(el.nodeName));
  };

  // ### isPurePara
  // > 리스트가 아닌 순수한 문단
  var isPurePara = function(el) {
    return isPara(el) && !isLI(el);
  };

  // ### isList
  // > 리스트 여부 판단
  // * `el` HTMLElement -> bool
  var isList = function(el) {
    return el && (el.nodeName === 'UL' || el.nodeName === 'OL');
  };

  // ### isOrderedList
  // > 순서가 있는 리스트 여부 판단
  // * `el` HTMLElement -> bool
  var isOrderedList = function(el) {
    return el && el.nodeName === 'OL';
  };

  // ### isUnorderedList
  // > 순서가 없는 리스트 여부 판단
  // * `el` HTMLElement -> bool
  var isUnorderedList = function(el) {
    return el && el.nodeName === 'UL';
  };

  // ### isBullet
  // > ul/ol여부 판단
  var isBullet = function(el) {
    return isOrderedList(el) || isUnorderedList(el);
  };

  // ### isLI
  // > LI 여부 리턴
  var isLI = function(el) {
    return el && el.nodeName === 'LI';
  };

  // ### isP
  // > P 여부 리턴
  var isP = function(el) {
    return el && el.nodeName === 'P';
  };

  // ### isA
  // > A 여부 리턴
  var isA = function(el) {
    return el && el.nodeName === 'A';
  };

  // ### isHR
  // > HorizontalRule 여부 판단
  // * `el` HTMLElement -> bool
  var isHR = function(el) {
    return el && el.nodeName === 'HR';
  };

  // ### isBR
  // * `el` HTMLElement -> bool
  var isBR = function(el) {
    return el && el.nodeName === 'BR';
  };

  // ### isEmptyText
  // > 빈 텍스트 엘리먼트 여부 리턴
  var isEmptyText = function(el) {
    return isText(el) && (el.nodeValue === '');
  };

  // ### isEmptyPara
  // > 빈 문단 여부 리턴
  var isEmptyPara = function(el) {
    if (!isPara(el)) { return false; }

    var aElInline = descendants(el, isData);
    return aElInline.length === 0 ||
           (aElInline.length === 1 && isNBSP(aElInline[0])) ||
           (aElInline.length === 1 && isFEFF(aElInline[0]));
  };

  // ### isEmptyInlineContainer
  // > 빈 컨테이너 여부 리턴
  var isEmptyInlineContainer = function(el) {
    if (isEmptyPara(el)) { return true; }
    if (!isInlineContainer(el)) { return false; }

    var aElInline = descendants(el, isData);

    return aElInline.length === 0 ||
           (aElInline.length === 1 && isNBSP(aElInline[0])) ||
           (aElInline.length === 1 && isFEFF(aElInline[0]));
  };

  // ### isP
  // > SPAN 여부 리턴
  var isSpan = function(el) {
    return el && el.nodeName === 'SPAN';
  };

  // ### isInvisible
  // > 보이지 않는 노드 여부 판단
  var isInvisible = function(el) {
    var aElInline = descendants(el, isData);
    return aElInline.length === 0;
  };

  // ### isOnContentEditable
  // > 편집영역 위에 있는 노드 여부 판단
  var isOnContentEditable = function(el) {
    while (el) {
      if (isNoteEditable(el)) { return true; }
      el = el.parentNode;
    }
    return false;
  };

  /* ------------------------------------------------------------------------------- */
  // dom modifier

  // ### slice
  // > dom 트레버싱
  // > `fApply` 각 노드에 적용할 함수
  // > `fPred` 노드 탐색을 어느 시점에 멈출지 판단 | optional
  var _traverse = function(el, fBefore, fAfter, fStop, bRtoL) {
    try {
      var trav = function(el) {
        if (fStop && fStop(el)) { throw "break"; }
        if (fBefore) { fBefore(el); }
        var aChild = bRtoL ? _.toArray(el.childNodes).reverse() : _.toArray(el.childNodes);
        for (var i=0, len=aChild.length; i < len; i++ ) { trav(aChild[i]); }
        if (fAfter) { fAfter(el); }
      };
      trav(el);
    } catch(e) {
      if (e !== "break") { throw e; }
    }
  };

  // ### traverse
  // 좌측 구석 -> 상향 탐색
  var traverse = function(el, fApply, fStop) {
    _traverse(el, null, fApply, fStop);
  };

  // ### traverseInt
  // 좌측 구석으로 하향탐색
  var traverseIn = function(el, fApply, fStop) {
    _traverse(el, fApply, null, fStop);
  };

  // ### traverseRight
  // 우측 구석 -> 상향탐색
  var traverseRight = function(el, fApply, fPred) {
    _traverse(el, null, fApply, fPred, true);
  };

  // ### traverseRightIn
  // 우측 구석으로 하향 탐색
  var traverseRightIn = function(el, fApply, fPred) {
    _traverse(el, fApply, null, fPred, true);
  };

  // ### descendants
  // > el 밑에 자식 노드 중에 fPred를 만족하는 모든 노드를 반환
  var descendants = function(el, fPred) {
    fPred = fPred || iter.success;

    var aElDescendant = [];
    traverse(el, function(elDescendant) {
      if (fPred(elDescendant)) {
        aElDescendant.push(elDescendant);
      }
    });

    return aElDescendant;
  };

  // ### hasDescendants
  // > 자식 노드중 pred를 만족하는지 여부 판단
  var hasDescendants = function(el, pred) {
    return descendants(el, pred).length > 0;
  };

  // ### hasParent
  // > 부모 노드가 있는지 여부 판단
  var hasParent = function(el) {
    return el.parentNode;
  };

  // ### hasNext
  // > 다음 형제 노드가 있는지 검사
  var hasNext = function(el) {
    return el && el.nextSibling;
  };

  // ### hasPrev
  // > 이전 형제 노드가 있는지 검사
  var hasPrev = function(el) {
    return el && el.previousSibling;
  };

  // ### hasChild
  // > 자식 노드 존재하는지 여부 검사
  var hasChild = function(el) {
    return el && el.childNodes && el.childNodes.length > 0;
  };

  // ### ancestor
  // > pred에 일치하는 가장 가까운 부모 노드 찾기
  // > 자신을 포함해서 찾는다.
  // TODO: note-editable을 사용하지 않는 버전 필요
  var ancestor = function(el, pred) {
    var elCurrent = el;
    while (elCurrent) {
      if (!elCurrent || elCurrent.className === 'note-editable') { break; }
      if (pred(elCurrent)) { return elCurrent; }
      elCurrent = elCurrent.parentNode;
    }
    return null;
  };

  // ### lastAncestor
  // > pred에 일치하는 최상위 부모노드 찾기
  var lastAncestor = function(el, pred) {
    var aAncestor = listAncestor(el);
    return _.last(_.filter(aAncestor, pred));
  };

  // ### listAncestor
  // > ancestor 목록 리턴(가까운 Ancestor부터)
  var listAncestor = function(el, pred) {
    pred = pred || iter.fail;

    var aElVisited = [];
    ancestor(el, function(e) {
      aElVisited.push(e);
      return pred(e);
    });

    return aElVisited;
  };


  // ### commonAncestor
  // > commonAncestor 반환
  var commonAncestor = function(node1, node2) {
    var ancestors = [], n;
    for (n = node1; n; n = n.parentNode) {
      ancestors.push(n);
    }

    for (n = node2; n; n = n.parentNode) {
      if (_.contains(ancestors, n)) {
        return n;
      }
    }
    return null;
  };

  var getClosestAncestorIn = function(node, ancestor, selfIsAncestor) {
    var p, n = selfIsAncestor ? node : node.parentNode;
    while (n) {
      p = n.parentNode;
      if (p === ancestor) {
        return n;
      }
      n = p;
    }
    return null;
  };

  var comparePoints = function(nodeA, offsetA, nodeB, offsetB) {
    // See http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Comparing
    var nodeC, root, childA, childB, n;
    if (nodeA == nodeB) {
      // Case 1: nodes are the same
      return offsetA === offsetB ? 0 : (offsetA < offsetB) ? -1 : 1;
    } else if ( (nodeC = getClosestAncestorIn(nodeB, nodeA, true)) ) {
      // Case 2: node C (container B or an ancestor) is a child node of A
      return offsetA <= position(nodeC) ? -1 : 1;
    } else if ( (nodeC = getClosestAncestorIn(nodeA, nodeB, true)) ) {
      // Case 3: node C (container A or an ancestor) is a child node of B
      return position(nodeC) < offsetB  ? -1 : 1;
    } else {
      // Case 4: containers are siblings or descendants of siblings
      root = commonAncestor(nodeA, nodeB);
      childA = (nodeA === root) ? root : getClosestAncestorIn(nodeA, root, true);
      childB = (nodeB === root) ? root : getClosestAncestorIn(nodeB, root, true);

      if (childA === childB) {
        // This shouldn't be possible
        throw "comparePoints got to case 4 and childA and childB are the same!";
      } else {
        n = root.firstChild;
        while (n) {
          if (n === childA) {
            return -1;
          } else if (n === childB) {
            return 1;
          }
          n = n.nextSibling;
        }
      }
    }
  };

  // ### comparePositions
  // > 입력받은 posA, posB을 비교
  // > @return number  0: equal to,
  // >                -1: posA less than posB,
  // >                 1: posA greater than posB
  var comparePositions = function(posA, posB) {
    return comparePoints(posA.cont, posA.offset, posB.cont, posB.offset);
  };

  // ### leftBottom
  // > 가장 왼쪽 노드 찾아가서 반환
  var leftBottom = function(el) {
    return el.firstChild ? leftBottom(el.firstChild) : el;
  };

  // ### inlineTop
  // Block에 가장 가까운 Inline 노드를 반환
  var inlineTop = function(el) {
    return _.last(listAncestor(el, function(e) { return isBlock(e.parentNode); }));
  };

  // ### styleInlineTop
  // Block에 가장 가까운 style 가능한 Inline 노드를 반환
  var styleInlineTop = function(el) {
    return _.last(listAncestor(el, function(e) { return isA(e.parentNode) ||  isBlock(e.parentNode); }));
  };

  // ### closetBody
  // > 가장 가까운 bodyContainer를 반환
  var closetBody = function(el) {
    var elCurrent = el;

    while (elCurrent) {
      if (isBodyContainer(elCurrent)) {
        return elCurrent;
      }
      elCurrent = elCurrent.parentNode;
    }
  };

  // ### length
  // > 입력받은 엘리먼트의 자식노드의 수 반환
  // > 텍스트 노드의 경우 글자 수 반환
  var length = function(el) {
    assert.ok(el);
    if (isData(el)) {
      return isText(el) ? el.nodeValue.length : 1;
    }

    switch (el.nodeType) {
    case 7:
    case 10:
      return 0;
    case 3:
    case 8:
      return el.length;
    default:
      return el.childNodes.length;
    }
  };

  // ### position
  // > 현재 노드 위치를 반환
    var position = function (el) {
    var cnt = 0;
        for (var i=0; el = el.previousSibling; i++) {}
    return i;
    };

  // ### depth
  // > 현재 노드에 depth를 반환
  var depth = function(el, pred) {
    pred = pred || iter.fail;
    return listAncestor(el, pred).length;
  };

  // ### remove
  // > node el을 dom 에서 삭제
  var remove = function(el) {
    removeNode(el, true);
  };

  // ### removeNode
  // > elNode를 dom 상에서 제거 [removeNode](http://help.dottoro.com/ljxjnsic.php)
  // > `bRemoveChild` child node 제거 여부, true인 경우 자식 노드를 모두 제거한다
  var removeNode = function(elNode, bRemoveChild) {
    if (!elNode || !elNode.parentNode) { return; }
    if (elNode.removeNode) { elNode.removeNode(bRemoveChild); return; }

    var elParent = elNode.parentNode;
    if (!bRemoveChild) {
      var aNode = [], i, len;
      for (i=0; i < elNode.childNodes.length; i++) {
        aNode.push(elNode.childNodes[i]);
      }

      for (i=0, len=aNode.length; i el 이 빈 노드인 경우 dom 상에서 제거한다.
  // > 재귀적으로 상위 노드를 계속 탐색한다
  var removeWhile = function(el, pred) {
    assert.ok(el);

    var walk = function(el) {
      var elParent = el.parentNode;
      if (elParent && pred(el)) {
        elParent.removeChild(el);
        walk(elParent, pred);
      }
    };

    var elParent = el.parentNode;
    remove(el);
    walk(elParent);
  };

  // ### removeAllAttributes
  // > element의 모든 속성 제거
  var removeAllAttributes = function(el, excludePred) {
    _.each(_.toArray(el.attributes), function(attr) {
      if (!attr) { return; }
      if (excludePred && excludePred(attr.name)) return;
      el.removeAttribute(attr.name);
    });
  };

  var NBSP = String.fromCharCode(160);
  var FEFF = "\ufeff";
  var BASE_PARA_HTML = '

'+FEFF+'

'; // appends: append children var appends = function(node, aChild) { _.each(aChild, function(child) { node.appendChild(child); }); }; // ### split // > `elRoot` : 잘라낼 트리 루트 // > `elPivot` : 잘라낼 기준 노드 // > `offset` : 텍스트 노드인 경우 잘라낼 offset var splitTree = function(root, pivot, offset) { assert.ok(root); assert.ok(pivot); // split pivot var splitPivot = function(current, offset) { if (offset >= length(current)) { return current.nextSibling; } if (offset === 0) { return current; } // splitText if (isText(current)) { return current.splitText(offset); } // splitNode var child = current.childNodes[offset]; current = insertAfter(current.cloneNode(false), current); appends(current, listNext(child, iter.fail)); return current; }; var aAncestor = listAncestor(pivot, iter.eq(root)); if (aAncestor.length === 1) { return splitPivot(pivot, offset); } return _.reduce(_.tail(aAncestor), function(current, parent) { var parentClone = insertAfter(parent.cloneNode(false), parent); if (current === pivot) { current = splitPivot(current, offset); } appends(parentClone, listNext(current, iter.fail)); return parentClone; }, pivot); }; // Note that we cannot use splitText() because it is bugridden in IE 9. var splitDataNode = function(node, index, positionsToPreserve) { var newNode = node.cloneNode(false); newNode.deleteData(0, index); node.deleteData(index, node.length - index); insertAfter(newNode, node); // Preserve positions if (positionsToPreserve) { for (var i = 0, position; position = positionsToPreserve[i++]; ) { // Handle case where position was inside the portion of node after the split point if (position.node == node && position.offset > index) { position.node = newNode; position.offset -= index; } // Handle the case where the position is a node offset within node's parent else if (position.node == node.parentNode && position.offset > position(node)) { ++position.offset; } } } return newNode; }; // ### splitText // > 텍스트 노드를 반환 var splitText = function(el, offset) { if (offset === 0) { return el; } else if (length(el) === offset) { return null; } else { return splitDataNode(el, offset); } }; // ### insertBefore // > elNew를 elTarget 이전에 삽입 var insertBefore = function(elNew, elTarget) { return elTarget.parentNode.insertBefore(elNew, elTarget); }; // ### insertAfter // > elNew를 elTarget 이후에 삽입 var insertAfter = function(node, precedingNode) { var nextNode = precedingNode.nextSibling, parent = precedingNode.parentNode; if (nextNode) { parent.insertBefore(node, nextNode); } else { parent.appendChild(node); } return node; }; // ### replace // > 입력받은 노드의 nodeName을 변경 // > ! 원본은 삭제 var replace = function(el, sNodeName) { assert.ok(el && sNodeName); var elNew = document.createElement(sNodeName); var sStyle = el.style.cssText; if (sStyle) { elNew.style.cssText = sStyle; } if (hasChild(el)) { _.each(_.toArray(el.childNodes), function(elChild) { elNew.appendChild(elChild); }); } insertAfter(elNew, el); removeNode(el); return elNew; }; // ### clone // 노드를 복제 // > !ie8 에서 잘라진 텍스트 노드를 normalize 해버리는 문제가 있다. var clone = function(el) { if (!el) { return; } if (el.childNodes) { // IE8에서 textNode가 병합되는 문제 회피 var elClone = el.cloneNode(false); _.each(el.childNodes, function(elChild){ elClone.appendChild(elChild.cloneNode(true)); }); return elClone; } else { return el.cloneNode(true); } }; // ### parent // > 노드에 부모 노드 반환 var parent = function(el) { var elParent = el.parentNode; if (elParent.className === 'note-editable') { return null; } return elParent; }; // ### next // > 다음 형제 노드 찾기 var next = function(el, pred) { var elNext = el; while (elNext) { if (pred(elNext)) { return elNext; } elNext = elNext.nextSibling; } return null; }; // ### listNext // > 다음 형제 노드를 pred가 만족할 때 까지 acc, 자신을 포함 var listNext = function(el, pred) { var aNode = [], elNext = el; while (elNext) { if (pred(elNext)) { break; } aNode.push(elNext); elNext = elNext.nextSibling; } return aNode; }; // ### listPrev // > 이전 형제 노드를 pred가 만족할 때 까지 acc, 자신을 포함 var listPrev = function(el, pred) { var aNode = [], elPrev = el; while (elPrev) { if (pred(elPrev)) { break; } aNode.push(elPrev); elPrev = elPrev.previousSibling; } return aNode; }; // ### nodesBetween // > start, end 사이에 노드를 모두 가지고 온다 var nodesBetween = function(elStart, elEnd) { if (elStart === elEnd) { return [elStart]; } var elCommon = commonAncestor(elStart, elEnd); var elEndAncestor = ancestor(elEnd, iter.peq('parentNode', elCommon)); var aNode = [], bFlag = false; traverse(elCommon, function(el) { if (el === elStart) { bFlag = true; } if (bFlag) { aNode.push(el); } }, iter.eq(elEndAncestor)); var aEnd = []; traverseIn(elEndAncestor, iter.push(aEnd), iter.eq(elEnd)); aEnd.push(elEnd); return aNode.concat(aEnd); }; // ### nextBP var nextBP = function(bpInit) { var elCont = bpInit.node, offset = bpInit.offset; if (length(elCont) === offset) { if (elCont.className === 'note-editable') { return null; } return {node: elCont.parentNode, offset: position(elCont) + 1}; } else { if (hasChild(elCont)) { var elChild = elCont.childNodes[offset]; return {node: elChild, offset: 0}; } else { return {node: elCont, offset: offset + 1}; } } }; // ### prevBP var prevBP = function(bpInit) { var elCont = bpInit.node, offset = bpInit.offset; if (offset === 0) { if (elCont.className === 'note-editable') { return null; } return {node: elCont.parentNode, offset: position(elCont)}; } else { if (hasChild(elCont)) { var elChild = elCont.childNodes[offset - 1]; return {node: elChild, offset: length(elChild)}; } else { return {node: elCont, offset: offset - 1}; } } }; // ### makeUntil var makeUntil = function(fnUnit) { return function(pred) { var stack = [], item = fnUnit.call(this); while (item) { if (pred(item, stack)) { return item; } stack.push(item); item = fnUnit.call(item); } }; }; // ### makeOffsetPath // > BPPath를 리턴 var makeOffsetPath = function(elRoot, elPivot) { var aOffset = [], el = elPivot; while (el && el !== elRoot) { aOffset.push(position(el)); el = el.parentNode; } assert.ok(el !== null); // el이 root에 포함되지 않는 경우... aOffset.push(position(elRoot)); return aOffset.reverse(); }; // ### fromOffsetPath // > elRoot와 aOffset을 받아 특정 노드를 리턴 var fromOffsetPath = function(elRoot, aOffset) { assert.ok(elRoot && aOffset); aOffset = _.rest(aOffset); var el = elRoot; _.each(aOffset, function(offset) { el = el.childNodes[offset]; }); return el; }; // ### create // > dom 노드 생성 var create = function(sTagName) { assert.ok(sTagName); return document.createElement(sTagName); }; // ### fragment // > html 을 받아서 documentFrgment를 반환 var fragment = function(sHTML) { var frag = document.createDocumentFragment(); if (!sHTML) { return frag; } var elTemp = document.createElement("DIV"); elTemp.innerHTML = sHTML; _.each(_.toArray(elTemp.childNodes), function(el) { frag.appendChild(el); }); return frag; }; // ### element // > shtml을 받아서 element를 반환 // ! shtml은 루트에 요소가 하나여야 한다 // ex) true ==
 
, // ex) false ==

var element = function(sHTML) { var elFrag = fragment(sHTML); assert.ok(elFrag.childNodes.length === 1); return elFrag.firstChild; }; // ### text var text = function(el) { var elDiv = create("div"); elDiv.appendChild(clone(el)); return elDiv.textContent || elDiv.innerText ; }; // ### wrap var wrap = function(sTag, el) { var elWrap = create(sTag); insertBefore(elWrap, el); elWrap.appendChild(el); return elWrap; }; // ### stripTagSpace // > HTML 태그 사이에 공백을 제거한다 var stripTagSpace = function(sText) { // 중복되는 정규식이 있어보임 return sText.replace(/\r?\n?/g, "") // 뉴라인 제거 .replace(/>([ \t]+)<') // 태그 사이 공백 제거 .replace(/[ \t][ \t]+/g, " ") // 2개 이상 공백을 1개로 변경 .replace(/^[ \t]+|[ \t]+$/, ""); // 공백으로 시작하거나 공백으로 끝나는 부분 제거 }; // ### stripFEFF // > 모든 FEFF를 제거 공백을 제거한다 var stripFEFF = function(sText) { // 중복되는 정규식이 있어보임 return sText.replace(/\ufeff/g, ""); // FEFF 제거 }; // ### repairHTML // > HTML 태그 보정 var repairHTML = function(sHTML) { // '>'짝이 맞지 않는 html 보정 sHTML = common.stringFilter.tagCorrector(sHTML); return sHTML; // custom attribute를 처리하지 못해 주석 처리 ex) data-user-style // // '

abc

abc

'와 같이 짝기 맞지 않는 태그 보정 // var results = ""; // HTMLParser(sHTML, { // start: function( tag, attrs, unary ) { // results += "<" + tag; // // for ( var i = 0; i < attrs.length; i++ ) // results += " " + attrs[i].name + '="' + attrs[i].escaped + '"'; // // results += (unary ? "/" : "") + ">"; // }, // end: function( tag ) { // results += ""; // }, // chars: function( text ) { // results += text; // }, // comment: function( text ) { // results += ""; // } // }); // return results; }; // ### cloneTagStruct // > aEl로 받은 태그 구조를 복사해서 생성 // > ex) [P, SPAN, TEXT] ->

TEXT

var cloneStruct = function(aEl) { var removeChild = function(el) { if (el.childNodes) { _.each(_.toArray(el.childNodes), remove); } return el; }; var elTop = removeChild(clone(aEl.shift())); while (aEl.length > 0) { var el = removeChild(clone(aEl.shift())); var elParent = elTop.firstChild ? elTop.firstChild : elTop; elParent.appendChild(el); } return elTop; }; // ### normalize // http://stackoverflow.com/questions/2023255/node-normalize-crashes-in-ie6 var normalize = function(node) { if (node.normalize) { node.normalize(); return; } for (var i=0, children = node.childNodes, nodeCount = children.length; i "1px 1px 1px 1px"형의 값을 split 함 var splitPostionString = function(sPos) { var aPos = sPos.split(' '); var nTop, nRight, nBottom, nLeft; if (aPos.length === 1) { nTop = parseInt(aPos[0]), nRight = nTop, nBottom = nTop, nLeft = nTop; } else if( aPos.length === 2 ) { nTop = parseInt(aPos[0]), nRight = parseInt(aPos[1]), nBottom = nTop, nLeft = nRight; } else if( aPos.length === 3 ) { nTop = parseInt(aPos[0]), nRight = parseInt(aPos[1]), nBottom = parseInt(aPos[2]), nLeft = nRight; } else{ nTop = parseInt(aPos[0]), nRight = parseInt(aPos[1]), nBottom = parseInt(aPos[2]), nLeft = parseInt(aPos[3]); } return {'top':nTop, 'right' : nRight, 'bottom' : nBottom, 'left': nLeft}; }; // ### parseColSpan // > td colSpan 값을 리턴(number) var parseColSpan = function(elTD) { assert.ok(isCell(elTD)); return parseInt(elTD.getAttribute('colSpan'), 10) || 1; }; // ### parseRowSpan // > td rowSpan 값을 리턴(number) var parseRowSpan = function(elTD) { assert.ok(isCell(elTD)); return parseInt(elTD.getAttribute('rowSpan'), 10) || 1; }; // ### isMergeHead var isMergeHead = function(elTD) { return isRowMergeHead(elTD) || isColMergeHead(elTD); }; // ### isRowMergeHead var isRowMergeHead = function(elTD) { if (!isCell(elTD)) { return false; } return parseRowSpan(elTD) > 1; }; // ### isColMergeHead var isColMergeHead = function(elTD) { if (!isCell(elTD)) { return false; } return parseColSpan(elTD) > 1; }; // ### padding para // > element가 비어있는 경우 FEFF 를 하나 넣어준다. // >> UL/OL이 들어오는 경우도 처리 var paddingInlineContainer = function(el) { if (isList(el) && _.all(el.childNodes, isEmpty)) { _.each(el.childNodes, paddingInlineContainer); return leftBottom(_.last(el.childNodes)); } else if (isEmptyInlineContainer(el) ) { var elInline = leftBottom(el); if (isText(elInline)) { elInline.nodeValue = FEFF; return elInline; } else { elInline.innerHTML = FEFF; return elInline.firstChild; } } return null; }; var MIN_PT = 7; // ### px2pt // > 글꼴크기의 px를 pt로 변환 var px2pt = function (px) { return _.max([px - parseInt((px + 1) / 4), MIN_PT]); }; // ### getUnit // > 정규식에 매치되는 값 리턴(없으면 빈 문자열) // > 정규식 : UNIT_REGEXP = /pt$|in$|em$|cm$|px$/ var getUnit = function (sValue) { if (!sValue) { return ""; } sValue = sValue.replace(/^\s+|\s+$/g, ''); var matched = sValue.match(/pt$|in$|em$|cm$|px$/); return matched ? matched[0] : ""; }; return { isBlock: isBlock, isInline: iter.not(isBlock), isTable: isTable, isTBody: isTBody, isTR: isTR, isTD: isTD, isCell: isCell, isContainer: isContainer, isInlineContainer: isInlineContainer, isIMG: isIMG, isData: isData, isText: isText, isEmptyText: isEmptyText, isFont: isFont, isStrike: isStrike, isBold: isBold, isItalic: isItalic, isUnderline: isUnderline, isDiv: isDiv, isBlockquote: isBlockquote, isNoteEditor: isNoteEditor, isNoteEditable: isNoteEditable, isFirstContainerChild : isFirstContainerChild, isLastContainerChild : isLastContainerChild, isFirstParaTextnode: isFirstParaTextnode, isLastParaTextnode: isLastParaTextnode, isBodyContainer: isBodyContainer, isEdgeOf: isEdgeOf, isLeftEdge: isLeftEdge, isRightEdge: isRightEdge, isLeftEdgeOf: isLeftEdgeOf, isRightEdgeOf: isRightEdgeOf, isEmpty: isEmpty, isSiblingOf: isSiblingOf, contains: contains, isAdjacent: isAdjacent, isNBSP: isNBSP, isFEFF: isFEFF, isPara: isPara, isHeading: isHeading, isPurePara: isPurePara, isList: isList, isOrderedList: isOrderedList, isUnorderedList: isUnorderedList, isBullet: isBullet, isLI: isLI, isP: isP, isA: isA, isHR: isHR, isBR: isBR, isEmptyPara: isEmptyPara, isEmptyInlineContainer: isEmptyInlineContainer, isSpan: isSpan, isInvisible: isInvisible, isOnContentEditable: isOnContentEditable, isDocumentFragment: isDocumentFragment, isDataBlock: isDataBlock, traverse: traverse, traverseIn: traverseIn, descendants: descendants, hasDescendants: hasDescendants, hasParent: hasParent, hasNext: hasNext, hasPrev: hasPrev, hasChild: hasChild, ancestor: ancestor, lastAncestor: lastAncestor, listAncestor: listAncestor, comparePositions: comparePositions, commonAncestor: commonAncestor, leftBottom: leftBottom, inlineTop: inlineTop, styleInlineTop: styleInlineTop, closetBody: closetBody, length: length, position: position, depth: depth, remove: remove, removeNode: removeNode, removeWhile: removeWhile, removeAllAttributes : removeAllAttributes, insertAfter: insertAfter, insertBefore: insertBefore, NBSP: NBSP, FEFF: FEFF, BASE_PARA_HTML: BASE_PARA_HTML, splitTree: splitTree, splitText: splitText, replace: replace, clone: clone, parent: parent, next: next, listNext: listNext, listPrev: listPrev, nodesBetween: nodesBetween, nextBP: nextBP, prevBP: prevBP, makeUntil: makeUntil, makeOffsetPath: makeOffsetPath, fromOffsetPath: fromOffsetPath, create: create, fragment: fragment, element: element, text: text, wrap: wrap, stripTagSpace: stripTagSpace, stripFEFF: stripFEFF, repairHTML: repairHTML, cloneStruct: cloneStruct, normalize: normalize, splitPostionString: splitPostionString, parseRowSpan: parseRowSpan, parseColSpan: parseColSpan, isMergeHead: isMergeHead, isRowMergeHead: isRowMergeHead, isColMergeHead: isColMergeHead, paddingInlineContainer: paddingInlineContainer, px2pt: px2pt, getUnit: getUnit }; });
@sjorek
Copy link
Contributor

sjorek commented Oct 9, 2013

I'd bet, this line makes groc fail:

// > @return number  0: equal to

… but I didn't debug it further … not enough time 😏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants