J-한솔넷

네이버 스마트 에디터 분석 #1 본문

웹 개발관련

네이버 스마트 에디터 분석 #1

jhansol 2013. 2. 13. 06:28

제가 근무하는 직업전문학교 홈페이지가 과거에 만들어진 것이라 웹 표준에 맞지 않아 상위버전의 브라우즈에서는 동작하지 않는 문제가 있어 고쳐야 하긴 한데, 엄두가 나질 않았습니다.

스마트 에디터는 알고 있은지는 꽤 되었습니다만 바로 적용하기에는 좀 그렇고 해서 차일피일 미루고 있었습니다.


새로 바뀌 자바스크립트 패턴에도 적응할 겸 해서 소스를 분석해보려고 합니다. 오늘은 그 첫째로 SmartEditor2.html 파일과 HuskyEZCreator.js 파일의 소스를 분석해보고자 합니다. 자바스크립트는 일부 미진한 부분이 있습니다. 그렇지만 차후에 보완하도록 하겠습니다.


SmartEditor2.html

이 파일은 아래에도 나와 있지만 데모용 페이지입니다. 스마트 에디터를 사용하기 위한 간단한 예시용 파일입니다. 웹페이지에 스마트 에디트를 사용하기 위해서는 아래와 같은 순서로 적용합니다.

  1. js/HuskyEZCreator.js 파일을 포함시켜야 합니다.
  2. 스마트 에디트를 적용하기 위한 TEXTAREA 태그를 삽입합니다.
  3. 페이지 하단에 스마트 에디터를 표시하는 스크립트를 삽입합니다.

    var oEditors = [];

    nhn.husky.EZCreator.createInIFrame({

    oAppRef: oEditors,

    elPlaceHolder: "ir1",

    sSkinURI: "SmartEditor2Skin.html",

    htParams : {bUseToolbar : true,

    fOnBeforeUnload : function(){

    //alert("아싸!");

    }

    }, //boolean

    fOnAppLoad : function(){

    //예제 코드

    //oEditors.getById["ir1"].exec("PASTE_HTML", ["로딩이 완료된 후에 본문에 삽입되는 text입니다."]);

    },

    fCreator: "createSEditor2"

    });

  4. 기타 부가적인 함수를 추가합니다. 아래 함수 중 submitContents() 함수는 스마트 에디터의 내용을 TEXTAREA에 적용하고 폼 데이터를 전송하는 함수이므로 반드시 추가해주어야 하겠습니다.


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="ko" xml:lang="ko">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

<title>네이버 :: Smart Editor 2 &#8482;</title>


<!-- 스마트 에디터를 적용하기 위한 자바스크립트 API 포함 -->

<script type="text/javascript" src="./js/HuskyEZCreator.js" charset="utf-8"></script>

</head>

<body>

<form action="sample.php" method="post">

<!-- 

아래 부분의 TEXTAREA는 스마트 에디터에 의해 편집되는 내용을 담는 것으로

기본적인 정보와 크기, 화면표시(표시되지 않음)으로 설정되어 있습니다. 이 부분에

스마트 에디터가 표시될 것입니다.

-->

<textarea name="ir1" id="ir1" rows="10" cols="100" style="width:766px; height:412px; display:none;"></textarea>

<p>

<input type="button" onclick="pasteHTML();" value="본문에 내용 넣기" />

<input type="button" onclick="showHTML();" value="본문 내용 가져오기" />

<input type="button" onclick="submitContents(this);" value="서버로 내용 전송" />

<input type="button" onclick="setDefaultFont();" value="기본 폰트 지정하기 (궁서_24)" />

</p>

</form>


<script type="text/javascript">

/*

============================================================================

이 부분은 위 부분의 TEXTAREA 테그에 씌워질 스마트 에디터 프래임을 만드는 일을 합

니다. createInIFrame 함수의 인자로 전달되는 정보는 JSON 객체 방식으로 전달합니다.

============================================================================

*/

var oEditors = [];

nhn.husky.EZCreator.createInIFrame({

oAppRef: oEditors,

elPlaceHolder: "ir1",

sSkinURI: "SmartEditor2Skin.html",

htParams : {bUseToolbar : true,

fOnBeforeUnload : function(){

//alert("아싸!");

}

}, //boolean

fOnAppLoad : function(){

//예제 코드

//oEditors.getById["ir1"].exec("PASTE_HTML", ["로딩이 완료된 후에 본문에 삽입되는 text입니다."]);

},

fCreator: "createSEditor2"

});


/*

============================================================================

이 부분은 본문에 내용 넣기라는 단추를 클릭했을 때 호출되는 함수입니다. 스마트 에디터

프래임 안에 아래와 같은 내용을 삽입합니다. 

"<span style='color:#FF0000;'>이미지도 같은 방식으로 삽입합니다.<\/span>"

============================================================================

*/

function pasteHTML() {

var sHTML = "<span style='color:#FF0000;'>이미지도 같은 방식으로 삽입합니다.<\/span>";

oEditors.getById["ir1"].exec("PASTE_HTML", [sHTML]);

}


