| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- (function() {
- Trex.Tool.Indent.Helper = {
- findBlocksToIndentFromRange: function(range, processor, savedCaret) {
- var startCaret = savedCaret.getCaret(_TRUE);
- var endCaret = savedCaret.getCaret(_FALSE);
- if (processor.isCollapsed()) {
- // getStartNode, getStartOffset 호출하지 않으면 오류가 발생한다.
- range.getStartNode();
- range.getStartOffset();
- var node = this.findBlockToIndent(startCaret, processor);
- var isEmptyParagraph = (node.tagName == "P" && node.firstChild == startCaret && node.lastChild == endCaret);
- if (isEmptyParagraph) {
- processor.stuffNode(node);
- }
- // TODO : block을 create한 경우만 restoreInternal을 해야한다. tab press[P로 감싸여 있지 않은 텍스트에서 tab 누르기] 테스트케이스와 관련있음
- savedCaret.restoreInternal();
- return [ node ];
- } else {
- var iterator = new goog.dom.TextRangeIterator(startCaret, 0, endCaret, 0);
- return this.findBlocksToIndentFromIterator(processor, iterator);
- }
- },
- findBlocksToIndentFromIterator: function(processor, iterator) {
- var self = this;
- var allNodes = self.collectAllNodes(iterator);
- var leafNodes = self.selectLeafNodes(allNodes);
- var validLeafNodes = self.filterUnableToIndent(leafNodes);
- var blocksToIndent = validLeafNodes.map(function(node) {
- return self.findBlockToIndent(node, processor);
- });
- blocksToIndent = blocksToIndent.compact().uniq();
- return blocksToIndent;
- },
- collectAllNodes: function (iterator) {
- var allNodes = [];
- goog.iter.forEach(iterator, function(node) {
- if (!allNodes.contains(node)) {
- allNodes.push(node);
- }
- });
- return allNodes;
- },
- selectLeafNodes: function (nodes) {
- var leafNodes = [];
- nodes.each(function(node) {
- if (node.childNodes.length == 0) {
- leafNodes.push(node);
- }
- });
- return leafNodes;
- },
- filterUnableToIndent: function (nodes) {
- var result = [];
- nodes.each(function(node) {
- // indent를 하지 못하는 TextNode를 걸러낸다.
- if ($tom.kindOf(node, "ul,ol,dl")) {
- $tom.removeListIfEmpty(node);
- } else if ($tom.kindOf(node.parentNode, "table") && $tom.isText(node)) {
- } else if ($tom.kindOf(node.parentNode, "thead,tbody,tfooter") && !$tom.kindOf(node, "tr")) {
- } else if ($tom.kindOf(node.parentNode, "tr") && !$tom.kindOf(node, "th,td")) {
- } else if ($tom.kindOf(node.parentNode, "ul,ol,dl") && !$tom.kindOf(node, "li,dd,dt")) {
- } else {
- result.push(node);
- }
- });
- return result;
- },
- findBlockToIndent: function(node) {
- var block = this.findOrCreateBlockForNode(node);
- return this.findIndentableHigherBlock(block);
- },
- findOrCreateBlockForNode: function(node) {
- if ($tom.isText(node) || $tom.kindOf(node, "%inline,img")) {
- var blockAncestor = $tom.ancestor(node, "p,li,dd,dt,h1,h2,h3,h4,h5,h6,div");
- if (blockAncestor && $tom.children(blockAncestor, "%block").length == 0) {
- return blockAncestor;
- } else {
- blockAncestor = $tom.ancestor(node, "%paragraph,pre,noscript,form,hr,address,fieldset,blockquote");
- return $tom.wrapInlinesWithP(node, blockAncestor);
- }
- } else {
- return node;
- }
- },
- findIndentableHigherBlock: function(block) {
- var foundNode = _NULL;
- var visitNode = block;
- while (visitNode && visitNode.tagName != "BODY") {
- if (!foundNode && $tom.kindOf(visitNode, "p,div,h1,h2,h3,h4,h5,h6")) {
- foundNode = visitNode;
- } else if ($tom.kindOf(visitNode, "li,dd,dt")) {
- return visitNode;
- } else if (foundNode && $tom.kindOf(visitNode, "td,th")) {
- return foundNode;
- }
- visitNode = visitNode.parentNode;
- }
- return foundNode;
- },
- findAncestorTableCell: function(node) {
- return $tom.ancestor(node, "td,th");
- },
- findNextCell: function(node) {
- var currentCell = this.findCurrentCell(node);
- var nextCell = $tom.next(currentCell, "td,th");
- if (!nextCell) {
- var nextRow = $tom.next($tom.parent(currentCell), "tr");
- if (nextRow) {
- nextCell = $tom.first(nextRow, "td,th");
- }
- }
- return nextCell;
- },
- findPreviousCell: function(node) {
- var currentCell = this.findCurrentCell(node);
- var prevCell = $tom.previous(currentCell, "td,th");
- if (!prevCell) {
- var prevRow = $tom.previous($tom.parent(currentCell), "tr");
- if (prevRow) {
- prevCell = $tom.last(prevRow, "td,th");
- }
- }
- return prevCell;
- },
- findCurrentCell: function(node) {
- return $tom.kindOf(node, "td,th") ? node : this.findAncestorTableCell(node);
- },
- isCaretOnStartOf: function(node, range) {
- var startNode = range.getStartNode();
- var startOffset = range.getStartOffset();
- while ($tom.isElement(startNode) && startNode.childNodes.length > 0) {
- startNode = startNode.childNodes[startOffset];
- startOffset = 0;
- }
- if (!startNode) {
- return _TRUE;
- }
- var iterator = new goog.dom.TextRangeIterator(node, 0, startNode, startOffset);
- var hasContent = _FALSE;
- goog.iter.forEach(iterator, function(visiting) {
- if (visiting.nodeType == 3 && !$tom.kindOf(visiting.parentNode, "script,style")) {
- var text = (visiting === startNode) ? visiting.nodeValue.substring(0, startOffset) : visiting.nodeValue;
- text = text.replace(Trex.__WORD_JOINER_REGEXP, "");
- hasContent = $tom.removeMeaninglessSpace(text).length > 0;
- } else if ($tom.isElement(visiting)) {
- if ($tom.kindOf(visiting, "img,embed,iframe")) {
- hasContent = _TRUE;
- }
- }
- if (hasContent) {
- throw goog.iter.StopIteration;
- }
- });
- return !hasContent;
- }
- };
- var indentHelper = Trex.Tool.Indent.Helper;
- var $caret_moved = {};
- // range 사용해서 indent할 block을 찾아서 chain handler 작업 지시한다.
- Trex.Tool.Indent.RangeIndenter = Trex.Class.create({
- initialize: function(handler) {
- this.handler = handler;
- },
- indent: function(processor) {
- var self = this;
- processor.executeUsingCaret(function(range, savedCaret) {
- var blockNodes = indentHelper.findBlocksToIndentFromRange(range, processor, savedCaret);
- blockNodes.each(function(node) {
- try {
- self.handler.handle(node, processor, range);
- } catch (e) {
- if (e == $caret_moved) {
- savedCaret.dispose();
- } else {
- throw e;
- }
- }
- });
- });
- }
- });
- Trex.Tool.Indent.TableCellIndenter = Trex.Class.create({
- initialize: function(handler) {
- this.handler = handler;
- },
- indent: function(processor) {
- var self = this;
- var tableCells = (processor.table) ? processor.table.getTdArr() : [];
- tableCells.each(function(cell) {
- var iterator = new goog.dom.TagIterator(cell);
- var blockNodes = indentHelper.findBlocksToIndentFromIterator(processor, iterator);
- blockNodes.each(function(node) {
- self.handler.handle(node, processor, _NULL);
- });
- });
- }
- });
- Trex.Tool.Indent.Judge = {
- ChildOfFirstTableCell: function(node) {
- var tableCell = indentHelper.findAncestorTableCell(node);
- return tableCell && !indentHelper.findPreviousCell(tableCell);
- },
- ChildOfLastTableCell: function(node) {
- var tableCell = indentHelper.findAncestorTableCell(node);
- return tableCell && !indentHelper.findNextCell(tableCell);
- },
- ChildOfTableCell: function(node) {
- return indentHelper.findAncestorTableCell(node);
- },
- ListItem: function(node) {
- return $tom.kindOf(node, "li") && $tom.kindOf(node.parentNode, "ol,ul");
- },
- OneDepthList: function(node) {
- if ($tom.kindOf(node, "li")) {
- // TODO: depth계산을 할 것이냐 부모/조상만 확인하여 return 할 것이냐 고민..
- var listBuilder = new Trex.Tool.StyledList.ListBuilder();
- if (listBuilder.countDepthOfList(node) == 1) {
- return _TRUE;
- }
- }
- return _FALSE;
- },
- IndentedBlockNode: function(node) {
- return $tom.kindOf(node, "%block") && node.style && node.style.marginLeft != "";
- },
- BlockNode: function(node) {
- // TODO %block vs %paragraph
- return $tom.kindOf(node, "%block");
- },
- HeadOfParagraph: function(node, processor, range) {
- return indentHelper.isCaretOnStartOf(node, range);
- },
- And: function(judge1, judge2){
- return function() {
- return judge1.apply(this, arguments) && judge2.apply(this, arguments);
- }
- },
- AlwaysTrue: function() {
- return _TRUE;
- }
- };
- Trex.Tool.Indent.Operation = {
- /* indent */
- GoToBelowTable: function(node, processor) {
- var table = $tom.ancestor(node, 'table');
- processor.bookmarkToNext(table);
- throw $caret_moved;
- },
- GoToNextCell: function(node, processor) {
- var nextCell = indentHelper.findNextCell(node);
- if (nextCell) {
- processor.selectFirstText(nextCell);
- throw $caret_moved;
- }
- },
- IndentListItem: function(node) {
- var groupNode = $tom.ancestor(node, 'ul,ol,dl');
- if (groupNode) {
- var prevSibling = $tom.previous(node);
- var nextSibling = $tom.next(node);
- if ($tom.kindOf(prevSibling, "ul,ol,dl")) {
- // move to previous Group
- $tom.append(prevSibling, node);
- } else {
- var newGroupNode = $tom.clone(groupNode);
- $tom.applyStyles(newGroupNode, { marginLeft: _NULL, paddingLeft: _NULL });
- $tom.wrap(newGroupNode, node);
- }
- // move next Siblings to same parent
- if ($tom.kindOf(nextSibling, "ul,ol,dl")) {
- $tom.moveChild(nextSibling, node.parentNode);
- $tom.remove(nextSibling);
- }
- }
- },
- getChildrenAsElement: function(node) {
- var blocks = [];
- var childNodes = node.childNodes;
- for (var i = 0, len = childNodes.length; i < len; i++) {
- var child = childNodes[i];
- if ($tom.isText(child)) {
- var wrappedChild = $tom.wrapInlinesWithP(child, node);
- blocks.push(wrappedChild);
- } else if ($tom.isElement(child)) {
- blocks.push(child);
- }
- }
- return blocks;
- },
- IndentBlockNode: function(node) {
- $tom.applyStyles(node, {marginLeft: "+2em"});
- },
- // AddFourSpaces: function(node, processor) {
- // processor.pasteContent(" ", _FALSE);
- // },
- /* outdent */
- GoToAboveTable: function(node, processor) {
- var table = $tom.ancestor(node, 'table');
- processor.bookmarkToPrevious(table);
- throw $caret_moved;
- },
- GoToPreviousCell: function(node, processor) {
- var previousCell = indentHelper.findPreviousCell(node);
- if (previousCell) {
- processor.moveCaretTo(previousCell, _TRUE);
- throw $caret_moved;
- }
- },
- OutdentListItem: function(node, processor) {
- var list = $tom.ancestor(node, 'ul,ol,dl');
- if (!list) {
- return;
- }
- var parentNode = list.parentNode;
- if ($tom.kindOf(parentNode, "li")) {
- $tom.unwrap(parentNode);
- parentNode = list.parentNode;
- }
- var grandParentList = $tom.kindOf(parentNode, 'ul,ol,dl') ? parentNode : _NULL;
- var newList;
- if (grandParentList) {
- newList = $tom.divideNode(list, $tom.indexOf(node));
- $tom.insertAt(node, newList);
- } else {
- newList = $tom.divideNode(list, $tom.indexOf(node));
- var cssText = $tom.getStyleText(node);
- // list의 스타일을 p에도 적용한다.
- var p = processor.newNode('p');
- $tom.setStyleText(p, cssText);
- $tom.replace(node, p);
- $tom.insertAt(p, newList);
- }
- $tom.removeListIfEmpty(list);
- $tom.removeListIfEmpty(newList);
- },
- OutdentBlockNode: function(node) {
- $tom.applyStyles(node, {marginLeft: "-2em"});
- },
- Propagate: function() {
- throw $propagate;
- }
- };
- })();
|