/** * SmartEditor2 NHN_Library:SE2.3.10.O11036:SmartEditor2.0-OpenSource * @version 11036 */ var nSE2Version = 11036;if(typeof window.nhn=='undefined') window.nhn = {}; /** * @fileOverview This file contains a function that takes care of various operations related to find and replace * @name N_FindReplace.js */ nhn.FindReplace = jindo.$Class({ sKeyword : "", window : null, document : null, bBrowserSupported : false, // true if End Of Contents is reached during last execution of find bEOC : false, $init : function(win){ this.sInlineContainer = "SPAN|B|U|I|S|STRIKE"; this.rxInlineContainer = new RegExp("^("+this.sInlineContainer+")$"); this.window = win; this.document = this.window.document; if(this.document.domain != this.document.location.hostname){ var oAgentInfo = jindo.$Agent(); var oNavigatorInfo = oAgentInfo.navigator(); if(oNavigatorInfo.firefox && oNavigatorInfo.version < 3){ this.bBrowserSupported = false; this.find = function(){return 3}; return; } } this.bBrowserSupported = true; }, /** * 해당노드의 다음 element를 찾는다. * 찾을 수 없거나 body 이면 body를 리턴 */ _findNextElement : function(elNode){ if(!elNode || elNode.tagName == "BODY"){ return null; } var elNext = elNode.nextSibling; if(elNext){ return (elNext.nodeType == 1 ? elNext : this._findNextElement(elNext)); }else{ return this._findNextElement(elNode.parentNode); } }, // 0: found // 1: not found // 2: keyword required // 3: browser not supported find : function(sKeyword, bCaseMatch, bBackwards, bWholeWord){ var bSearchResult, bFreshSearch; this.window.focus(); if(!sKeyword) return 2; // try find starting from current cursor position this.bEOC = false; bSearchResult = this.findNext(sKeyword, bCaseMatch, bBackwards, bWholeWord); if(bSearchResult) return 0; // end of the contents could have been reached so search again from the beginning this.bEOC = true; bSearchResult = this.findNew(sKeyword, bCaseMatch, bBackwards, bWholeWord); if(bSearchResult) return 0; return 1; }, findNew : function (sKeyword, bCaseMatch, bBackwards, bWholeWord){ this.findReset(); return this.findNext(sKeyword, bCaseMatch, bBackwards, bWholeWord); }, findNext : function(sKeyword, bCaseMatch, bBackwards, bWholeWord){ var bSearchResult; bCaseMatch = bCaseMatch || false; bWholeWord = bWholeWord || false; bBackwards = bBackwards || false; if(this.window.find){ var bWrapAround = false; return this.window.find(sKeyword, bCaseMatch, bBackwards, bWrapAround, bWholeWord); } // IE solution if(this.document.body.createTextRange){ try{ var iOption = 0; if(bBackwards) iOption += 1; if(bWholeWord) iOption += 2; if(bCaseMatch) iOption += 4; this.window.focus(); if(this.document.selection){ this._range = this.document.selection.createRangeCollection().item(0); this._range.collapse(false); }else{ // [SMARTEDITORSUS-1528] IE11인 경우 this._range = this.document.body.createTextRange(); var elNext = this._findNextElement(this.window.getSelection().focusNode); if(elNext){ this._range.moveToElementText(elNext); } } bSearchResult = this._range.findText(sKeyword, 1, iOption); this._range.select(); return bSearchResult; }catch(e){ return false; } } return false; }, findReset : function() { if (this.window.find){ this.window.getSelection().removeAllRanges(); return; } // IE solution if(this.document.body.createTextRange){ if(this.document.selection){ this._range = this.document.body.createTextRange(); this._range.collapse(true); this._range.select(); }else if(this.window.getSelection){ // [SMARTEDITORSUS-1528] IE11인 경우 var oSelection = this.window.getSelection(); oSelection.removeAllRanges(); oSelection.selectAllChildren(this.document.body); oSelection.collapseToStart(); } } }, // 0: replaced & next word found // 1: replaced & next word not found // 2: not replaced & next word found // 3: not replaced & next word not found // 4: sOriginalWord required replace : function(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord){ return this._replace(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord); }, /** * [SMARTEDITORSUS-1591] 크롬에서 replaceAll 시 selection 을 새로 만들면 첫번째 단어가 삭제되지 않고 남는 문제가 있어서 * selection 객체를 받아서 사용할 수 있도록 private 메서드 추가 * TODO: 근본적으로 HuskyRange 를 리팩토링할 필요가 있음 */ _replace : function(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord, oSelection){ if(!sOriginalWord) return 4; oSelection = oSelection || new nhn.HuskyRange(this.window); oSelection.setFromSelection(); bCaseMatch = bCaseMatch || false; var bMatch, selectedText = oSelection.toString(); if(bCaseMatch) bMatch = (selectedText == sOriginalWord); else bMatch = (selectedText.toLowerCase() == sOriginalWord.toLowerCase()); if(!bMatch) return this.find(sOriginalWord, bCaseMatch, bBackwards, bWholeWord)+2; if(typeof Replacement == "function"){ // the returned oSelection must contain the replacement oSelection = Replacement(oSelection); }else{ oSelection.pasteText(Replacement); } // force it to find the NEXT occurance of sOriginalWord oSelection.select(); return this.find(sOriginalWord, bCaseMatch, bBackwards, bWholeWord); }, // returns number of replaced words // -1 : if original word is not given replaceAll : function(sOriginalWord, Replacement, bCaseMatch, bWholeWord){ if(!sOriginalWord) return -1; var bBackwards = false; var iReplaceResult; var iResult = 0; var win = this.window; if(this.find(sOriginalWord, bCaseMatch, bBackwards, bWholeWord) !== 0){ return iResult; } var oSelection = new nhn.HuskyRange(this.window); oSelection.setFromSelection(); // 시작점의 북마크가 지워지면서 시작점을 지나서 replace가 되는 현상 방지용 // 첫 단어 앞쪽에 특수 문자 삽입 해서, replace와 함께 북마크가 사라지는 것 방지 oSelection.collapseToStart(); var oTmpNode = this.window.document.createElement("SPAN"); oTmpNode.innerHTML = unescape("%uFEFF"); oSelection.insertNode(oTmpNode); oSelection.select(); var sBookmark = oSelection.placeStringBookmark(); this.bEOC = false; while(!this.bEOC){ iReplaceResult = this._replace(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord, oSelection); if(iReplaceResult == 0 || iReplaceResult == 1){ iResult++; } } var startingPointReached = function(){ var oCurSelection = new nhn.HuskyRange(win); oCurSelection.setFromSelection(); oSelection.moveToBookmark(sBookmark); var pos = oSelection.compareBoundaryPoints(nhn.W3CDOMRange.START_TO_END, oCurSelection); if(pos == 1) return false; return true; }; iReplaceResult = 0; this.bEOC = false; while(!startingPointReached() && iReplaceResult == 0 && !this.bEOC){ iReplaceResult = this._replace(sOriginalWord, Replacement, bCaseMatch, bBackwards, bWholeWord, oSelection); if(iReplaceResult == 0 || iReplaceResult == 1){ iResult++; } } oSelection.moveToBookmark(sBookmark); oSelection.deleteContents(); // [SMARTEDITORSUS-1591] 크롬에서 첫번째 단어가 삭제되지 않는 경우가 있으므로 select()메서드대신 deleteContents() 메서드를 호출한다. oSelection.removeStringBookmark(sBookmark); // setTimeout 없이 바로 지우면 IE8 브라우저가 빈번하게 죽어버림 setTimeout(function(){ oTmpNode.parentNode.removeChild(oTmpNode); }, 0); return iResult; }, _isBlankTextNode : function(oNode){ if(oNode.nodeType == 3 && oNode.nodeValue == ""){return true;} return false; }, _getNextNode : function(elNode, bDisconnected){ if(!elNode || elNode.tagName == "BODY"){ return {elNextNode: null, bDisconnected: false}; } if(elNode.nextSibling){ elNode = elNode.nextSibling; while(elNode.firstChild){ if(elNode.tagName && !this.rxInlineContainer.test(elNode.tagName)){ bDisconnected = true; } elNode = elNode.firstChild; } return {elNextNode: elNode, bDisconnected: bDisconnected}; } return this._getNextNode(nhn.DOMFix.parentNode(elNode), bDisconnected); }, _getNextTextNode : function(elNode, bDisconnected){ var htNextNode, elNode; while(true){ htNextNode = this._getNextNode(elNode, bDisconnected); elNode = htNextNode.elNextNode; bDisconnected = htNextNode.bDisconnected; if(elNode && elNode.nodeType != 3 && !this.rxInlineContainer.test(elNode.tagName)){ bDisconnected = true; } if(!elNode || (elNode.nodeType==3 && !this._isBlankTextNode(elNode))){ break; } } return {elNextText: elNode, bDisconnected: bDisconnected}; }, _getFirstTextNode : function(){ // 문서에서 제일 앞쪽에 위치한 아무 노드 찾기 var elFirstNode = this.document.body.firstChild; while(!!elFirstNode && elFirstNode.firstChild){ elFirstNode = elFirstNode.firstChild; } // 문서에 아무 노드도 없음 if(!elFirstNode){ return null; } // 처음 노드가 텍스트 노드가 아니거나 bogus 노드라면 다음 텍스트 노드를 찾음 if(elFirstNode.nodeType != 3 || this._isBlankTextNode(elFirstNode)){ var htTmp = this._getNextTextNode(elFirstNode, false); elFirstNode = htTmp.elNextText; } return elFirstNode; }, _addToTextMap : function(elNode, aTexts, aElTexts, nLen){ var nStartPos = aTexts[nLen].length; for(var i=0, nTo=elNode.nodeValue.length; i=0; j--){ var sTmp = sText.substring(j, j+nOriginLen); if(bWholeWord && (j > 0 && sText.charAt(j-1).match(/[a-zA-Z가-힣]/)) ){ continue; } if(sTmp == sOriginalWord){ nMatchCnt++; var oSelection = new nhn.HuskyRange(this.window); // 마지막 글자의 뒷부분 처리 var elContainer, nOffset; if(j+nOriginLen < aElTexts[i].length){ elContainer = aElTexts[i][j+nOriginLen][0]; nOffset = aElTexts[i][j+nOriginLen][1]; }else{ elContainer = aElTexts[i][j+nOriginLen-1][0]; nOffset = aElTexts[i][j+nOriginLen-1][1]+1; } oSelection.setEnd(elContainer, nOffset, true, true); oSelection.setStart(aElTexts[i][j][0], aElTexts[i][j][1], true); if(typeof Replacement == "function"){ // the returned oSelection must contain the replacement oSelection = Replacement(oSelection); }else{ oSelection.pasteText(Replacement); } j -= nOriginLen; } continue; } } /* var t2 = new Date(); console.log("OK"); console.log(sOriginalWord); console.log("MC:"+(t1-t0)); console.log("RP:"+(t2-t1)); */ return nMatchCnt; }catch(e){ /* console.log("ERROR"); console.log(sOriginalWord); console.log(new Date()-t0); */ return nMatchCnt; } } }); // "padding", "backgroundcolor", "border", "borderTop", "borderRight", "borderBottom", "borderLeft", "color", "textAlign", "fontWeight" nhn.husky.SE2M_TableTemplate = [ {}, /* // 0 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "0" }, htTableStyle : { border : "1px dashed #666666", borderRight : "0", borderBottom : "0" }, aRowStyle : [ { padding : "3px 0 2px 0", border : "1px dashed #666666", borderTop : "0", borderLeft : "0" } ] }, // 1 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "0" }, htTableStyle : { border : "1px solid #c7c7c7", borderRight : "0", borderBottom : "0" }, aRowStyle : [ { padding : "3px 0 2px 0", border : "1px solid #c7c7c7", borderTop : "0", borderLeft : "0" } ] }, // 2 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { border : "1px solid #c7c7c7" }, aRowStyle : [ { padding : "2px 0 1px 0", border : "1px solid #c7c7c7" } ] }, // 3 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { border : "1px double #c7c7c7" }, aRowStyle : [ { padding : "1px 0 0", border : "3px double #c7c7c7" } ] }, // 4 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { borderWidth : "2px 1px 1px 2px", borderStyle : "solid", borderColor : "#c7c7c7" }, aRowStyle : [ { padding : "2px 0 0", borderWidth : "1px 2px 2px 1px", borderStyle : "solid", borderColor : "#c7c7c7" } ] }, // 5 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { borderWidth : "1px 2px 2px 1px", borderStyle : "solid", borderColor : "#c7c7c7" }, aRowStyle : [ { padding : "1px 0 0", borderWidth : "2px 1px 1px 2px", borderStyle : "solid", borderColor : "#c7c7c7" } ] }, */ // Black theme ====================================================== // 6 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { backgroundColor : "#c7c7c7" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#ffffff", color : "#666666" } ] }, // 7 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { backgroundColor : "#c7c7c7" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#ffffff", color : "#666666" }, { padding : "3px 4px 2px", backgroundColor : "#f3f3f3", color : "#666666" } ] }, // 8 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "0" }, htTableStyle : { backgroundColor : "#ffffff", borderTop : "1px solid #c7c7c7" }, aRowStyle : [ { padding : "3px 4px 2px", borderBottom : "1px solid #c7c7c7", backgroundColor : "#ffffff", color : "#666666" }, { padding : "3px 4px 2px", borderBottom : "1px solid #c7c7c7", backgroundColor : "#f3f3f3", color : "#666666" } ] }, // 9 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "0" }, htTableStyle : { border : "1px solid #c7c7c7" }, ht1stRowStyle : { padding : "3px 4px 2px", backgroundColor : "#f3f3f3", color : "#666666", borderRight : "1px solid #e7e7e7", textAlign : "left", fontWeight : "normal" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#ffffff", borderTop : "1px solid #e7e7e7", borderRight : "1px solid #e7e7e7", color : "#666666" } ] }, // 10 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { backgroundColor : "#c7c7c7" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#f8f8f8", color : "#666666" }, { padding : "3px 4px 2px", backgroundColor : "#ebebeb", color : "#666666" } ] }, // 11 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "0" }, ht1stRowStyle : { padding : "3px 4px 2px", borderTop : "1px solid #000000", borderBottom : "1px solid #000000", backgroundColor : "#333333", color : "#ffffff", textAlign : "left", fontWeight : "normal" }, aRowStyle : [ { padding : "3px 4px 2px", borderBottom : "1px solid #ebebeb", backgroundColor : "#ffffff", color : "#666666" }, { padding : "3px 4px 2px", borderBottom : "1px solid #ebebeb", backgroundColor : "#f8f8f8", color : "#666666" } ] }, // 12 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { backgroundColor : "#c7c7c7" }, ht1stRowStyle : { padding : "3px 4px 2px", backgroundColor : "#333333", color : "#ffffff", textAlign : "left", fontWeight : "normal" }, ht1stColumnStyle : { padding : "3px 4px 2px", backgroundColor : "#f8f8f8", color : "#666666", textAlign : "left", fontWeight : "normal" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#ffffff", color : "#666666" } ] }, // 13 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { backgroundColor : "#c7c7c7" }, ht1stColumnStyle : { padding : "3px 4px 2px", backgroundColor : "#333333", color : "#ffffff", textAlign : "left", fontWeight : "normal" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#ffffff", color : "#666666" } ] }, // Blue theme ====================================================== // 14 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { backgroundColor : "#a6bcd1" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#ffffff", color : "#3d76ab" } ] }, // 15 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { backgroundColor : "#a6bcd1" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#ffffff", color : "#3d76ab" }, { padding : "3px 4px 2px", backgroundColor : "#f6f8fa", color : "#3d76ab" } ] }, // 16 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "0" }, htTableStyle : { backgroundColor : "#ffffff", borderTop : "1px solid #a6bcd1" }, aRowStyle : [ { padding : "3px 4px 2px", borderBottom : "1px solid #a6bcd1", backgroundColor : "#ffffff", color : "#3d76ab" }, { padding : "3px 4px 2px", borderBottom : "1px solid #a6bcd1", backgroundColor : "#f6f8fa", color : "#3d76ab" } ] }, // 17 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "0" }, htTableStyle : { border : "1px solid #a6bcd1" }, ht1stRowStyle : { padding : "3px 4px 2px", backgroundColor : "#f6f8fa", color : "#3d76ab", borderRight : "1px solid #e1eef7", textAlign : "left", fontWeight : "normal" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#ffffff", borderTop : "1px solid #e1eef7", borderRight : "1px solid #e1eef7", color : "#3d76ab" } ] }, // 18 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { backgroundColor : "#a6bcd1" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#fafbfc", color : "#3d76ab" }, { padding : "3px 4px 2px", backgroundColor : "#e6ecf2", color : "#3d76ab" } ] }, // 19 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "0" }, ht1stRowStyle : { padding : "3px 4px 2px", borderTop : "1px solid #466997", borderBottom : "1px solid #466997", backgroundColor : "#6284ab", color : "#ffffff", textAlign : "left", fontWeight : "normal" }, aRowStyle : [ { padding : "3px 4px 2px", borderBottom : "1px solid #ebebeb", backgroundColor : "#ffffff", color : "#3d76ab" }, { padding : "3px 4px 2px", borderBottom : "1px solid #ebebeb", backgroundColor : "#f6f8fa", color : "#3d76ab" } ] }, // 20 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { backgroundColor : "#a6bcd1" }, ht1stRowStyle : { padding : "3px 4px 2px", backgroundColor : "#6284ab", color : "#ffffff", textAlign : "left", fontWeight : "normal" }, ht1stColumnStyle : { padding : "3px 4px 2px", backgroundColor : "#f6f8fa", color : "#3d76ab", textAlign : "left", fontWeight : "normal" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#ffffff", color : "#3d76ab" } ] }, // 21 { htTableProperty : { border : "0", cellPadding : "0", cellSpacing : "1" }, htTableStyle : { backgroundColor : "#a6bcd1" }, ht1stColumnStyle : { padding : "3px 4px 2px", backgroundColor : "#6284ab", color : "#ffffff", textAlign : "left", fontWeight : "normal" }, aRowStyle : [ { padding : "3px 4px 2px", backgroundColor : "#ffffff", color : "#3d76ab" } ] } ]; if(typeof window.nhn=='undefined'){window.nhn = {};} if (!nhn.husky){nhn.husky = {};} nhn.husky.oMockDebugger = { log_MessageStart: function() {}, log_MessageEnd: function() {}, log_MessageStepStart: function() {}, log_MessageStepEnd: function() {}, log_CallHandlerStart: function() {}, log_CallHandlerEnd: function() {}, handleException: function() {}, setApp: function() {} }; //{ /** * @fileOverview This file contains Husky framework core * @name HuskyCore.js */ nhn.husky.HuskyCore = jindo.$Class({ name : "HuskyCore", aCallerStack : null, $init : function(htOptions){ this.htOptions = htOptions||{}; if( this.htOptions.oDebugger ){ if( !nhn.husky.HuskyCore._cores ) { nhn.husky.HuskyCore._cores = []; nhn.husky.HuskyCore.getCore = function() { return nhn.husky.HuskyCore._cores; }; } nhn.husky.HuskyCore._cores.push(this); this.htOptions.oDebugger.setApp(this); } // To prevent processing a Husky message before all the plugins are registered and ready, // Queue up all the messages here until the application's status is changed to READY this.messageQueue = []; this.oMessageMap = {}; this.oDisabledMessage = {}; this.aPlugins = []; this.appStatus = nhn.husky.APP_STATUS.NOT_READY; this.aCallerStack = []; this._fnWaitForPluginReady = jindo.$Fn(this._waitForPluginReady, this).bind(); // Register the core as a plugin so it can receive messages this.registerPlugin(this); }, setDebugger: function(oDebugger) { this.htOptions.oDebugger = oDebugger; oDebugger.setApp(this); }, exec : function(msg, args, oEvent){ // If the application is not yet ready just queue the message if(this.appStatus == nhn.husky.APP_STATUS.NOT_READY){ this.messageQueue[this.messageQueue.length] = {'msg':msg, 'args':args, 'event':oEvent}; return true; } this.exec = this._exec; this.exec(msg, args, oEvent); }, delayedExec : function(msg, args, nDelay, oEvent){ var fExec = jindo.$Fn(this.exec, this).bind(msg, args, oEvent); setTimeout(fExec, nDelay); }, _exec : function(msg, args, oEvent){ return (this._exec = this.htOptions.oDebugger?this._execWithDebugger:this._execWithoutDebugger).call(this, msg, args, oEvent); }, _execWithDebugger : function(msg, args, oEvent){ this.htOptions.oDebugger.log_MessageStart(msg, args); var bResult = this._doExec(msg, args, oEvent); this.htOptions.oDebugger.log_MessageEnd(msg, args); return bResult; }, _execWithoutDebugger : function(msg, args, oEvent){ return this._doExec(msg, args, oEvent); }, _doExec : function(msg, args, oEvent){ var bContinue = false; if(!this.oDisabledMessage[msg]){ var allArgs = []; if(args && args.length){ var iLen = args.length; for(var i=0; i= 0 && nhn.DOMFix.parentNode(aAllNodes[iChildIdx]) == aAllNodes[iCurIdx]){ iChildIdx = this._recurConstructClonedTree(aAllNodes, iChildIdx, oCurNodeCloneWithChildren); } // this may trigger an error message in IE when an erroneous script is inserted oClonedParentNode.insertBefore(oCurNodeCloneWithChildren, oClonedParentNode.firstChild); return iChildIdx; }; this._recurConstructClonedTree = _recurConstructClonedTree; aNodes[aNodes.length] = nhn.DOMFix.parentNode(aNodes[aNodes.length-1]); this._recurConstructClonedTree(aNodes, aNodes.length-1, oClonedParentNode); return {oStartContainer: oClonedStartContainer, oEndContainer: oClonedEndContainer}; }, cloneRange : function(){ return this._copyRange(new nhn.W3CDOMRange(this._window)); }, _copyRange : function(oClonedRange){ oClonedRange.collapsed = this.collapsed; oClonedRange.commonAncestorContainer = this.commonAncestorContainer; oClonedRange.endContainer = this.endContainer; oClonedRange.endOffset = this.endOffset; oClonedRange.startContainer = this.startContainer; oClonedRange.startOffset = this.startOffset; oClonedRange._document = this._document; return oClonedRange; }, collapse : function(toStart){ if(toStart){ this.endContainer = this.startContainer; this.endOffset = this.startOffset; }else{ this.startContainer = this.endContainer; this.startOffset = this.endOffset; } this._updateRangeInfo(); }, compareBoundaryPoints : function(how, sourceRange){ switch(how){ case nhn.W3CDOMRange.START_TO_START: return this._compareEndPoint(this.startContainer, this.startOffset, sourceRange.startContainer, sourceRange.startOffset); case nhn.W3CDOMRange.START_TO_END: return this._compareEndPoint(this.endContainer, this.endOffset, sourceRange.startContainer, sourceRange.startOffset); case nhn.W3CDOMRange.END_TO_END: return this._compareEndPoint(this.endContainer, this.endOffset, sourceRange.endContainer, sourceRange.endOffset); case nhn.W3CDOMRange.END_TO_START: return this._compareEndPoint(this.startContainer, this.startOffset, sourceRange.endContainer, sourceRange.endOffset); } }, _findBody : function(oNode){ if(!oNode){return null;} while(oNode){ if(oNode.tagName == "BODY"){return oNode;} oNode = nhn.DOMFix.parentNode(oNode); } return null; }, _compareEndPoint : function(oContainerA, iOffsetA, oContainerB, iOffsetB){ return this.oBrowserSelection.compareEndPoints(oContainerA, iOffsetA, oContainerB, iOffsetB); var iIdxA, iIdxB; if(!oContainerA || this._findBody(oContainerA) != this._document.body){ oContainerA = this._document.body; iOffsetA = 0; } if(!oContainerB || this._findBody(oContainerB) != this._document.body){ oContainerB = this._document.body; iOffsetB = 0; } var compareIdx = function(iIdxA, iIdxB){ // iIdxX == -1 when the node is the commonAncestorNode // if iIdxA == -1 // -> [[...]]... // if iIdxB == -1 // -> ...[[...]] if(iIdxB == -1){iIdxB = iIdxA+1;} if(iIdxA < iIdxB){return -1;} if(iIdxA == iIdxB){return 0;} return 1; }; var oCommonAncestor = this._getCommonAncestorContainer(oContainerA, oContainerB); // ================================================================================================================================================ // Move up both containers so that both containers are direct child nodes of the common ancestor node. From there, just compare the offset // Add 0.5 for each contaienrs that has "moved up" since the actual node is wrapped by 1 or more parent nodes and therefore its position is somewhere between idx & idx+1 // NODE1

NODE2

NODE3
// The position of NODE2 in COMMON_ANCESTOR is somewhere between after NODE1(idx1) and before NODE3(idx2), so we let that be 1.5 // container node A in common ancestor container var oNodeA = oContainerA; var oTmpNode = null; if(oNodeA != oCommonAncestor){ while((oTmpNode = nhn.DOMFix.parentNode(oNodeA)) != oCommonAncestor){oNodeA = oTmpNode;} iIdxA = this._getPosIdx(oNodeA)+0.5; }else{ iIdxA = iOffsetA; } // container node B in common ancestor container var oNodeB = oContainerB; if(oNodeB != oCommonAncestor){ while((oTmpNode = nhn.DOMFix.parentNode(oNodeB)) != oCommonAncestor){oNodeB = oTmpNode;} iIdxB = this._getPosIdx(oNodeB)+0.5; }else{ iIdxB = iOffsetB; } return compareIdx(iIdxA, iIdxB); }, _getCommonAncestorContainer : function(oNode1, oNode2){ oNode1 = oNode1 || this.startContainer; oNode2 = oNode2 || this.endContainer; var oComparingNode = oNode2; while(oNode1){ while(oComparingNode){ if(oNode1 == oComparingNode){return oNode1;} oComparingNode = nhn.DOMFix.parentNode(oComparingNode); } oComparingNode = oNode2; oNode1 = nhn.DOMFix.parentNode(oNode1); } return this._document.body; }, deleteContents : function(){ if(this.collapsed){return;} this._splitTextEndNodesOfTheRange(); var aNodes = this._getNodesInRange(); if(aNodes.length < 1){return;} var oPrevNode = aNodes[0].previousSibling; while(oPrevNode && this._isBlankTextNode(oPrevNode)){oPrevNode = oPrevNode.previousSibling;} var oNewStartContainer, iNewOffset = -1; if(!oPrevNode){ oNewStartContainer = nhn.DOMFix.parentNode(aNodes[0]); iNewOffset = 0; } for(var i=0; iA]B // -> []B // without these lines, the result would yeild to // -> []B if(oNewStartContainer == oNode && iNewOffset === 0){ iNewOffset = this._getPosIdx(oNewStartContainer); oNewStartContainer = nhn.DOMFix.parentNode(oNode); } } } if(!oPrevNode){ this.setStart(oNewStartContainer, iNewOffset, true, true); }else{ if(oPrevNode.tagName == "BODY"){ this.setStartBefore(oPrevNode, true); }else{ this.setStartAfter(oPrevNode, true); } } this.collapse(true); }, extractContents : function(){ var oClonedContents = this.cloneContents(); this.deleteContents(); return oClonedContents; }, getInsertBeforeNodes : function(){ var oFirstNode = null; var oParentContainer; if(this.startContainer.nodeType == "3"){ oParentContainer = nhn.DOMFix.parentNode(this.startContainer); if(this.startContainer.nodeValue.length <= this.startOffset){ oFirstNode = this.startContainer.nextSibling; }else{ oFirstNode = this.startContainer.splitText(this.startOffset); } }else{ oParentContainer = this.startContainer; oFirstNode = nhn.DOMFix.childNodes(this.startContainer)[this.startOffset]; } if(!oFirstNode || !nhn.DOMFix.parentNode(oFirstNode)){oFirstNode = null;} return {elParent: oParentContainer, elBefore: oFirstNode}; }, insertNode : function(newNode){ var oInsertBefore = this.getInsertBeforeNodes(); oInsertBefore.elParent.insertBefore(newNode, oInsertBefore.elBefore); this.setStartBefore(newNode); }, selectNode : function(refNode){ this.reset(this._window); this.setStartBefore(refNode); this.setEndAfter(refNode); }, selectNodeContents : function(refNode){ this.reset(this._window); this.setStart(refNode, 0, true); this.setEnd(refNode, nhn.DOMFix.childNodes(refNode).length); }, _endsNodeValidation : function(oNode, iOffset){ if(!oNode || this._findBody(oNode) != this._document.body){throw new Error("INVALID_NODE_TYPE_ERR oNode is not part of current document");} if(oNode.nodeType == 3){ if(iOffset > oNode.nodeValue.length){iOffset = oNode.nodeValue.length;} }else{ if(iOffset > nhn.DOMFix.childNodes(oNode).length){iOffset = nhn.DOMFix.childNodes(oNode).length;} } return iOffset; }, setEnd : function(refNode, offset, bSafe, bNoUpdate){ if(!bSafe){offset = this._endsNodeValidation(refNode, offset);} this.endContainer = refNode; this.endOffset = offset; if(!bNoUpdate){ if(!this.startContainer || this._compareEndPoint(this.startContainer, this.startOffset, this.endContainer, this.endOffset) != -1){ this.collapse(false); }else{ this._updateRangeInfo(); } } }, setEndAfter : function(refNode, bNoUpdate){ if(!refNode){throw new Error("INVALID_NODE_TYPE_ERR in setEndAfter");} if(refNode.tagName == "BODY"){ this.setEnd(refNode, nhn.DOMFix.childNodes(refNode).length, true, bNoUpdate); return; } this.setEnd(nhn.DOMFix.parentNode(refNode), this._getPosIdx(refNode)+1, true, bNoUpdate); }, setEndBefore : function(refNode, bNoUpdate){ if(!refNode){throw new Error("INVALID_NODE_TYPE_ERR in setEndBefore");} if(refNode.tagName == "BODY"){ this.setEnd(refNode, 0, true, bNoUpdate); return; } this.setEnd(nhn.DOMFix.parentNode(refNode), this._getPosIdx(refNode), true, bNoUpdate); }, setStart : function(refNode, offset, bSafe, bNoUpdate){ if(!bSafe){offset = this._endsNodeValidation(refNode, offset);} this.startContainer = refNode; this.startOffset = offset; if(!bNoUpdate){ if(!this.endContainer || this._compareEndPoint(this.startContainer, this.startOffset, this.endContainer, this.endOffset) != -1){ this.collapse(true); }else{ this._updateRangeInfo(); } } }, setStartAfter : function(refNode, bNoUpdate){ if(!refNode){throw new Error("INVALID_NODE_TYPE_ERR in setStartAfter");} if(refNode.tagName == "BODY"){ this.setStart(refNode, nhn.DOMFix.childNodes(refNode).length, true, bNoUpdate); return; } this.setStart(nhn.DOMFix.parentNode(refNode), this._getPosIdx(refNode)+1, true, bNoUpdate); }, setStartBefore : function(refNode, bNoUpdate){ if(!refNode){throw new Error("INVALID_NODE_TYPE_ERR in setStartBefore");} if(refNode.tagName == "BODY"){ this.setStart(refNode, 0, true, bNoUpdate); return; } this.setStart(nhn.DOMFix.parentNode(refNode), this._getPosIdx(refNode), true, bNoUpdate); }, surroundContents : function(newParent){ newParent.appendChild(this.extractContents()); this.insertNode(newParent); this.selectNode(newParent); }, toString : function(){ var oTmpContainer = this._document.createElement("DIV"); oTmpContainer.appendChild(this.cloneContents()); return oTmpContainer.textContent || oTmpContainer.innerText || ""; }, // this.oBrowserSelection.getCommonAncestorContainer which uses browser's built-in API runs faster but may return an incorrect value. // Call this function to fix the problem. // // In IE, the built-in API would return an incorrect value when, // 1. commonAncestorContainer is not selectable // AND // 2. The selected area will look the same when its child node is selected // eg) // when

TEST

is selected, TEST will be returned as commonAncestorContainer fixCommonAncestorContainer : function(){ if(!jindo.$Agent().navigator().ie){ return; } this.commonAncestorContainer = this._getCommonAncestorContainer(); }, _isBlankTextNode : function(oNode){ if(oNode.nodeType == 3 && oNode.nodeValue == ""){return true;} return false; }, _isAllChildBlankText : function(elNode){ for(var i=0, nLen=elNode.childNodes.length; i // // // // // // // // // // // // , it's easier to compare the position of B and D rather than C and F because they are siblings // // If the range were collapsed, oActualEndNode will precede oActualStartNode by doing this oActualStartNode = this._getNextNode(this._getPrevNode(oActualStartNode)); oActualEndNode = this._getPrevNode(this._getNextNode(oActualEndNode)); if(oActualStartNode && oActualEndNode && oActualEndNode.tagName != "BODY" && (this._getNextNode(oActualEndNode) == oActualStartNode || (oActualEndNode == oActualStartNode && this._isBlankTextNode(oActualEndNode))) ){ bCollapsed = true; } } return bCollapsed; }, _splitTextEndNodesOfTheRange : function(){ var oEndPoints = this._splitTextEndNodes({oStartContainer: this.startContainer, iStartOffset: this.startOffset, oEndContainer: this.endContainer, iEndOffset: this.endOffset}); this.startContainer = oEndPoints.oStartContainer; this.startOffset = oEndPoints.iStartOffset; this.endContainer = oEndPoints.oEndContainer; this.endOffset = oEndPoints.iEndOffset; }, _splitTextEndNodes : function(oEndPoints){ oEndPoints = this._splitStartTextNode(oEndPoints); oEndPoints = this._splitEndTextNode(oEndPoints); return oEndPoints; }, _splitStartTextNode : function(oEndPoints){ var oStartContainer = oEndPoints.oStartContainer; var iStartOffset = oEndPoints.iStartOffset; var oEndContainer = oEndPoints.oEndContainer; var iEndOffset = oEndPoints.iEndOffset; if(!oStartContainer){return oEndPoints;} if(oStartContainer.nodeType != 3){return oEndPoints;} if(iStartOffset === 0){return oEndPoints;} if(oStartContainer.nodeValue.length <= iStartOffset){return oEndPoints;} var oLastPart = oStartContainer.splitText(iStartOffset); if(oStartContainer == oEndContainer){ iEndOffset -= iStartOffset; oEndContainer = oLastPart; } oStartContainer = oLastPart; iStartOffset = 0; return {oStartContainer: oStartContainer, iStartOffset: iStartOffset, oEndContainer: oEndContainer, iEndOffset: iEndOffset}; }, _splitEndTextNode : function(oEndPoints){ var oStartContainer = oEndPoints.oStartContainer; var iStartOffset = oEndPoints.iStartOffset; var oEndContainer = oEndPoints.oEndContainer; var iEndOffset = oEndPoints.iEndOffset; if(!oEndContainer){return oEndPoints;} if(oEndContainer.nodeType != 3){return oEndPoints;} if(iEndOffset >= oEndContainer.nodeValue.length){return oEndPoints;} if(iEndOffset === 0){return oEndPoints;} oEndContainer.splitText(iEndOffset); return {oStartContainer: oStartContainer, iStartOffset: iStartOffset, oEndContainer: oEndContainer, iEndOffset: iEndOffset}; }, _getNodesInRange : function(){ if(this.collapsed){return [];} var oStartNode = this._getActualStartNode(this.startContainer, this.startOffset); var oEndNode = this._getActualEndNode(this.endContainer, this.endOffset); return this._getNodesBetween(oStartNode, oEndNode); }, _getActualStartNode : function(oStartContainer, iStartOffset){ var oStartNode = oStartContainer; if(oStartContainer.nodeType == 3){ if(iStartOffset >= oStartContainer.nodeValue.length){ oStartNode = this._getNextNode(oStartContainer); if(oStartNode.tagName == "BODY"){oStartNode = null;} }else{ oStartNode = oStartContainer; } }else{ if(iStartOffset < nhn.DOMFix.childNodes(oStartContainer).length){ oStartNode = nhn.DOMFix.childNodes(oStartContainer)[iStartOffset]; }else{ oStartNode = this._getNextNode(oStartContainer); if(oStartNode.tagName == "BODY"){oStartNode = null;} } } return oStartNode; }, _getActualEndNode : function(oEndContainer, iEndOffset){ var oEndNode = oEndContainer; if(iEndOffset === 0){ oEndNode = this._getPrevNode(oEndContainer); if(oEndNode.tagName == "BODY"){oEndNode = null;} }else if(oEndContainer.nodeType == 3){ oEndNode = oEndContainer; }else{ oEndNode = nhn.DOMFix.childNodes(oEndContainer)[iEndOffset-1]; } return oEndNode; }, _getNextNode : function(oNode){ if(!oNode || oNode.tagName == "BODY"){return this._document.body;} if(oNode.nextSibling){return oNode.nextSibling;} return this._getNextNode(nhn.DOMFix.parentNode(oNode)); }, _getPrevNode : function(oNode){ if(!oNode || oNode.tagName == "BODY"){return this._document.body;} if(oNode.previousSibling){return oNode.previousSibling;} return this._getPrevNode(nhn.DOMFix.parentNode(oNode)); }, // includes partially selected // for
, _getNodesBetween(b, c) will yield to b, "a" and c _getNodesBetween : function(oStartNode, oEndNode){ var aNodesBetween = []; this._nNodesBetweenLen = 0; if(!oStartNode || !oEndNode){return aNodesBetween;} // IE may throw an exception on "oCurNode = oCurNode.nextSibling;" when oCurNode is 'invalid', not null or undefined but somehow 'invalid'. // It happened during browser's build-in UNDO with control range selected(table). try{ this._recurGetNextNodesUntil(oStartNode, oEndNode, aNodesBetween); }catch(e){ return []; } return aNodesBetween; }, _recurGetNextNodesUntil : function(oNode, oEndNode, aNodesBetween){ if(!oNode){return false;} if(!this._recurGetChildNodesUntil(oNode, oEndNode, aNodesBetween)){return false;} var oNextToChk = oNode.nextSibling; while(!oNextToChk){ if(!(oNode = nhn.DOMFix.parentNode(oNode))){return false;} aNodesBetween[this._nNodesBetweenLen++] = oNode; if(oNode == oEndNode){return false;} oNextToChk = oNode.nextSibling; } return this._recurGetNextNodesUntil(oNextToChk, oEndNode, aNodesBetween); }, _recurGetChildNodesUntil : function(oNode, oEndNode, aNodesBetween){ if(!oNode){return false;} var bEndFound = false; var oCurNode = oNode; if(oCurNode.firstChild){ oCurNode = oCurNode.firstChild; while(oCurNode){ if(!this._recurGetChildNodesUntil(oCurNode, oEndNode, aNodesBetween)){ bEndFound = true; break; } oCurNode = oCurNode.nextSibling; } } aNodesBetween[this._nNodesBetweenLen++] = oNode; if(bEndFound){return false;} if(oNode == oEndNode){return false;} return true; } }); nhn.W3CDOMRange.START_TO_START = 0; nhn.W3CDOMRange.START_TO_END = 1; nhn.W3CDOMRange.END_TO_END = 2; nhn.W3CDOMRange.END_TO_START = 3; /** * @fileOverview This file contains a cross-browser function that implements all of the W3C's DOM Range specification and some more * @name HuskyRange.js */ nhn.HuskyRange = jindo.$Class({ setWindow : function(win){ this.reset(win || window); }, $init : function(win){ this.HUSKY_BOOMARK_START_ID_PREFIX = "husky_bookmark_start_"; this.HUSKY_BOOMARK_END_ID_PREFIX = "husky_bookmark_end_"; this.sBlockElement = "P|DIV|LI|H[1-6]|PRE"; this.sBlockContainer = "BODY|TABLE|TH|TR|TD|UL|OL|BLOCKQUOTE|FORM"; this.rxBlockElement = new RegExp("^("+this.sBlockElement+")$"); this.rxBlockContainer = new RegExp("^("+this.sBlockContainer+")$"); this.rxLineBreaker = new RegExp("^("+this.sBlockElement+"|"+this.sBlockContainer+")$"); this.setWindow(win); }, select : function(){ try{ this.oBrowserSelection.selectRange(this); }catch(e){} }, setFromSelection : function(iNum){ this.setRange(this.oBrowserSelection.getRangeAt(iNum), true); }, setRange : function(oW3CRange, bSafe){ this.reset(this._window); this.setStart(oW3CRange.startContainer, oW3CRange.startOffset, bSafe, true); this.setEnd(oW3CRange.endContainer, oW3CRange.endOffset, bSafe); }, setEndNodes : function(oSNode, oENode){ this.reset(this._window); this.setEndAfter(oENode, true); this.setStartBefore(oSNode); }, splitTextAtBothEnds : function(){ this._splitTextEndNodesOfTheRange(); }, getStartNode : function(){ if(this.collapsed){ if(this.startContainer.nodeType == 3){ if(this.startOffset === 0){return null;} if(this.startContainer.nodeValue.length <= this.startOffset){return null;} return this.startContainer; } return null; } if(this.startContainer.nodeType == 3){ if(this.startOffset >= this.startContainer.nodeValue.length){return this._getNextNode(this.startContainer);} return this.startContainer; }else{ if(this.startOffset >= nhn.DOMFix.childNodes(this.startContainer).length){return this._getNextNode(this.startContainer);} return nhn.DOMFix.childNodes(this.startContainer)[this.startOffset]; } }, getEndNode : function(){ if(this.collapsed){return this.getStartNode();} if(this.endContainer.nodeType == 3){ if(this.endOffset === 0){return this._getPrevNode(this.endContainer);} return this.endContainer; }else{ if(this.endOffset === 0){return this._getPrevNode(this.endContainer);} return nhn.DOMFix.childNodes(this.endContainer)[this.endOffset-1]; } }, getNodeAroundRange : function(bBefore, bStrict){ if(!this.collapsed){return this.getStartNode();} if(this.startContainer && this.startContainer.nodeType == 3){return this.startContainer;} //if(this.collapsed && this.startContainer && this.startContainer.nodeType == 3) return this.startContainer; //if(!this.collapsed || (this.startContainer && this.startContainer.nodeType == 3)) return this.getStartNode(); var oBeforeRange, oAfterRange, oResult; if(this.startOffset >= nhn.DOMFix.childNodes(this.startContainer).length){ oAfterRange = this._getNextNode(this.startContainer); }else{ oAfterRange = nhn.DOMFix.childNodes(this.startContainer)[this.startOffset]; } if(this.endOffset === 0){ oBeforeRange = this._getPrevNode(this.endContainer); }else{ oBeforeRange = nhn.DOMFix.childNodes(this.endContainer)[this.endOffset-1]; } if(bBefore){ oResult = oBeforeRange; if(!oResult && !bStrict){oResult = oAfterRange;} }else{ oResult = oAfterRange; if(!oResult && !bStrict){oResult = oBeforeRange;} } return oResult; }, _getXPath : function(elNode){ var sXPath = ""; while(elNode && elNode.nodeType == 1){ sXPath = "/" + elNode.tagName+"["+this._getPosIdx4XPath(elNode)+"]" + sXPath; elNode = nhn.DOMFix.parentNode(elNode); } return sXPath; }, _getPosIdx4XPath : function(refNode){ var idx = 0; for(var node = refNode.previousSibling; node; node = node.previousSibling){ if(node.tagName == refNode.tagName){idx++;} } return idx; }, // this was written specifically for XPath Bookmark and it may not perform correctly for general purposes _evaluateXPath : function(sXPath, oDoc){ sXPath = sXPath.substring(1, sXPath.length-1); var aXPath = sXPath.split(/\//); var elNode = oDoc.body; for(var i=2; i -1 && elContainer){ var aChildNodes = nhn.DOMFix.childNodes(elContainer); var elNode = null; var nIdx = nTextNodeIdx; var nOffsetLeft = nOffset; while((elNode = aChildNodes[nIdx]) && elNode.nodeType == 3 && elNode.nodeValue.length < nOffsetLeft){ nOffsetLeft -= elNode.nodeValue.length; nIdx++; } elContainer = nhn.DOMFix.childNodes(elContainer)[nIdx]; nOffset = nOffsetLeft; } if(!elContainer){ elContainer = this._document.body; nOffset = 0; } return {elContainer: elContainer, nOffset: nOffset}; }, // this was written specifically for XPath Bookmark and it may not perform correctly for general purposes getXPathBookmark : function(){ var nTextNodeIdx1 = -1; var htEndPt1 = {elContainer: this.startContainer, nOffset: this.startOffset}; var elNode1 = this.startContainer; if(elNode1.nodeType == 3){ htEndPt1 = this._getFixedStartTextNode(); nTextNodeIdx1 = this._getPosIdx(htEndPt1.elContainer); elNode1 = nhn.DOMFix.parentNode(elNode1); } var sXPathNode1 = this._getXPath(elNode1); var oBookmark1 = {sXPath:sXPathNode1, nTextNodeIdx:nTextNodeIdx1, nOffset: htEndPt1.nOffset}; if(this.collapsed){ var oBookmark2 = {sXPath:sXPathNode1, nTextNodeIdx:nTextNodeIdx1, nOffset: htEndPt1.nOffset}; }else{ var nTextNodeIdx2 = -1; var htEndPt2 = {elContainer: this.endContainer, nOffset: this.endOffset}; var elNode2 = this.endContainer; if(elNode2.nodeType == 3){ htEndPt2 = this._getFixedEndTextNode(); nTextNodeIdx2 = this._getPosIdx(htEndPt2.elContainer); elNode2 = nhn.DOMFix.parentNode(elNode2); } var sXPathNode2 = this._getXPath(elNode2); var oBookmark2 = {sXPath:sXPathNode2, nTextNodeIdx:nTextNodeIdx2, nOffset: htEndPt2.nOffset}; } return [oBookmark1, oBookmark2]; }, moveToXPathBookmark : function(aBookmark){ if(!aBookmark){return false;} var oBookmarkInfo1 = this._evaluateXPathBookmark(aBookmark[0]); var oBookmarkInfo2 = this._evaluateXPathBookmark(aBookmark[1]); if(!oBookmarkInfo1["elContainer"] || !oBookmarkInfo2["elContainer"]){return;} this.startContainer = oBookmarkInfo1["elContainer"]; this.startOffset = oBookmarkInfo1["nOffset"]; this.endContainer = oBookmarkInfo2["elContainer"]; this.endOffset = oBookmarkInfo2["nOffset"]; return true; }, _getFixedTextContainer : function(elNode, nOffset){ while(elNode && elNode.nodeType == 3 && elNode.previousSibling && elNode.previousSibling.nodeType == 3){ nOffset += elNode.previousSibling.nodeValue.length; elNode = elNode.previousSibling; } return {elContainer:elNode, nOffset:nOffset}; }, _getFixedStartTextNode : function(){ return this._getFixedTextContainer(this.startContainer, this.startOffset); }, _getFixedEndTextNode : function(){ return this._getFixedTextContainer(this.endContainer, this.endOffset); }, placeStringBookmark : function(){ if(this.collapsed || jindo.$Agent().navigator().ie || jindo.$Agent().navigator().firefox){ return this.placeStringBookmark_NonWebkit(); }else{ return this.placeStringBookmark_Webkit(); } }, placeStringBookmark_NonWebkit : function(){ var sTmpId = (new Date()).getTime(); var oInsertionPoint = this.cloneRange(); oInsertionPoint.collapseToEnd(); var oEndMarker = this._document.createElement("SPAN"); oEndMarker.id = this.HUSKY_BOOMARK_END_ID_PREFIX+sTmpId; oInsertionPoint.insertNode(oEndMarker); var oInsertionPoint = this.cloneRange(); oInsertionPoint.collapseToStart(); var oStartMarker = this._document.createElement("SPAN"); oStartMarker.id = this.HUSKY_BOOMARK_START_ID_PREFIX+sTmpId; oInsertionPoint.insertNode(oStartMarker); // IE에서 빈 SPAN의 앞뒤로 커서가 이동하지 않아 문제가 발생 할 수 있어, 보이지 않는 특수 문자를 임시로 넣어 줌. if(jindo.$Agent().navigator().ie){ // SPAN의 위치가 TD와 TD 사이에 있을 경우, 텍스트 삽입 시 알수 없는 오류가 발생한다. // TD와 TD사이에서는 텍스트 삽입이 필요 없음으로 그냥 try/catch로 처리 try{ oStartMarker.innerHTML = unescape("%uFEFF"); }catch(e){} try{ oEndMarker.innerHTML = unescape("%uFEFF"); }catch(e){} } this.moveToBookmark(sTmpId); return sTmpId; }, placeStringBookmark_Webkit : function(){ var sTmpId = (new Date()).getTime(); var elInsertBefore, elInsertParent; // Do not insert the bookmarks between TDs as it will break the rendering in Chrome/Safari // -> modify the insertion position from [abc]abc to [abc]abc var oInsertionPoint = this.cloneRange(); oInsertionPoint.collapseToEnd(); elInsertBefore = this._document.createTextNode(""); oInsertionPoint.insertNode(elInsertBefore); elInsertParent = elInsertBefore.parentNode; if(elInsertBefore.previousSibling && elInsertBefore.previousSibling.tagName == "TD"){ elInsertParent = elInsertBefore.previousSibling; elInsertBefore = null; } var oEndMarker = this._document.createElement("SPAN"); oEndMarker.id = this.HUSKY_BOOMARK_END_ID_PREFIX+sTmpId; elInsertParent.insertBefore(oEndMarker, elInsertBefore); var oInsertionPoint = this.cloneRange(); oInsertionPoint.collapseToStart(); elInsertBefore = this._document.createTextNode(""); oInsertionPoint.insertNode(elInsertBefore); elInsertParent = elInsertBefore.parentNode; if(elInsertBefore.nextSibling && elInsertBefore.nextSibling.tagName == "TD"){ elInsertParent = elInsertBefore.nextSibling; elInsertBefore = elInsertParent.firstChild; } var oStartMarker = this._document.createElement("SPAN"); oStartMarker.id = this.HUSKY_BOOMARK_START_ID_PREFIX+sTmpId; elInsertParent.insertBefore(oStartMarker, elInsertBefore); //elInsertBefore.parentNode.removeChild(elInsertBefore); this.moveToBookmark(sTmpId); return sTmpId; }, cloneRange : function(){ return this._copyRange(new nhn.HuskyRange(this._window)); }, moveToBookmark : function(vBookmark){ if(typeof(vBookmark) != "object"){ return this.moveToStringBookmark(vBookmark); }else{ return this.moveToXPathBookmark(vBookmark); } }, getStringBookmark : function(sBookmarkID, bEndBookmark){ if(bEndBookmark){ return this._document.getElementById(this.HUSKY_BOOMARK_END_ID_PREFIX+sBookmarkID); }else{ return this._document.getElementById(this.HUSKY_BOOMARK_START_ID_PREFIX+sBookmarkID); } }, moveToStringBookmark : function(sBookmarkID, bIncludeBookmark){ var oStartMarker = this.getStringBookmark(sBookmarkID); var oEndMarker = this.getStringBookmark(sBookmarkID, true); if(!oStartMarker || !oEndMarker){return false;} this.reset(this._window); if(bIncludeBookmark){ this.setEndAfter(oEndMarker); this.setStartBefore(oStartMarker); }else{ this.setEndBefore(oEndMarker); this.setStartAfter(oStartMarker); } return true; }, removeStringBookmark : function(sBookmarkID){ /* var oStartMarker = this._document.getElementById(this.HUSKY_BOOMARK_START_ID_PREFIX+sBookmarkID); var oEndMarker = this._document.getElementById(this.HUSKY_BOOMARK_END_ID_PREFIX+sBookmarkID); if(oStartMarker) nhn.DOMFix.parentNode(oStartMarker).removeChild(oStartMarker); if(oEndMarker) nhn.DOMFix.parentNode(oEndMarker).removeChild(oEndMarker); */ this._removeAll(this.HUSKY_BOOMARK_START_ID_PREFIX+sBookmarkID); this._removeAll(this.HUSKY_BOOMARK_END_ID_PREFIX+sBookmarkID); }, _removeAll : function(sID){ var elNode; while((elNode = this._document.getElementById(sID))){ nhn.DOMFix.parentNode(elNode).removeChild(elNode); } }, collapseToStart : function(){ this.collapse(true); }, collapseToEnd : function(){ this.collapse(false); }, createAndInsertNode : function(sTagName){ var tmpNode = this._document.createElement(sTagName); this.insertNode(tmpNode); return tmpNode; }, getNodes : function(bSplitTextEndNodes, fnFilter){ if(bSplitTextEndNodes){this._splitTextEndNodesOfTheRange();} var aAllNodes = this._getNodesInRange(); var aFilteredNodes = []; if(!fnFilter){return aAllNodes;} for(var i=0; i= 0){return true;} if(bIncludePartlySelected){ if(startToEnd == 1){return false;} if(endToStart == -1){return false;} return true; } return false; }, isNodeInRange : function(oNode, bIncludePartlySelected, bContentOnly){ var oTmpRange = new nhn.HuskyRange(this._window); if(bContentOnly && oNode.firstChild){ oTmpRange.setStartBefore(oNode.firstChild); oTmpRange.setEndAfter(oNode.lastChild); }else{ oTmpRange.selectNode(oNode); } return this.isRangeInRange(oTmpRange, bIncludePartlySelected); }, pasteText : function(sText){ this.pasteHTML(sText.replace(/&/g, "&").replace(//g, ">").replace(/ /g, " ").replace(/"/g, """)); }, pasteHTML : function(sHTML){ var oTmpDiv = this._document.createElement("DIV"); oTmpDiv.innerHTML = sHTML; if(!oTmpDiv.firstChild){ this.deleteContents(); return; } var oFirstNode = oTmpDiv.firstChild; var oLastNode = oTmpDiv.lastChild; var clone = this.cloneRange(); var sBM = clone.placeStringBookmark(); this.collapseToStart(); while(oTmpDiv.lastChild){this.insertNode(oTmpDiv.lastChild);} this.setEndNodes(oFirstNode, oLastNode); // delete the content later as deleting it first may mass up the insertion point // eg)

[A]BCD

---paste O---> O

BCD

clone.moveToBookmark(sBM); clone.deleteContents(); clone.removeStringBookmark(sBM); }, toString : function(){ this.toString = nhn.W3CDOMRange.prototype.toString; return this.toString(); }, toHTMLString : function(){ var oTmpContainer = this._document.createElement("DIV"); oTmpContainer.appendChild(this.cloneContents()); return oTmpContainer.innerHTML; }, findAncestorByTagName : function(sTagName){ var oNode = this.commonAncestorContainer; while(oNode && oNode.tagName != sTagName){oNode = nhn.DOMFix.parentNode(oNode);} return oNode; }, selectNodeContents : function(oNode){ if(!oNode){return;} var oFirstNode = oNode.firstChild?oNode.firstChild:oNode; var oLastNode = oNode.lastChild?oNode.lastChild:oNode; this.reset(this._window); if(oFirstNode.nodeType == 3){ this.setStart(oFirstNode, 0, true); }else{ this.setStartBefore(oFirstNode); } if(oLastNode.nodeType == 3){ this.setEnd(oLastNode, oLastNode.nodeValue.length, true); }else{ this.setEndAfter(oLastNode); } }, /** * 노드의 취소선/밑줄 정보를 확인한다 * 관련 BTS [SMARTEDITORSUS-26] * @param {Node} oNode 취소선/밑줄을 확인할 노드 * @param {String} sValue textDecoration 정보 * @see nhn.HuskyRange#_checkTextDecoration */ _hasTextDecoration : function(oNode, sValue){ if(!oNode || !oNode.style){ return false; } if(oNode.style.textDecoration.indexOf(sValue) > -1){ return true; } if(sValue === "underline" && oNode.tagName === "U"){ return true; } if(sValue === "line-through" && (oNode.tagName === "S" || oNode.tagName === "STRIKE")){ return true; } return false; }, /** * 노드에 취소선/밑줄을 적용한다 * 관련 BTS [SMARTEDITORSUS-26] * [FF] 노드의 Style 에 textDecoration 을 추가한다 * [FF 외] U/STRIKE 태그를 추가한다 * @param {Node} oNode 취소선/밑줄을 적용할 노드 * @param {String} sValue textDecoration 정보 * @see nhn.HuskyRange#_checkTextDecoration */ _setTextDecoration : function(oNode, sValue){ if (jindo.$Agent().navigator().firefox) { // FF oNode.style.textDecoration = (oNode.style.textDecoration) ? oNode.style.textDecoration + " " + sValue : sValue; } else{ if(sValue === "underline"){ oNode.innerHTML = "" + oNode.innerHTML + "" }else if(sValue === "line-through"){ oNode.innerHTML = "" + oNode.innerHTML + "" } } }, /** * 인자로 전달받은 노드 상위의 취소선/밑줄 정보를 확인하여 노드에 적용한다 * 관련 BTS [SMARTEDITORSUS-26] * @param {Node} oNode 취소선/밑줄을 적용할 노드 */ _checkTextDecoration : function(oNode){ if(oNode.tagName !== "SPAN"){ return; } var bUnderline = false, bLineThrough = false, sTextDecoration = "", oParentNode = null; oChildNode = oNode.firstChild; /* check child */ while(oChildNode){ if(oChildNode.nodeType === 1){ bUnderline = (bUnderline || oChildNode.tagName === "U"); bLineThrough = (bLineThrough || oChildNode.tagName === "S" || oChildNode.tagName === "STRIKE"); } if(bUnderline && bLineThrough){ return; } oChildNode = oChildNode.nextSibling; } oParentNode = nhn.DOMFix.parentNode(oNode); /* check parent */ while(oParentNode && oParentNode.tagName !== "BODY"){ if(oParentNode.nodeType !== 1){ oParentNode = nhn.DOMFix.parentNode(oParentNode); continue; } if(!bUnderline && this._hasTextDecoration(oParentNode, "underline")){ bUnderline = true; this._setTextDecoration(oNode, "underline"); // set underline } if(!bLineThrough && this._hasTextDecoration(oParentNode, "line-through")){ bLineThrough = true; this._setTextDecoration(oNode, "line-through"); // set line-through } if(bUnderline && bLineThrough){ return; } oParentNode = nhn.DOMFix.parentNode(oParentNode); } }, /** * Range에 속한 노드들에 스타일을 적용한다 * @param {Object} oStyle 적용할 스타일을 가지는 Object (예) 글꼴 색 적용의 경우 { color : "#0075c8" } * @param {Object} [oAttribute] 적용할 속성을 가지는 Object (예) 맞춤범 검사의 경우 { _sm2_spchk: "강남콩", class: "se2_check_spell" } * @param {String} [sNewSpanMarker] 새로 추가된 SPAN 노드를 나중에 따로 처리해야하는 경우 마킹을 위해 사용하는 문자열 * @param {Boolean} [bIncludeLI] LI 도 스타일 적용에 포함할 것인지의 여부 [COM-1051] _getStyleParentNodes 메서드 참고하기 * @param {Boolean} [bCheckTextDecoration] 취소선/밑줄 처리를 적용할 것인지 여부 [SMARTEDITORSUS-26] _setTextDecoration 메서드 참고하기 */ styleRange : function(oStyle, oAttribute, sNewSpanMarker, bIncludeLI, bCheckTextDecoration){ var aStyleParents = this.aStyleParents = this._getStyleParentNodes(sNewSpanMarker, bIncludeLI); if(aStyleParents.length < 1){return;} var sName, sValue; for(var i=0; i= 0)){ oSNode = this.getNodeAroundRange(false, true); oENode = this.getNodeAroundRange(false, true); oStart = this._getLineStartInfo(oSNode); oEnd = this._getLineEndInfo(oENode); } } return {oStart: oStart, oEnd: oEnd}; } }).extend(nhn.W3CDOMRange); /** * @fileOverview This file contains cross-browser selection function * @name BrowserSelection.js */ nhn.BrowserSelection = function(win){ this.init = function(win){ this._window = win || window; this._document = this._window.document; }; this.init(win); // [SMARTEDITORSUS-888] IE9 이후로 document.createRange 를 지원 /* var oAgentInfo = jindo.$Agent().navigator(); if(oAgentInfo.ie){ nhn.BrowserSelectionImpl_IE.apply(this); }else{ nhn.BrowserSelectionImpl_FF.apply(this); }*/ if(!!this._document.createRange){ nhn.BrowserSelectionImpl_FF.apply(this); }else{ nhn.BrowserSelectionImpl_IE.apply(this); } this.selectRange = function(oRng){ this.selectNone(); this.addRange(oRng); }; this.selectionLoaded = true; if(!this._oSelection){this.selectionLoaded = false;} }; nhn.BrowserSelectionImpl_FF = function(){ this._oSelection = this._window.getSelection(); this.getRangeAt = function(iNum){ iNum = iNum || 0; try{ var oFFRange = this._oSelection.getRangeAt(iNum); }catch(e){return new nhn.W3CDOMRange(this._window);} return this._FFRange2W3CRange(oFFRange); }; this.addRange = function(oW3CRange){ var oFFRange = this._W3CRange2FFRange(oW3CRange); this._oSelection.addRange(oFFRange); }; this.selectNone = function(){ this._oSelection.removeAllRanges(); }; this.getCommonAncestorContainer = function(oW3CRange){ var oFFRange = this._W3CRange2FFRange(oW3CRange); return oFFRange.commonAncestorContainer; }; this.isCollapsed = function(oW3CRange){ var oFFRange = this._W3CRange2FFRange(oW3CRange); return oFFRange.collapsed; }; this.compareEndPoints = function(elContainerA, nOffsetA, elContainerB, nOffsetB){ var oFFRangeA = this._document.createRange(); var oFFRangeB = this._document.createRange(); oFFRangeA.setStart(elContainerA, nOffsetA); oFFRangeB.setStart(elContainerB, nOffsetB); oFFRangeA.collapse(true); oFFRangeB.collapse(true); try{ return oFFRangeA.compareBoundaryPoints(1, oFFRangeB); }catch(e){ return 1; } }; this._FFRange2W3CRange = function(oFFRange){ var oW3CRange = new nhn.W3CDOMRange(this._window); oW3CRange.setStart(oFFRange.startContainer, oFFRange.startOffset, true); oW3CRange.setEnd(oFFRange.endContainer, oFFRange.endOffset, true); return oW3CRange; }; this._W3CRange2FFRange = function(oW3CRange){ var oFFRange = this._document.createRange(); oFFRange.setStart(oW3CRange.startContainer, oW3CRange.startOffset); oFFRange.setEnd(oW3CRange.endContainer, oW3CRange.endOffset); return oFFRange; }; }; nhn.BrowserSelectionImpl_IE = function(){ this._oSelection = this._document.selection; this.oLastRange = { oBrowserRange : null, elStartContainer : null, nStartOffset : -1, elEndContainer : null, nEndOffset : -1 }; this._updateLastRange = function(oBrowserRange, oW3CRange){ this.oLastRange.oBrowserRange = oBrowserRange; this.oLastRange.elStartContainer = oW3CRange.startContainer; this.oLastRange.nStartOffset = oW3CRange.startOffset; this.oLastRange.elEndContainer = oW3CRange.endContainer; this.oLastRange.nEndOffset = oW3CRange.endOffset; }; this.getRangeAt = function(iNum){ iNum = iNum || 0; var oW3CRange, oBrowserRange; if(this._oSelection.type == "Control"){ oW3CRange = new nhn.W3CDOMRange(this._window); var oSelectedNode = this._oSelection.createRange().item(iNum); // if the selction occurs in a different document, ignore if(!oSelectedNode || oSelectedNode.ownerDocument != this._document){return oW3CRange;} oW3CRange.selectNode(oSelectedNode); return oW3CRange; }else{ //oBrowserRange = this._oSelection.createRangeCollection().item(iNum); oBrowserRange = this._oSelection.createRange(); var oSelectedNode = oBrowserRange.parentElement(); // if the selction occurs in a different document, ignore if(!oSelectedNode || oSelectedNode.ownerDocument != this._document){ oW3CRange = new nhn.W3CDOMRange(this._window); return oW3CRange; } oW3CRange = this._IERange2W3CRange(oBrowserRange); return oW3CRange; } }; this.addRange = function(oW3CRange){ var oIERange = this._W3CRange2IERange(oW3CRange); oIERange.select(); }; this.selectNone = function(){ this._oSelection.empty(); }; this.getCommonAncestorContainer = function(oW3CRange){ return this._W3CRange2IERange(oW3CRange).parentElement(); }; this.isCollapsed = function(oW3CRange){ var oRange = this._W3CRange2IERange(oW3CRange); var oRange2 = oRange.duplicate(); oRange2.collapse(); return oRange.isEqual(oRange2); }; this.compareEndPoints = function(elContainerA, nOffsetA, elContainerB, nOffsetB){ var oIERangeA, oIERangeB; if(elContainerA === this.oLastRange.elStartContainer && nOffsetA === this.oLastRange.nStartOffset){ oIERangeA = this.oLastRange.oBrowserRange.duplicate(); oIERangeA.collapse(true); }else{ if(elContainerA === this.oLastRange.elEndContainer && nOffsetA === this.oLastRange.nEndOffset){ oIERangeA = this.oLastRange.oBrowserRange.duplicate(); oIERangeA.collapse(false); }else{ oIERangeA = this._getIERangeAt(elContainerA, nOffsetA); } } if(elContainerB === this.oLastRange.elStartContainer && nOffsetB === this.oLastRange.nStartOffset){ oIERangeB = this.oLastRange.oBrowserRange.duplicate(); oIERangeB.collapse(true); }else{ if(elContainerB === this.oLastRange.elEndContainer && nOffsetB === this.oLastRange.nEndOffset){ oIERangeB = this.oLastRange.oBrowserRange.duplicate(); oIERangeB.collapse(false); }else{ oIERangeB = this._getIERangeAt(elContainerB, nOffsetB); } } return oIERangeA.compareEndPoints("StartToStart", oIERangeB); }; this._W3CRange2IERange = function(oW3CRange){ if(this.oLastRange.elStartContainer === oW3CRange.startContainer && this.oLastRange.nStartOffset === oW3CRange.startOffset && this.oLastRange.elEndContainer === oW3CRange.endContainer && this.oLastRange.nEndOffset === oW3CRange.endOffset){ return this.oLastRange.oBrowserRange; } var oStartIERange = this._getIERangeAt(oW3CRange.startContainer, oW3CRange.startOffset); var oEndIERange = this._getIERangeAt(oW3CRange.endContainer, oW3CRange.endOffset); oStartIERange.setEndPoint("EndToEnd", oEndIERange); this._updateLastRange(oStartIERange, oW3CRange); return oStartIERange; }; this._getIERangeAt = function(oW3CContainer, iW3COffset){ var oIERange = this._document.body.createTextRange(); var oEndPointInfoForIERange = this._getSelectableNodeAndOffsetForIE(oW3CContainer, iW3COffset); var oSelectableNode = oEndPointInfoForIERange.oSelectableNodeForIE; var iIEOffset = oEndPointInfoForIERange.iOffsetForIE; oIERange.moveToElementText(oSelectableNode); oIERange.collapse(oEndPointInfoForIERange.bCollapseToStart); oIERange.moveStart("character", iIEOffset); return oIERange; }; this._getSelectableNodeAndOffsetForIE = function(oW3CContainer, iW3COffset){ // var oIERange = this._document.body.createTextRange(); var oNonTextNode = null; var aChildNodes = null; var iNumOfLeftNodesToCount = 0; if(oW3CContainer.nodeType == 3){ oNonTextNode = nhn.DOMFix.parentNode(oW3CContainer); aChildNodes = nhn.DOMFix.childNodes(oNonTextNode); iNumOfLeftNodesToCount = aChildNodes.length; }else{ oNonTextNode = oW3CContainer; aChildNodes = nhn.DOMFix.childNodes(oNonTextNode); //iNumOfLeftNodesToCount = iW3COffset; iNumOfLeftNodesToCount = (iW3COffset=0){break;} oPrevNonTextNode = aChildNodes[i]; } var pointRangeIdx = i; if(pointRangeIdx !== 0 && aChildNodes[pointRangeIdx-1].nodeType == 3){ var oRgTextStart = this._document.body.createTextRange(); var oCurTextNode = null; if(oPrevNonTextNode){ oRgTextStart.moveToElementText(oPrevNonTextNode); oRgTextStart.collapse(false); oCurTextNode = oPrevNonTextNode.nextSibling; }else{ oRgTextStart.moveToElementText(oContainer); oRgTextStart.collapse(true); oCurTextNode = oContainer.firstChild; } var oRgTextsUpToThePoint = oRgOrigPoint.duplicate(); oRgTextsUpToThePoint.setEndPoint("StartToStart", oRgTextStart); var textCount = oRgTextsUpToThePoint.text.replace(/[\r\n]/g,"").length; while(textCount > oCurTextNode.nodeValue.length && oCurTextNode.nextSibling){ textCount -= oCurTextNode.nodeValue.length; oCurTextNode = oCurTextNode.nextSibling; } // this will enforce IE to re-reference oCurTextNode var oTmp = oCurTextNode.nodeValue; if(bStartPt && oCurTextNode.nextSibling && oCurTextNode.nextSibling.nodeType == 3 && textCount == oCurTextNode.nodeValue.length){ textCount -= oCurTextNode.nodeValue.length; oCurTextNode = oCurTextNode.nextSibling; } oContainer = oCurTextNode; offset = textCount; }else{ oContainer = oRgOrigPoint.parentElement(); offset = pointRangeIdx; } return {"oContainer" : oContainer, "iOffset" : offset}; }; }; nhn.DOMFix = new (jindo.$Class({ $init : function(){ if(jindo.$Agent().navigator().ie || jindo.$Agent().navigator().opera){ this.childNodes = this._childNodes_Fix; this.parentNode = this._parentNode_Fix; }else{ this.childNodes = this._childNodes_Native; this.parentNode = this._parentNode_Native; } }, _parentNode_Native : function(elNode){ return elNode.parentNode; }, _parentNode_Fix : function(elNode){ if(!elNode){return elNode;} while(elNode.previousSibling){elNode = elNode.previousSibling;} return elNode.parentNode; }, _childNodes_Native : function(elNode){ return elNode.childNodes; }, _childNodes_Fix : function(elNode){ var aResult = null; var nCount = 0; if(elNode){ var aResult = []; elNode = elNode.firstChild; while(elNode){ aResult[nCount++] = elNode; elNode=elNode.nextSibling; } } return aResult; } }))(); /*[ * ADD_APP_PROPERTY * * 주요 오브젝트를 모든 플러그인에서 this.oApp를 통해서 직접 접근 가능 하도록 등록한다. * * sPropertyName string 등록명 * oProperty object 등록시킬 오브젝트 * ---------------------------------------------------------------------------]*/ /*[ * REGISTER_BROWSER_EVENT * * 특정 브라우저 이벤트가 발생 했을때 Husky 메시지를 발생 시킨다. * * obj HTMLElement 브라우저 이벤트를 발생 시킬 HTML 엘리먼트 * sEvent string 발생 대기 할 브라우저 이벤트 * sMsg string 발생 할 Husky 메시지 * aParams array 메시지에 넘길 파라미터 * nDelay number 브라우저 이벤트 발생 후 Husky 메시지 발생 사이에 딜레이를 주고 싶을 경우 설정. (1/1000초 단위) * ---------------------------------------------------------------------------]*/ /*[ * DISABLE_MESSAGE * * 특정 메시지를 코어에서 무시하고 라우팅 하지 않도록 비활성화 한다. * * sMsg string 비활성화 시킬 메시지 * ---------------------------------------------------------------------------]*/ /*[ * ENABLE_MESSAGE * * 무시하도록 설정된 메시지를 무시하지 않도록 활성화 한다. * * sMsg string 활성화 시킬 메시지 * ---------------------------------------------------------------------------]*/ /*[ * EXEC_ON_READY_FUNCTION * * oApp.run({fnOnAppReady:fnOnAppReady})와 같이 run 호출 시점에 지정된 함수가 있을 경우 이를 MSG_APP_READY 시점에 실행 시킨다. * 코어에서 자동으로 발생시키는 메시지로 직접 발생시키지는 않도록 한다. * * none * ---------------------------------------------------------------------------]*/ /** * @pluginDesc Husky Framework에서 자주 사용되는 메시지를 처리하는 플러그인 */ nhn.husky.CorePlugin = jindo.$Class({ name : "CorePlugin", // nStatus = 0(request not sent), 1(request sent), 2(response received) // sContents = response htLazyLoadRequest_plugins : {}, htLazyLoadRequest_allFiles : {}, htHTMLLoaded : {}, $AFTER_MSG_APP_READY : function(){ this.oApp.exec("EXEC_ON_READY_FUNCTION", []); }, $ON_ADD_APP_PROPERTY : function(sPropertyName, oProperty){ this.oApp[sPropertyName] = oProperty; }, $ON_REGISTER_BROWSER_EVENT : function(obj, sEvent, sMsg, aParams, nDelay){ this.oApp.registerBrowserEvent(obj, sEvent, sMsg, aParams, nDelay); }, $ON_DISABLE_MESSAGE : function(sMsg){ this.oApp.disableMessage(sMsg, true); }, $ON_ENABLE_MESSAGE : function(sMsg){ this.oApp.disableMessage(sMsg, false); }, $ON_LOAD_FULL_PLUGIN : function(aFilenames, sClassName, sMsgName, oThisRef, oArguments){ var oPluginRef = oThisRef.$this || oThisRef; // var nIdx = _nIdx||0; var sFilename = aFilenames[0]; if(!this.htLazyLoadRequest_plugins[sFilename]){ this.htLazyLoadRequest_plugins[sFilename] = {nStatus:1, sContents:""}; } if(this.htLazyLoadRequest_plugins[sFilename].nStatus === 2){ //this.oApp.delayedExec("MSG_FULL_PLUGIN_LOADED", [sFilename, sClassName, sMsgName, oThisRef, oArguments, false], 0); this.oApp.exec("MSG_FULL_PLUGIN_LOADED", [sFilename, sClassName, sMsgName, oThisRef, oArguments, false]); }else{ this._loadFullPlugin(aFilenames, sClassName, sMsgName, oThisRef, oArguments, 0); } }, _loadFullPlugin : function(aFilenames, sClassName, sMsgName, oThisRef, oArguments, nIdx){ jindo.LazyLoading.load(nhn.husky.SE2M_Configuration.LazyLoad.sJsBaseURI+"/"+aFilenames[nIdx], jindo.$Fn(function(aFilenames, sClassName, sMsgName, oThisRef, oArguments, nIdx){ var sCurFilename = aFilenames[nIdx]; // plugin filename var sFilename = aFilenames[0]; if(nIdx == aFilenames.length-1){ this.htLazyLoadRequest_plugins[sFilename].nStatus=2; this.oApp.exec("MSG_FULL_PLUGIN_LOADED", [aFilenames, sClassName, sMsgName, oThisRef, oArguments]); return; } //this.oApp.exec("LOAD_FULL_PLUGIN", [aFilenames, sClassName, sMsgName, oThisRef, oArguments, nIdx+1]); this._loadFullPlugin(aFilenames, sClassName, sMsgName, oThisRef, oArguments, nIdx+1); }, this).bind(aFilenames, sClassName, sMsgName, oThisRef, oArguments, nIdx), "utf-8" ); }, $ON_MSG_FULL_PLUGIN_LOADED : function(aFilenames, sClassName, sMsgName, oThisRef, oArguments, oRes){ // oThisRef.$this는 현재 로드되는 플러그인이 parent 인스턴스일 경우 존재 함. oThisRef.$this는 현재 플러그인(oThisRef)를 parent로 삼고 있는 인스턴스 // oThisRef에 $this 속성이 없다면 parent가 아닌 일반 인스턴스 // oPluginRef는 결과적으로 상속 관계가 있다면 자식 인스턴스를 아니라면 일반적인 인스턴스를 가짐 var oPluginRef = oThisRef.$this || oThisRef; var sFilename = aFilenames; // now the source code is loaded, remove the loader handlers for(var i=0, nLen=oThisRef._huskyFLT.length; ili>button"); } }, $LOCAL_BEFORE_FIRST : function(sMsg) { var aToolItems = jindo.$$(">ul>li[class*=" + this.sUIClassPrefix + "]>button", this.elTextTool); var nItemLength = aToolItems.length; this.elFirstToolbarItem = this.elFirstToolbarItem || aToolItems[0]; this.elLastToolbarItem = aToolItems[nItemLength-1]; this.oApp.registerBrowserEvent(this.toolbarArea, "keydown", "NAVIGATE_TOOLBAR", []); }, $init : function(oAppContainer){ this.htUIList = {}; this.htWrappedUIList = {}; this.aUICmdMap = {}; this._assignHTMLElements(oAppContainer); this._setRoundedCornerButton(); // [SMARTEDITORSUS-1124] 텍스트 툴바 버튼의 라운드 처리 }, $ON_MSG_APP_READY : function(){ this.oApp.registerBrowserEvent(this.toolbarArea, "mouseover", "EVENT_TOOLBAR_MOUSEOVER", []); this.oApp.registerBrowserEvent(this.toolbarArea, "mouseout", "EVENT_TOOLBAR_MOUSEOUT", []); this.oApp.registerBrowserEvent(this.toolbarArea, "mousedown", "EVENT_TOOLBAR_MOUSEDOWN", []); /* var aBtns = jindo.$$("BUTTON", this.toolbarArea); for(var i=0; i nToolbarRight){ welLayer.css("left", (nToolbarRight-nLayerRight-nMargin)+"px"); } if(nLayerLeft < nToolbarLeft){ welLayer.css("left", (nToolbarLeft-nLayerLeft+nMargin)+"px"); } }else{ elLayer.style.right = "0"; nLayerLeft = welLayer.offset().left; nLayerRight = nLayerLeft + elLayer.offsetWidth; nToolbarLeft = this.welToolbarArea.offset().left; nToolbarRight = nToolbarLeft + this.toolbarArea.offsetWidth; if(nLayerRight > nToolbarRight){ welLayer.css("right", -1*(nToolbarRight-nLayerRight-nMargin)+"px"); } if(nLayerLeft < nToolbarLeft){ welLayer.css("right", -1*(nToolbarLeft-nLayerLeft+nMargin)+"px"); } } }, $ON_EVENT_TOOLBAR_MOUSEOVER : function(weEvent){ if(this.nUIStatus === 2){ return; } var aAffectedElements = this._getAffectedElements(weEvent.element); for(var i=0; i childNodes.length<=2) // -> In this case, do not close here(mousedown). The layer will be closed on "click". If we close the layer here, the click event will open it again because it toggles the visibility. while(elTmp){ if(elTmp.className && elTmp.className.match(/active/) && (elTmp.childNodes.length>2 || elTmp.parentNode.className.match(/se2_pair/))){ return; } elTmp = elTmp.parentNode; } this.oApp.exec("HIDE_ACTIVE_LAYER_IF_NOT_CHILD", [weEvent.element]); }, _enableUI : function(sUIName){ var i, nLen; this.nUIStatus = 0; var welUI = this.htWrappedUIList[sUIName]; var elUI = this.htUIList[sUIName]; if(!welUI){ return; } welUI.removeClass("off"); var aAllBtns = elUI.getElementsByTagName("BUTTON"); for(i=0, nLen=aAllBtns.length; i //