/*

============================================================================

이 부분은 위 pasteHTML() 함수와는 반대로 스마트 에디터 프래임의 편집 내용을 가져와

메시지로 출력하는 예제입니다.

============================================================================

*/

function showHTML() {

var sHTML = oEditors.getById["ir1"].getIR();

alert(sHTML);

}

/*

============================================================================

이 부분은 편집된 내용을 서버로 전성하는 부분으로 스마트 에디터 프래임의 편집 내용을

TEXTAREA에 적용하고 TEXTAREA가 속한 폼으로 하여금 전송하도록 합니다.

============================================================================

*/

function submitContents(elClickedObj) {

oEditors.getById["ir1"].exec("UPDATE_CONTENTS_FIELD", []); // 에디터의 내용이 textarea에 적용됩니다.

// 에디터의 내용에 대한 값 검증은 이곳에서 document.getElementById("ir1").value를 이용해서 처리하면 됩니다.

try {

elClickedObj.form.submit();

} catch(e) {}

}


/*

============================================================================

이 부분은 스므트 에디터의 기본 서체를 지정하는 부분입니다. setDefaultFont() 함수를 

이용하는군요.

============================================================================

*/

function setDefaultFont() {

var sDefaultFont = '궁서';

var nFontSize = 24;

oEditors.getById["ir1"].setDefaultFont(sDefaultFont, nFontSize);

}

</script>


</body>

</html>



HuskyEZCreator.js


이 파일은 위 소스에서 호출되는 nhn.husky.EZCreator.createInIFrame() 함수와 그외 스마트 에디터를 생성하고 실행하는데 도움이 되는 함수들이 들어 있는 파일입니다. 이 부분은 별도로 수정해줄 필요가 없습니다.

이 파일에서 가장 핵심은 EZCreator객체의 createInIFrame() 함수입니다. 

createInIFrame() 함수는 스마트 에디터를 생성하기 위한 여러 정보를 받아 IFRAME을 생성하고 여기에 스마트 에디터 객체를 만들고, 실행할 수 있도록 해 줍니다.

그리고 showBlocker(), hideBlocker() 함수는 아직 그 용도를 확실히 파악하지는 못했습니다.


/*

============================================================================

이 파일은 HTML로 작성된 스킨 파일과 지정한 옵션으로 스마트 에디터를 생생

하는 함수와 도움을 주는 함수들이 기록되어 있습니다. 

============================================================================

*/


// 이 부분은 nhn 객체가 없으면 빈 nhn객체를 생성하고 그 속성인 husky객체를

// 생성합니다.

if(typeof window.nhn=='undefined') window.nhn = {};

if (!nhn.husky) nhn.husky = {};


/*

============================================================================

이 부분은 husky의 속성인 EZCreator 객체를 생성하는 부분입니다. EZCreator객

체는 아래와 같은 속성을 가집니다.

- createInIFrame( JSONObject )

- createInIFrame( oAppRef, elPlaceHolder, sSkinURI, fCreator, fOnAppLoad, bUseBlocker, htParams )

- showBlocker()

- hideBlocker()

============================================================================

*/

