| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672 |
- /**
- * @fileOverview
- * native selection, range 객체를 wrapping 한 객체로 Processor 에서 주로 사용된다.
- */
- Trex.I.Selection = {};
- Trex.I.Selection.Standard = /** @lends Trex.Canvas.Selection.prototype */{
- /**
- * native selection object를 리턴한다.
- * @returns {Object} - native selection object
- * @example
- * txSelection.getSel();
- */
- getSel: function(){
- return this.win.getSelection();
- },
- /**
- * 선택된 영역의 텍스트 데이터를 리턴한다.
- * @returns {String} - 선택된 영역의 텍스트 데이터
- * @example
- * txSelection.getText();
- */
- getText: function() {
- return this.getSel().toString();
- },
- /**
- * 선택된 영역의 노드를 리턴한다.
- * @returns {Element} - 선택된 영역의 노드
- * @example
- * txSelection.getNode();
- */
- getNode: function() {
- var _rng = this.getRange();
- if (_rng) {
- var _startContainer = _rng.startContainer;
- if (_startContainer.nodeType == 1) {
- if ($tom.isBody(_startContainer)) {
- return (_startContainer);
- } else {
- return (_startContainer.childNodes[_rng.startOffset]);
- }
- } else {
- return (_startContainer.parentNode);
- }
- } else {
- return _NULL;
- }
- },
- /**
- * native range 를 생성한다.
- * @returns {Object} - native range 객체
- * @example
- * txSelection.createRange();
- */
- createRange: function() {
- return this.doc.createRange();
- },
- /**
- * native text range 를 생성한다.
- * @returns {Object} - native text range 객체
- * @example
- * txSelection.createTextRange();
- */
- createTextRange: function() {
- return this.doc.createRange();
- },
- /**
- * native range object를 리턴한다.
- * @returns {Object} - native range 객체
- * @example
- * txSelection.getRange();
- */
- getRange: function(collapse) {
- var _sel = this.getSel();
- if (_sel && _sel.rangeCount > 0) {
- if (collapse == _NULL) {
- if (_sel.rangeCount == 1) { //단일 Range = 일반적인 경우
- return _sel.getRangeAt(0);
- } else { //복수 Range -> 단일 Range로 변환
- return this.mergeRange(_sel);
- }
- } else { //Range를 collapse할 경우
- var _rng = _sel.getRangeAt(0);
- _rng.collapse(collapse);
- return _rng;
- }
- } else { //Range가 없을 경우
- return this.doc.createRange();
- }
- },
- /**
- * 선택된 영역의 collapse 여부(선택된 영역이 있는지 여부)를 리턴한다.
- * @returns {Boolean} - collapse 여부
- * @example
- * txSelection.isCollapsed();
- */
- isCollapsed: function() {
- var _sel = this.getSel();
- return (_sel && _sel.isCollapsed);
- },
- /**
- * 선택된 영역을 collapse 시킨다.
- * @param {Boolean} toStart - 위치, 시작 = true
- * @example
- * txSelection.collapse(true);
- */
- collapse: function(toStart) {
- var _sel = this.getSel();
- if (_sel && _sel.rangeCount > 0) {
- var _rng = _sel.getRangeAt(0);
- _rng.collapse(toStart);
- }
- },
- /**
- * 선택된 영역의 컨트롤 노드(img,object,hr,table,button)를 리턴한다.
- * @returns {Element} - 선택된 영역의 노드
- * @example
- * txSelection.getControl();
- */
- getControl: function() {
- var _sel = this.getSel();
- var _node;
- if ($tx.opera) {
- /* @opera IMG 선택시 isCollapsed 가 true 되는 문제가 있음. */
- _node = _sel.anchorNode.childNodes[_sel.anchorOffset];
- if (_node == _NULL) {
- return _NULL;
- }
- if(_sel.isCollapsed && _node.tagName != "IMG") {
- return _NULL;
- }
- }
- else {
- if(_sel.isCollapsed) {
- return _NULL;
- }
- _node = _sel.anchorNode.childNodes[_sel.anchorOffset];
- }
- if($tom.kindOf(_node, '%control')) {
- return _node;
- } else {
- return _NULL;
- }
- },
- /**
- * 선택된 영역이 컨트롤 노드인지 여부를 리턴한다.
- * @returns {Boolean} - 컨트롤 노드인지 여부
- * @example
- * txSelection.hasControl();
- */
- hasControl: function() {
- return (this.getControl() != _NULL);
- },
- /**
- * 컨트롤 노드를 선택한다.
- * @param {Element} node - 컨트롤 노트
- * @example
- * txSelection.selectControl(node);
- */
- selectControl: function(node) {
- var _rng = this.createRange();
- _rng.selectNode(node);
- var _sel = this.getSel();
- _sel.removeAllRanges();
- _sel.addRange(_rng);
- },
- /**
- * 선택된 영역이 텍스트 데이터 영역의 어떤 위치인지를 리턴한다.
- * @returns {Number} - 텍스트 데이터 영역의 어떤 위치인지 <br/>
- * 빈 텍스트일 경우 : $tom.__POSITION.__EMPTY_TEXT : -2<br/>
- * 텍스트의 처음 : $tom.__POSITION.__START_OF_TEXT : -1<br/>
- * 텍스트의 중간 : $tom.__POSITION.__MIDDLE_OF_TEXT : 0<br/>
- * 텍스트의 마지막 : $tom.__POSITION.__END_OF_TEXT : 1
- * @example
- * txSelection.compareTextPos();
- */
- compareTextPos: function() {
- var _rng = this.getRange();
- if (_rng) {
- var _startContainer = _rng.startContainer;
- if (_startContainer.nodeType == 3) {
- if ( _startContainer.textContent.trim().length == 0 ){
- return $tom.__POSITION.__EMPTY_TEXT;
- }else if(_rng.startOffset == 0 ) {
- return $tom.__POSITION.__START_OF_TEXT;
- } else if(_rng.startOffset == _startContainer.textContent.length) {
- return $tom.__POSITION.__END_OF_TEXT;
- } else {
- return $tom.__POSITION.__MIDDLE_OF_TEXT;
- }
- }
- }
- return $tom.__POSITION.__END_OF_TEXT;
- },
- /**
- * @private
- * selection에 복수의 range가 있을 경우 range를 합친디ㅏ.
- * @returns {Object} - native range 객체
- * @example
- * txSelection.mergeRange(sel);
- */
- mergeRange: function(sel) {
- try {
- var _ranges = [];
- for(var i=0,_length=sel.rangeCount; i<_length; i++) {
- _ranges.push(sel.getRangeAt(i));
- }
- sel.removeAllRanges();
-
- var _startNode = _ranges[0].startContainer.childNodes[_ranges[0].startOffset];
- var _endNode = _ranges[_length - 1].endContainer.childNodes[_ranges[_length - 1].endOffset - 1];
-
- var _rng = this.doc.createRange();
- try {
- _rng.setStart(_startNode, 0);
- } catch (e) {
- _rng.collapse(_TRUE);
- }
- try {
- _rng.setEnd(_endNode, _endNode.childNodes.length);
- } catch (e) {}
-
- sel.addRange(_rng);
- return sel.getRangeAt(0);
- } catch(e) {
- return sel.getRangeAt(0);
- }
- },
- /**
- * @private
- * 특정 위치로 range의 시작위치를 지정한다.
- * @param {Object} rng - native range 객체
- * @param {Element} node - 특정 부모 노드
- * @param {Number} offset - 노드의 옵셋
- * @example
- * txSelection.setStart(range, node, 1);
- */
- setStart: function(rng, node, offset) {
- try {
- rng.setStart(node, offset);
- } catch (e) {
- rng.collapse(_TRUE);
- rng.setStart(node, offset);
- }
- },
- /**
- * @private
- * 특정 위치로 range의 끝위치를 지정한다.
- * @param {Object} rng - native range 객체
- * @param {Element} node - 특정 부모 노드
- * @param {Number} offset - 노드의 옵셋
- * @example
- * txSelection.setEnd(range, node, 1);
- */
- setEnd: function(rng, node, offset) {
- try {
- rng.setEnd(node, offset);
- } catch (e) {
- rng.collapse(_FALSE);
- rng.setEnd(node, offset);
- }
- },
- /**
- * 주어진 range를 선택한다.
- * @returns {Object} - native selection 객체
- * @example
- * txSelection.selectRange(range);
- */
- selectRange: function(rng) {
- var _sel = this.getSel();
- _sel.removeAllRanges();
- _sel.addRange(rng);
- }
- };
-
- Trex.I.Selection.Trident = /** @lends Trex.Canvas.Selection.prototype */{
- /**
- * native selection object를 리턴한다.
- * @returns {Object} - native selection object
- * @example
- * txSelection.getSel();
- */
- getSel: function(){
- return this.doc.selection;
- },
- /**
- * 선택된 영역의 텍스트 데이터를 리턴한다.
- * @returns {String} - 선택된 영역의 텍스트 데이터
- * @example
- * txSelection.getText();
- */
- getText: function() {
- return this.getSel().createRange().text;
- },
- /**
- * 선택된 영역의 노드를 리턴한다.
- * @returns {Element} - 선택된 영역의 노드
- * @example
- * txSelection.getNode();
- */
- getNode: function() {
- var _sel = this.getSel();
- var _type = _sel.type.toLowerCase();
- if (_type === "control") {
- return (_sel.createRange().item(0));
- } else {
- return (_sel.createRange().parentElement());
- }
- },
- /**
- * native range 를 생성한다.
- * @returns {Object} - native range 객체
- * @example
- * txSelection.createRange();
- */
- createRange: function() {
- var _sel = this.getSel();
- return _sel.createRange();
- },
- /**
- * native text range 를 생성한다.
- * @returns {Object} - native text range 객체
- * @example
- * txSelection.createTextRange();
- */
- createTextRange: function() {
- return this.doc.body.createTextRange();
- },
- /**
- * native range object를 리턴한다.
- * @returns {Object} - native range 객체
- * @example
- * txSelection.getRange();
- */
- getRange: function(collapse){
- var _sel = this.getSel();
- var _type = _sel.type.toLowerCase();
- if (_type == "none") {
- return _sel.createRange() ? _sel.createRange() : function(){
- var _rng = this.doc.body.createTextRange();
- _rng.collapse(_TRUE);
- _rng.select();
- return _rng;
- }();
- }
- if (collapse == _NULL) {
- return _sel.createRange();
- } else {
- if (_type === "text") {
- var _rng = _sel.createRange();
- _rng.collapse(collapse);
- _rng.select();
- return _sel.createRange();
- } else {
- if (_type === "control") {
- _sel.empty();
- }
- return _sel.createRange();
- }
- }
- },
- /**
- * 선택된 영역의 collapse 여부(선택된 영역이 있는지 여부)를 리턴한다.
- * @returns {Boolean} - collapse 여부
- * @example
- * txSelection.isCollapsed();
- */
- isCollapsed: function() {
- var _sel = this.getSel();
- var _type = _sel.type.toLowerCase();
- if(_type === "none") {
- return _TRUE;
- } else if(_type === "control") {
- return _TRUE;
- } else if(_type === "text") {
- var _rng = _sel.createRange();
- return _rng.compareEndPoints('StartToEnd', _rng) == 0;
- } else {
- return _TRUE;
- }
- },
- /**
- * 선택된 영역을 collapse 시킨다.
- * @param {Boolean} toStart - 위치, 시작 = true
- * @example
- * txSelection.collapse(true);
- */
- collapse: function(toStart) {
- var _sel = this.getSel();
- var _type = _sel.type.toLowerCase();
- if(_type === "text") {
- var _rng = _sel.createRange();
- _rng.collapse(toStart);
- _rng.select();
- return _sel.createRange();
- } else {
- if(_type === "control") {
- _sel.empty();
- }
- return _sel.createRange();
- }
- },
- /**
- * 선택된 영역의 컨트롤 노드(img,object,hr,table,button)를 리턴한다.
- * @returns {Element} - 선택된 영역의 노드
- * @example
- * txSelection.hasControl();
- */
- getControl: function() {
- var _sel = this.getSel();
- var _type = _sel.type.toLowerCase();
- if (_type === "control") {
- var _node = _sel.createRange().item(0);
- if($tom.kindOf(_node, '%control')) {
- return _node;
- } else {
- return _NULL;
- }
- } else {
- return _NULL;
- }
- },
- /**
- * 선택된 영역이 컨트롤 노드인지 여부를 리턴한다.
- * @returns {Boolean} - 컨트롤 노드인지 여부
- * @example
- * txSelection.hasControl();
- */
- hasControl: function() {
- var _sel = this.getSel();
- var _type = _sel.type.toLowerCase();
- if (_type === "control") {
- return _TRUE;
- } else {
- return _FALSE;
- }
- },
- /**
- * 컨트롤 노드를 선택한다.
- * @param {Element} node - 컨트롤 노트
- * @example
- * txSelection.selectControl(node);
- */
- selectControl: function(node) {
- var _rng = this.doc.body.createControlRange();
- _rng.add(node);
- _rng.select();
- },
- /**
- * 선택된 영역이 텍스트 데이터 영역의 어떤 위치인지를 리턴한다.
- * @returns {Number} - 텍스트 데이터 영역의 어떤 위치인지 <br/>
- * 텍스트의 처음 : $tom.__POSITION.__START_OF_TEXT : -1<br/>
- * 텍스트의 중간 : $tom.__POSITION.__MIDDLE_OF_TEXT : 0<br/>
- * 텍스트의 마지막 : $tom.__POSITION.__END_OF_TEXT : 1
- * @example
- * txSelection.compareTextPos();
- */
- compareTextPos: function() {
- var _sel = this.getSel();
- var _type = _sel.type.toLowerCase();
- if(_type === "none") {
- var _rng = _sel.createRange();
- var _rng2 = _rng.duplicate();
- _rng2.moveToElementText(_rng.parentElement());
- if ( _rng2.text.trim().replace(Trex.__WORD_JOINER_REGEXP, "").length == 0 ){
- return $tom.__POSITION.__EMPTY_TEXT;
- } else if(_rng.compareEndPoints('StartToStart', _rng2) == 0) {
- return $tom.__POSITION.__START_OF_TEXT;
- } else if(_rng.compareEndPoints('EndToEnd', _rng2) == 0) {
- return $tom.__POSITION.__END_OF_TEXT;
- } else {
- return $tom.__POSITION.__MIDDLE_OF_TEXT;
- }
- }
- return $tom.__POSITION.__END_OF_TEXT;
- },
- /**
- * @private
- * @reference http://msdn.microsoft.com/en-us/library/ms536745(VS.85).aspx
- StartToEnd - Move the start of the TextRange object to the end of the specified oTextRange parameter.
- StartToStart - Move the start of the TextRange object to the start of the specified oTextRange parameter.
- EndToStart - Move the end of the TextRange object to the start of the specified oTextRange parameter.
- EndToEnd - Move the end of the TextRange object to the end of the specified oTextRange parameter.
- */
- transTextRange: function(rng, node, offset, toStart) {
- var _pntRng = this.createTextRange();
-
- var _pntNode = this.win.span(Trex.__WORD_JOINER);
- $tom.insertAt(_pntNode, node);
- _pntRng.moveToElementText(_pntNode);
- $tom.remove(_pntNode);
-
- _pntRng.collapse(_TRUE);
- _pntRng.moveStart('character', offset);
-
- if (toStart) {
- rng.setEndPoint('StartToStart', _pntRng);
- } else {
- rng.setEndPoint('EndToEnd', _pntRng);
- }
-
- return rng;
- },
- /**
- * @private
- * 특정 위치로 range의 시작위치를 지정한다.
- * @param {Object} rng - native range 객체
- * @param {Element} node - 특정 부모 노드
- * @param {Number} offset - 노드의 옵셋
- * @example
- * txSelection.setStart(range, node, 1);
- */
- setStart: function(rng, node, offset) {
- try {
- this.transTextRange(rng, node, offset, _TRUE);
- } catch (e) {
- console.log(e)
- }
- return rng;
- },
- /**
- * @private
- * 특정 위치로 range의 끝위치를 지정한다.
- * @param {Object} rng - native range 객체
- * @param {Element} node - 특정 부모 노드
- * @param {Number} offset - 노드의 옵셋
- * @example
- * txSelection.setEnd(range, node, 1);
- */
- setEnd: function(rng, node, offset) {
- try {
- this.transTextRange(rng, node, offset, _FALSE);
- } catch (e) {
- console.log(e)
- }
- return rng;
- },
- /**
- * 주어진 range를 선택한다.
- * @returns {Object} - native selection 객체
- * @example
- * txSelection.selectRange(range);
- */
- selectRange: function(rng) {
- rng.select();
- }
- };
- Trex.I.Selection.TridentStandard = {
- /**
- * 선택된 영역의 컨트롤 노드(img,object,hr,table,button)를 리턴한다.
- * @returns {Element} - 선택된 영역의 노드
- * @example
- * txSelection.getControl();
- */
- getControl: function() {
- var _sel = this.getSel();
- if(_sel.isCollapsed) {
- return null;
- }
- if ($tom.isElement(_sel.anchorNode)) {
- var _node = _sel.anchorNode.childNodes[_sel.anchorOffset];
- if ($tom.kindOf(_node, '%control')) {
- return _node;
- } else {
- return null;
- }
- }
- //button
- var _prevNode = $tom.previous(_sel.focusNode);
- var _nextNode = $tom.next(_sel.anchorNode);
- if(_prevNode == _nextNode) {
- return $tom.first(_prevNode, '%control');
- } else {
- return null;
- }
- },
- /**
- * 컨트롤 노드를 선택한다.
- * @param {Element} node - 컨트롤 노트
- * @example
- * txSelection.selectControl(node);
- */
- selectControl: function(node) {
- var _rng = this.createRange();
- _rng.selectNode(node);
- var _sel = this.getSel();
- _sel.removeAllRanges();
- _sel.addRange(_rng);
- }
- };
- Trex.I.Selection.Gecko = {
-
- };
- Trex.I.Selection.Webkit = {
- /**
- * 선택된 영역의 컨트롤 노드(img,object,hr,table,button)를 리턴한다.
- * @returns {Element} - 선택된 영역의 노드
- * @example
- * txSelection.getControl();
- */
- getControl: function() {
- var _sel = this.getSel();
- if(_sel.isCollapsed) {
- return _NULL;
- }
- if ($tom.isElement(_sel.anchorNode)) {
- var _node = _sel.anchorNode.childNodes[_sel.anchorOffset];
- if ($tom.kindOf(_node, '%control')) {
- return _node;
- } else {
- return _NULL;
- }
- }
- //button
- var _prevNode = $tom.previous(_sel.focusNode);
- var _nextNode = $tom.next(_sel.anchorNode);
- if(_prevNode == _nextNode) {
- return $tom.first(_prevNode, '%control');
- } else {
- return _NULL;
- }
- },
- /**
- * 컨트롤 노드를 선택한다.
- * @param {Element} node - 컨트롤 노트
- * @example
- * txSelection.selectControl(node);
- */
- selectControl: function(node) {
- var _rng = this.createRange();
- _rng.selectNode(node);
- var _sel = this.getSel();
- _sel.removeAllRanges();
- _sel.addRange(_rng);
- }
- };
- Trex.I.Selection.Presto = {
-
- };
- /**
- * native selection, range 객체를 wrapping 한 객체로 <br/>
- * browser에 따라 필요한 함수들을 mixin한다. <br/>
- * 주로 Processor와 연관된 객체에서 호출하며, <br/>
- * processor.getTxSel()를 통해서 txSelection를 얻어서 사용한다. <br/>
- * native selection 과 구분짓기 위해서 txSelection로 명명한다.
- *
- * @class
- * @param {Object} processor - Processor 객체
- */
- Trex.Canvas.Selection = Trex.Class.create(/** @lends Trex.Canvas.Selection.prototype */{
- /** @ignore */
- $mixins: [
- Trex.I.Selection.Standard,
- (($tx.msie_nonstd)? Trex.I.Selection.Trident: {}),
- (($tx.msie_std)? Trex.I.Selection.TridentStandard: {}),
- (($tx.gecko)? Trex.I.Selection.Gecko: {}),
- (($tx.webkit)? Trex.I.Selection.Webkit: {}),
- (($tx.presto)? Trex.I.Selection.Presto: {})
- ],
- initialize: function(processor) {
- this.processor = processor;
- this.win = processor.win;
- this.doc = processor.doc;
- }
- });
|