(function() {
var BlockRangeIterator = Trex.Class.create({
initialize: function(processor, patterns, start, end) {
this.processor = processor;
this.start = start;
this.end = end || this.start;
this.current = this.start;
this.wTranslator = $tom.translate(patterns).extract('%wrapper');
this.pTranslator = $tom.translate(patterns).extract('%paragraph');
},
hasNext: function() {
return !!this.current;
},
next: function() {
var _current = this.current;
_current = this.find(_current);
var _next = _current;
if ($tom.include(_current, this.end)) {
_next = _NULL;
} else {
while(_next && !$tom.next(_next)) {
_next = $tom.parent(_next);
if($tom.isBody(_next)) {
_next = _NULL;
}
}
if(_next) {
_next = $tom.next(_next);
}
}
if (_next == this.end) {
_next = _NULL;
}
this.current = _next;
return _current;
},
find: function(node) {
var _bNode;
var _node = node;
if(!$tom.hasContent(_node)) {
return _node;
}
while(_node) {
_bNode = _node;
if($tom.isBody(_node)) {
break;
}
if($tom.kindOf(_node, this.wTranslator.getExpression())) {
return _node;
}
if($tom.kindOf(_node, '%wrapper,%outergroup')) {
_node = $tom.descendant(_bNode, this.pTranslator.getExpression());
if(_node) {
return _node;
}
_node = $tom.descendant(_bNode, '%paragraph');
if(_node) {
_bNode = _node;
break;
}
}
if($tom.kindOf(_node, this.pTranslator.getExpression())) {
return _node;
}
if(_node.nextSibling && _node.nodeType == 3) {
// BlockIterator 이니까 TextNode 는 찾는 대상이 아님.
_node = _node.nextSibling;
} else {
_node = _node.parentNode;
}
}
var _innerName = $tom.paragraphOf($tom.getName(_bNode));
var _wNode = this.processor.newNode(_innerName);
var _pNodes = $tom.extract(_bNode, node, '%text,%inline,img,object,embed,hr');
$tom.wrap(_wNode, _pNodes);
this.processor.stuffNode(_wNode);
return _wNode;
}
});
Object.extend(Trex.I.Processor.Standard, /** @lends Trex.Canvas.Processor.prototype */{
/**
* @private
* 선택한 영역안에 있는 노드 중에 패턴을 만족하는 블럭 노드들을 리턴한다.
* @param {String} pattern - 수집할 노드 패턴 조건
* @param {Element} start - 시작하는 노드(#tx_start_marker)
* @param {Element} end - 끝나는 노드(#tx_end_marker)
* @returns {Array} - 선택한 영역안에 있는 노드 중에 패턴을 만족하는 노드들
* @example
* processor.getBlockRangeIterator('div,p,li', node, node);
*/
getBlockRangeIterator: function(pattern, start, end) {
return new BlockRangeIterator(this, pattern, start, end);
}
});
})();
(function() {
var InlineRangeIterator = Trex.Class.create({
initialize: function(processor, patterns, start, end) {
this.processor = processor;
this.start = start;
this.end = end || this.start;
this.current = this.start;
this.iTranslator = $tom.translate(patterns).extract('%inline');
},
hasNext: function() {
return !!this.current;
},
next: function() {
var _current = this.current;
_current = this.find(_current);
var _next = _current;
if (_current == this.end) {
_next = _NULL;
} else {
while(_next && !$tom.next(_next)) {
_next = $tom.parent(_next);
if($tom.isBody(_next)) {
_next = _NULL;
}
}
if(_next) {
_next = $tom.next(_next);
}
}
if ($tom.include(_next, this.end)) {
_next = $tom.top(_next, _TRUE);
}
this.current = _next;
return _current;
},
find: function(node) {
var _node = node;
if($tom.kindOf(_node, '%paragraph,%outergroup,%block') || $tom.isBody(_node)) {
var _bNode = _node;
_node = $tom.top(_bNode, _TRUE);
if(!_node) {
var _innerName = $tom.inlineOf();
var _iNode = this.processor.create(_innerName);
$tom.append(_bNode, _iNode);
return _iNode;
}
}
if($tom.kindOf(_node, 'br')) {
return _node;
} else if(!$tom.hasContent(_node)) {
return _node;
}
if($tom.kindOf(_node, this.iTranslator.getExpression())) {
return _node;
}
var _innerName = $tom.inlineOf();
var _iNode = this.processor.create(_innerName);
$tom.insertAt(_iNode, _node);
if(_node) {
$tom.append(_iNode, _node);
}
return _iNode;
}
});
Object.extend(Trex.I.Processor.Standard, /** @lends Trex.Canvas.Processor.prototype */{
/**
* @private
* 선택한 영역안에 있는 노드 중에 패턴을 만족하는 인라인 노드들을 리턴한다.
* @param {String} pattern - 수집할 노드 패턴 조건
* @param {Element} start - 시작하는 노드(#tx_start_marker)
* @param {Element} end - 끝나는 노드(#tx_end_marker)
* @returns {Array} - 선택한 영역안에 있는 노드 중에 패턴을 만족하는 노드들
* @example
* processor.getInlineRangeIterator('span,font,a', node, node);
*/
getInlineRangeIterator: function(pattern, start, end) {
return new InlineRangeIterator(this, pattern, start, end);
}
});
})();
(function() {
var __CACHING_DOC = _NULL;
var __CACHING_NODE = {};
var __CACHING_PARAGRAPH = {};
Object.extend(Trex.I.Processor.Standard, /** @lends Trex.Canvas.Processor.prototype */{
/**
* 노드를 생성하여 리턴한다. 캐싱을 사용하여 이미 생성했던 노드는 복사한다.
* @private
* @param {String} name - 노드명
* @example
* processor.newNode('div');
*/
newNode: function(name) {
if(__CACHING_DOC != this.doc) {
__CACHING_NODE = {};
__CACHING_DOC = this.doc;
}
if(!__CACHING_NODE[name]) {
__CACHING_NODE[name] = this.win[name]();
}
return $tom.clone(__CACHING_NODE[name], _FALSE);
},
/**
* 텍스트 노드를 생성한다.
* @private
* @param {String} text - 텍스트내용
*/
newText: function(text) {
return this.doc.createTextNode(text);
},
/**
* 노드를 생성하여 리턴한다. 캐싱을 사용하여 이미 생성했던 노드는 복사한다.
* @private
* @param {String} name - 노드명
* @example
* processor.newParagraph('p');
*/
newParagraph: function(name) {
if(__CACHING_DOC != this.doc) {
__CACHING_PARAGRAPH = {};
__CACHING_DOC = this.doc;
}
if(!__CACHING_PARAGRAPH[name]) {
__CACHING_PARAGRAPH[name] = this.stuffNode(this.newNode(name));
}
return $tom.clone(__CACHING_PARAGRAPH[name], _TRUE);
}
});
})();
(function() {
var __CACHING_DOC = _NULL;
var __CACHING_NODE = _NULL;
var __HAS_DUMMY = _FALSE;
var __TEXT_GC_LIST = [];
Object.extend(Trex.I.Processor.Standard, /** @lends Trex.Canvas.Processor.prototype */{
/**
* 빈 텍스트 노드를 생성한다.
* @private
* @param {Boolean} keep - 계속 유지할 것인지 여부 optional
*/
newDummy: function(keep) {
if(__CACHING_DOC != this.doc) {
__CACHING_NODE = _NULL;
__TEXT_GC_LIST = [];
__CACHING_DOC = this.doc;
}
if(!__CACHING_NODE) {
__CACHING_NODE = this.doc.createTextNode(Trex.__WORD_JOINER);
}
var _dummy = $tom.clone(__CACHING_NODE);
if(!keep) {
__TEXT_GC_LIST.push(_dummy);
__HAS_DUMMY = _TRUE;
}
// try {
// throw new Error();
// } catch (e) {
// console.log((++newDummyCalled) + "\n" + e.stack);
// }
return _dummy;
},
/**
* 생성된 빈 텍스트 노드들을 삭제한다.
* @private
*/
/* TODO
* Bug : __TEXT_GC_LIST에 저장된 dummy를 splitText를 하면, reference가 사라지는 효과가 발생한다.
* dummy를 넣기 위한 splitText 부분을 수정할 필요가 있다.
* startConatiner를 지우면 (현재까지 확인된 바에 따르면) Chrome에서는 커서가 사라지고 더 이상 range를 가져오지 못하게 된다.
*/
clearDummy: function() {
if (!__HAS_DUMMY) {
return;
}
var range, startNode;
try {
range = this.createGoogRange();
startNode = range && range.getStartNode();
} catch (ignore4ie678) {}
var remained = _NULL;
// console.log(__TEXT_GC_LIST.length);
for (var i = 0, len = __TEXT_GC_LIST.length-1; i < len; i++) {
try {
var _dummy = __TEXT_GC_LIST.shift();
// console.log(!!(_dummy && _dummy.nodeValue))
if (_dummy && _dummy.nodeValue) {
if (_dummy.nodeValue == Trex.__WORD_JOINER) {
if (startNode != _dummy) {
// console.log('remove');
$tom.remove(_dummy);
} else {
remained = _dummy;
}
} else {
// console.log('replace');
_dummy.nodeValue = _dummy.nodeValue.replace(Trex.__WORD_JOINER_REGEXP, "");
}
} else {
// console.log("this's not dummy");
}
} catch(e) {
}
}
remained && __TEXT_GC_LIST.splice(0, 0, remained);
__HAS_DUMMY = _FALSE;
}
});
})();
/**
* Wysiwyg 영역의 컨텐츠를 조작하기 위해 사용되며,
* browser와 newlinepolicy에 따라 필요한 함수들을 mixin한다.
* 이 객체를 통해서 Bookmark, txSelection, Marker 객체에 접근한다.
* canvas.getProcessor()를 통해서 얻거나
* canvas.execute(), canvas.query()를 통해서 processor를 얻어서 사용한다.
*
* @abstract
* @class
* @param {Object} win - Wysiwyg 영역의 window 객체
* @param {Object} doc - Wysiwyg 영역의 document 객체
*
* @example
* canvas.execute(function(processor) {
* processor.pasteContent('
', _FALSE);
* });
*
* var value = canvas.query(function(processor) {
* return processor.getText();
* });
*
* var _processor = canvas.getProcessor();
* _processor.focusOnTop();
*/
Trex.Canvas.Processor = Trex.Class.draft({
/** @ignore */
$mixins: [
Trex.I.Processor.Standard,
(($tx.msie_nonstd)? Trex.I.Processor.Trident: {}),
(($tx.msie_std)? Trex.I.Processor.TridentStandard: {}),
(($tx.gecko)? Trex.I.Processor.Gecko: {}),
(($tx.webkit)? Trex.I.Processor.Webkit: {}),
(($tx.presto)? Trex.I.Processor.Presto: {})
]
});
/**
* newlinepolicy가 p인 Wysiwyg Processor
* @class
* @extends Trex.Canvas.Processor
* @param {Object} win - Wysiwyg 영역의 window 객체
* @param {Object} doc - Wysiwyg 영역의 document 객체
*/
Trex.Canvas.ProcessorP = Trex.Class.create({
/** ignore */
$extend: Trex.Canvas.Processor,
/** @ignore */
$mixins: [
Trex.I.Processor.StandardP,
(($tx.msie_nonstd)? Trex.I.Processor.TridentP: {}),
(($tx.msie_std)? Trex.I.Processor.TridentStandardP: {}),
(($tx.gecko)? Trex.I.Processor.GeckoP: {}),
(($tx.webkit)? Trex.I.Processor.WebkitP: {}),
(($tx.presto)? Trex.I.Processor.PrestoP: {})
]
});