TinyMCE 플러그인 - WikiExporter

회사에서 생성되는 문서의 많은 부분은 Trac의 위키로 관리된다. 장점이 많지만 문서의 길이가 길어지기 시작하면 위키 코드만 보고는 편집하기 어려운 것도 사실이다. 좀 분량이 되는 문서를 Google Docs에서 만들었다가 위키로 옮길 일이 있어 예전에 만들다 말았던 위키도우미;;를 끄집어내 TinyMCE 플러그인으로 만들었는데 어지간히 복잡한 문서 말고는 그럭저럭 나와주는 것 같다. 덕분에 집에 일찍 갔다-_-

다운로드 : WikiExporter.1.0.zip (6.02KB)

그림에 보이는 것 처럼 원본은 Google Docs나 드림위버나 MS워드같은 HTML 편집이 가능한 곳에서 작성하고 TinyMCE 편집화면에 붙여넣은 후 왼쪽 위에 있는 빨간 W 버튼을 누르면 HTML 코드를 변환해준다. 문서가 지나치게 길면 컴퓨터가 폭발할 수도 있으니 주의..

TinyMCE를 다운로드 받아 플러그인을 설치해서 써도 되고 (어디 업로드 하지 않고 그냥 PC에서 바로 실행해도 된다) 귀찮은 사람은 이 쪽을 이용해도 된다.

'컴퓨터 얘기 > 프로그래밍' 카테고리의 다른 글

드림위버와 이별하기  (5) 2007/11/28
MySQL Foreign Key 바보짓  (6) 2007/04/09
TinyMCE 플러그인 - WikiExporter  (5) 2007/02/07
멜론 앨범 커버 다운로더  (19) 2007/02/04
Crizin.HTTPRequest.php  (8) 2007/02/03
preg 계열 함수들의 버그?  (10) 2006/08/21

자바스크립트에서 문자열을 합치는 방법

어제 워크샵에서 배운 것들을 이것 저것 해보는 중인데 그 중 StringBuffer의 성능에 대해 간단히 벤치마킹 해본 결과를 적어본다. 진작에 좀 알았으면 좋았을 것을..;

자바스크립트에서 두 문자열을 하나로 합치고 싶을때는 + 연산자로 간단히 합칠 수 있다. 다른 언어에서도 마찬가지지만 좀 저수준에서 바라보면 문자열을 합치는 작업은 앞쪽 문자열의 끝부분을 찾아서 그 뒤에 뒤쪽 문자열을 붙이는 방법이기 때문에 앞쪽 문자열이 길수록 작업시간이 늘어난다. 그래서 거대한 양의 HTML 코드를 동적으로 생성해 + 연산자로 이어붙여 innerHTML 메소드로 넣어줄때는 문자열이 길어질 수록 길이의 제곱에 비례해 시간이 늘어나는 걸 볼 수 있다.

자바의 경우는 이 문제를 StringBuffer라는 객체를 사용해 해결한다. 일정 공간의 버퍼를 만들고 여기에 문자열을 추가하면서 버퍼가 모자라면 지금 할당된 버퍼의 용량을 두배로 늘려 사용하는 단순한 방법인데 속도가 상당히 향상된다.

자바스크립트에서는 메모리를 직접 다루는게 불가능하기 때문에 이런 방법은 쓰기 힘들고, 추가할 문자열을 실제로 이어붙이는게 아니라 배열에 임시로 넣어두었다가 필요할때 합쳐서 쓰는 방법을 사용한다. 배열에 문자열을 집어넣는건 문자열의 길이와 상관없이 항상 일정한 시간이 걸리기 때문에 최종적으로 문자열을 하나로 합치는 시간에서만 문자열의 길이에 비례한 시간이 소요된다.

Example. http://crizin.net/work/demo/stringBufferExample.html

prototype을 선언해서 좀 더 우아하게 쓸 수도 있다.

Example. http://crizin.net/work/demo/stringBufferPrototypeExample.html (참고 : Java Script String Buffer)

아무튼 저런식으로 문자열을 다루면 극한 상황일수록 많은 시간을 줄일 수 있게된다. IE의 경우에는 대략 몇십배씩 차이가 나는데 파이어폭스나 오페라 같은 경우는 두 방법의 차이가 거의 없다. 아마 내부적으로 + 연산자를 StringBuffer로 처리하는게 아닌가 추측됨. (오페라의 경우에는 최적화가 잘 돼 있는지 오히려 + 연산자가 더 빠르다)

Demo : http://crizin.net/work/demo/stringBenchmark.html

그래서 결론은 IE7이 빨리 나오길 바란다는 것으로 마무리;;

인터페이스 혁신, AJAX 기술 실전 워크샵

워크샵 로고 이미지