nhn.husky.EZCreator = new (function(){

this.nBlockerCount = 0;

/*

========================================================================

이 부분은 메서드 createInIFrame()를 정의하는 것입니다. 이 함수는 전달 인

수가 하나인 경우 JSON 객체 형식으로 인수를 받는 방법과 이전 버전과의

호환성을 위해 각각의 인자를 받아 들이는 방식 두 가지가 있습니다.

========================================================================

*/

this.createInIFrame = function(htOptions){

if(arguments.length == 1){

var oAppRef = htOptions.oAppRef;

var elPlaceHolder = htOptions.elPlaceHolder;

var sSkinURI = htOptions.sSkinURI;

var fCreator = htOptions.fCreator;

var fOnAppLoad = htOptions.fOnAppLoad;

var bUseBlocker = htOptions.bUseBlocker;

var htParams = htOptions.htParams || null;

}else{

// 이전 버전과의 호환을 위해

var oAppRef = arguments[0];

var elPlaceHolder = arguments[1];

var sSkinURI = arguments[2];

var fCreator = arguments[3];

var fOnAppLoad = arguments[4];

var bUseBlocker = arguments[5];

var htParams = arguments[6];

}


/*

=====================================================================

이 부분은 아직 잘 모르겠군요. Blocker는 문서의 스크롤 영역의 높이, 화

면 표시 영역의 높이 중 큰 값을 높이로 하고, 폭은 화면의 폭으로 하는

DIV 태그로 문서에 추가되는 것으로만 파악되었습니다.

=====================================================================

*/

if(bUseBlocker) nhn.husky.EZCreator.showBlocker();


/*

=====================================================================

이 부분은 이벤트 핸들러를 태그에 추가하는 함수 입니다. 비 익스플로러

와 익스플로러용 두 부분으로 구성되어 있습니다.

태그 객체에 addEventListener가 있으면 비 익스플로러, 그렇지 않으면 익

스플로러용으로 구분합니다.

=====================================================================

*/

var attachEvent = function(elNode, sEvent, fHandler){ 

if(elNode.addEventListener){

elNode.addEventListener(sEvent, fHandler, false);

}else{

elNode.attachEvent("on"+sEvent, fHandler);

}


// TEXTAREA 태그의 id가 지정되지 않았으면 경고 메시지를 표시합니다.

if(!elPlaceHolder){

alert("Placeholder is required!");

return;

}


// elPlaceHolder가 객체가 아니면 id로 간주하고 해당 id의 객체를 가져

// 와 다시 지정합니다.

if(typeof(elPlaceHolder) != "object")

elPlaceHolder = document.getElementById(elPlaceHolder);


var elIFrame, nEditorWidth, nEditorHeight;

 

/*

=====================================================================

이 부분은 TEXTAREA를 대체할 IFRAME을 생성합니다. 페이지 로드 후에

스마트 에디터를 생성하고 사용할 수 있도록 합니다.

=====================================================================

*/

try{

// IFRAME 태그 생성

elIFrame = document.createElement("<IFRAME frameborder=0 scrolling=no>");

}catch(e){

// 오류가 발생한 경우 익스플로러 형식으로 태그 생성

elIFrame = document.createElement("IFRAME");

elIFrame.setAttribute("frameborder", "0");

elIFrame.setAttribute("scrolling", "no");

}

// elIFrame의 스타일(폭과 높이) 지정후 TEXTAREA 태그 뒤에 삽입

elIFrame.style.width = "1px";

elIFrame.style.height = "1px";

elPlaceHolder.parentNode.insertBefore(elIFrame, elPlaceHolder.nextSibling);

// elIFrame이 로더 되었을 때 호출될 이벤트 핸들러 추가

attachEvent(elIFrame, "load", function(){

// fCreator 함수 가져옴

fCreator = elIFrame.contentWindow[fCreator] || elIFrame.contentWindow.createSEditor2;

// elIFrame의 폭과 높이, 마진 등을 설정한다.

try{

nEditorWidth = elIFrame.contentWindow.document.body.scrollWidth || "500px";

nEditorHeight = elIFrame.contentWindow.document.body.scrollHeight + 12;

elIFrame.style.width =  "100%";

elIFrame.style.height = nEditorHeight+ "px";

elIFrame.contentWindow.document.body.style.margin = "0";

}catch(e){

nhn.husky.EZCreator.hideBlocker(true);

elIFrame.style.border = "5px solid red";

elIFrame.style.width = "500px";

elIFrame.style.height = "500px";

alert("Failed to access "+sSkinURI);

return;

}

// 스마트 에디터 객체를 생성한다.

var oApp = fCreator(elPlaceHolder, htParams); // oEditor

// 연관된 TEXTAREA 태그를 지정한다.

oApp.elPlaceHolder = elPlaceHolder;


// 스마트 에디트 객체를 객체의 레퍼런스 배열에 추가한다.

oAppRef[oAppRef.length] = oApp;

// 레퍼런스 배열의 속성인 getById가 없으면 빈 배열을 생성한다.

if(!oAppRef.getById) oAppRef.getById = {};

// 스마트 에디트를 getById 배열에 추가한다.

if(elPlaceHolder.id) oAppRef.getById[elPlaceHolder.id] = oApp;


// 스마트 에디트를 실행한다.

oApp.run({fnOnAppReady:fOnAppLoad}); 

// ??

nhn.husky.EZCreator.hideBlocker();

});

// 스마트 에디트 스킨을 IFRAME의 소스로 지정한다.

elIFrame.src = sSkinURI;

};

/*

========================================================================

이 부분은 아직 잘 모르겠습니다. 추후 분석을 해봐야겠습니다.

========================================================================

*/

this.showBlocker = function(){

if(this.nBlockerCount<1){

var elBlocker = document.createElement("DIV");

elBlocker.style.position = "absolute";

elBlocker.style.top = 0;

elBlocker.style.left = 0;

elBlocker.style.backgroundColor = "#FFFFFF";

elBlocker.style.width = "100%";


document.body.appendChild(elBlocker);

nhn.husky.EZCreator.elBlocker = elBlocker;

}


nhn.husky.EZCreator.elBlocker.style.height = Math.max(document.body.scrollHeight, document.body.clientHeight)+"px";

this.nBlockerCount++;

};

/*

========================================================================

이 부분은 아직 잘 모르겠습니다. 추후 분석을 해봐야겠습니다.

========================================================================

*/

this.hideBlocker = function(bForce){

if(!bForce){

if(--this.nBlockerCount > 0) return;

}

this.nBlockerCount = 0;

if(nhn.husky.EZCreator.elBlocker) nhn.husky.EZCreator.elBlocker.style.display = "none";

}

})();