..이라는 제목을 가진 컨퍼런스를 듣고 왔다. 윤석찬님의 AJAX 대략 훑어보기, 박병권님의 AJAX 실전 예제, 그리고 강규영님의 삽질 프리 AJAX 프로그래밍;;까지 세개의 섹션으로 진행됐는데 AJAX를 처음 접해보는 사람과 이미 다루어본 사람 모두 커버되는 알찬 자리였다. 내경우엔 사전에 주워들은 풍월이 좀 있어 세번째 강규영님 섹션이 아주 도움이 많이 됐는데 그야말로 삽질을 최소화해주는 팁으로 가득차있어 유용했다. 그래서 나는 이렇게 스스로 삽질을 자청해 수많은 사람들의 삽질을 방지해주는 분들을 존경해 마지 않는다. (세번째 섹션의 PPT 파일과 참고자료들이 이 곳에 올라와있다. AJAX에 관심이 없더라도 자바스크립터라면 한번쯤 훑어보길 강력히 권함)

예전에 어디선가 자바스크립트 팁이라고 XMLHTTPRequest 객체를 이용한 꼼수를 소개하는 글을 본적 있는데 '이런 것도 되는구나..' 하고 나중에 써먹을 요량으로 북마크만 해둔채 잊어버린 적이 있다. 그 뒤에 여러 블로그에서 AJAX가 자주 언급돼서 살펴보니 예전에 봤던 바로 그녀석인거다. 같은 도구를 던져줘도 나처럼 북마크만 해두고 잊어버리는 녀석이 있는가 하면 이걸로 지도를 보여줄 상상을 해내는 사람도 있다. 3초간 반성..

PPT 서너장이면 개념에 예제설명까지 끝날정도로 간단한 요녀석에 기대가 크다. 웹이 플랫폼화 되어가고 웹페이지가 윈도우 어플리케이션처럼 편리한 인터페이스를 가지고, 무엇보다 좀더 재밌는 웹을 만들어주는데 큰 역할을 해주는 녀석이기에..

쓸데없는 얘기 1. 가장 중요한 AJAX를 어떻게 읽는가 하는 문제는 강의하신 세분 모두 '에이잭스'로 합의 보신 듯 싶다. (찾아보니 유럽쪽에선 '아약스', 미국쪽에선 '에이잭스'가 대세라고 하는데 개인적으론 '아작스'가 왠지 정겹다;;)

쓸데없는 얘기 2. 웹페이지에 동적인 객체들을 추가하는데 있어서 'createElement(), appendChild() 따위의 DOM 노가다' vs 'innerHTML()' 둘중에 어떤게 좋을지 예전부터 궁금했었는데 innerHTML()쪽이 빠르다고 한다. 사람도 편하고 기계도 편하니 innerHTML 승! (다만 innerHTML()에 삽입될 스트링에 + 연산을 과도하게 사용할경우 문자열 작업에 관련된 고질적인 퍼포먼스 저하가 생겨 배보다 배꼽이 더 큰 경우가 생길 수도 있음에 주의)

쓸데없는 얘기 3. 아직도 궁금한건 98년도에 나온 기술이(그때는 IE에서만 되긴 했지만) 왜 이제서야 히트치고 있는건지. Jesse James Garrett이 이름을 불러주기 전에는 다만 한떨기 ActiveX 컴포넌트에 지나지 않았던건지?;

'컴퓨터 얘기 > 시시한얘기' 카테고리의 다른 글

Gmail Mobile  (11) 2005/12/20
그분이 오셨어요..  (13) 2005/09/20
인터페이스 혁신, AJAX 기술 실전 워크샵  (7) 2005/09/15
나우누리 재가입  (16) 2005/09/06
결국 Gmail로 정착  (20) 2005/08/31
This Page Is Valid XHTML 1.0 Transitional!  (8) 2005/08/07

날씨를 보여주는 자바스크립트

기상청에서 제공하는 날씨정보 XML은 미리 허락된 날씨 정보업체에서만 사용이 가능하다고 하지만 나를 포함해 여기저기서 쓰고 있는 사람이 꽤 많은데도 굳이 막지 않는걸 보면 암묵적으로 사용에 동의하고 있는지도 모르겠다. 그리고 사실 이런건 공공재라고 볼 수도 있는데 막으면 좀 섭섭하지.. 우리나라 기상청 서버 놔두고 외국 날씨 서비스에 가서 기온 가져오는 것도 웃기고..

위에는 쓸데없는 소리였고;; 이 홈페이지 오른쪽 밑에 나오는 날씨 아이콘은 메인페이지를 호출할때마다 기상청에 접속해서 날씨를 읽어온 후 아이콘을 불러오게 된다. 그 과정에서 조금이지만 로딩 시간이 길어지고 내 홈페이지의 트래픽도 증가하는 문제가 있는데 이걸 스크립트로 만들어 사용자에게 떠넘겨버리면 어떨까 싶어 한참전부터 시도해봤지만 결국 오늘로서 포기하고 중간 결과물만 올려둔다.

이 스크립트의 치명적인 문제점은 파이어폭스(아마 넷스케이프도 해당될 듯)에서 기본적으로 XMLHttpRequest() 오브젝트를 이용해서 다른 도메인의 데이터 소스를 가져올 수 없다는데 있다. 다른 도메인에 접근할 수 있도록 대화창을 띄워 Allow 하게 하면 되지만 접속하는 사용자마다 보안경고를 보게될 생각을 하면 끔찍하다;;

여기서는 날씨정보를 담은 XML 문서를 responseText로 받아와 문자열 노가다를 하고 있는데 responseXML을 이용해서 간단하게 코딩을 하고 싶었지만 기상청 서버의 Content-type이 text/xml이 아닌 text/plain으로 잘못 설정돼있어 브라우저에서 XML로 인식하지 못하는 것 같다.

혹시 사용해보거나 테스트하고 싶은 분들을 위해 간단히 설명하자면 함수는 function getWeather(str, code) { ... } 하나뿐이니 적당한 곳에 넣어두고

<div id="weatherDiv">날씨 가져오는 중..</div>
<script>getWeather("weatherDiv", 108)</script>
이런식으로 날씨정보가 들어갈 태그에 id를 지정하고, 그 다음에 getWeather()를 호출해주면 된다. 첫번째 인수는 날씨 표시할 곳의 ID, 두번째는 지역 코드(소스 참조). 플래쉬 아이콘은 기상청 사이트에서 직접링크하게 돼있는데 본격적으로 이용해야 한다면 아이콘 정도는 자기 계정에 올려두고 사용하도록 하자.

날씨보기 링크 (소스는 소스보기로..;;)

덧.

집에와서 테스트 해보니 안된다-_-

익스플로러는 보안 설정의 '도메인 간의 데이터 소스 액세스' 옵션을 사용으로 설정하지 않으면 안되고 집의 파이어폭스는 보안 설정을 묻는 대화창이 뜨지도 않는다. 원격지의 소스를 불러오는건 애초에 불가능한건가..
이제 그냥 미련없이 포기-_- (옌장 ㅜㅛㅜ)

덧2.

영 미련이 남아서 도저히;; 그냥 내 호스트를 한번 거치게 해서 원격지가 아닌 로컬 데이터 소스로 접근하도록 변경했다. getWeather() 함수를 기상청 XML 대신 아래의 페이지를 불러오도록 수정해서 lib.js에 넣었다.

<?
    header("Content-Type: text/xml");

    $fp = @fsockopen("www.kma.go.kr", 80);

    fwrite($fp, "GET /weather/xml/current.xml HTTP/1.0\r\n\r\n");

    for($i=0; $i<8; $i++)
        fgets($fp, 1024);

    while( $buff = fgets($fp, 1024) )
        echo $buff;

    fclose($fp);
?>
이제 잘 돌아간다. 더이상 손대지 말아야지 -_- (아래는 잘 돌아가는 getWeather() 함수)

function getWeather(str, code)
{
    /*    춘천    101
     *    백령도  102
     *    강릉    105
     *    서울    108
     *    인천    112
     *    울릉도  115
     *    수원    119
     *    청주    131
     *    대전    133
     *    대구    143
     *    전주    146
     *    울산    152
     *    마산    155
     *    광주    156
     *    부산    159
     *    제주    184 */


    var obj = document.getElementById(str);
    var xml;

    try { xml = new ActiveXObject("Msxml2.XMLHTTP"); }
    catch(e) {
        try { xml = new ActiveXObject("Microsoft.XMLHTTP"); }
        catch(e) {
            try { xml = new XMLHttpRequest(); }
            catch(e) { xml = null; }
        }
    }

    if( obj && xml )
    {
        try {
            // 날씨정보가 들어있는 페이지의 경로
            xml.open("GET", "/some/where/weather.php?dummy=" + new Date().getTime(), true);
        }
        catch(e)
        { obj.innerHTML = "Failed"; return; }

        xml.onreadystatechange = function()
        {
            if( xml.readyState == 4 )
            {
                var body = xml.responseText;
                body = body.substring(body.indexOf("<l"), body.lastIndexOf("l>")+2);

                local = body.split("<l");

                var ta = 0;
                var icon = 0;

                for(var i=1; i<local.length; i++)
                {
                    var block = local[i];

                    if( block.indexOf(code) != -1 )
                    {
                        var pos1 = block.indexOf("icon");
                        var pos2 = block.indexOf("\" ", pos1);

                        icon = block.substring(pos1+6, pos2);

                        pos1 = block.indexOf("ta");
                        pos2 = block.indexOf("\">", pos1);

                        ta = block.substring(pos1+4, pos2);
                    }
                }

                if( icon )
                {
                    // 아이콘 파일의 주소
                    icon = "/some/where/sub" + icon + ".swf";

                    obj.innerHTML = "<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\" codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,29,0\" width=\"25\" height=\"25\"><param name=\"movie\" value=\"" + icon + "\"><param name=\"quality\" value=\"high\"><param name=\"wmode\" value=\"transparent\"><embed src=\"" + icon + "\" quality=\"high\" pluginspage=\"http://www.macromedia.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" width=\"25\" height=\"25\"></embed></object><br>" + ta + "℃";
                }
                else
                    obj.innerHTML = "Error";
            }
        }

        xml.send(null);

        delete xml;
    }
}