PageSourceSearch

https://smurfmagic.com/cheditor/cheditor.js

js smurfmagic.com collected 2026-10-08 05:42:00 UTC 316,064 bytes, 7,933 lines download raw bytes

1// ================================================================
2//                       CHEditor 5.1.9.1
3// ----------------------------------------------------------------
4// Homepage: http://www.chcode.com
5// EMail: [email protected]
6// Copyright (c) 1997-2016 CHSOFT
7// ================================================================
8var GB = {
9    colors: ['#000000','#313131','#434343','#535353','#666666','#999999','#a0a0a0','#b5b5b5','#c0c0c0','#dcdcdc','#eeeeee','#ffffff',
10             '#ff0000','#ff8000','#ffff00','#80ff00','#00ff00','#00ff99','#00ffff','#0080ff','#0000ff','#7f00ff','#ff00ff','#ff007f',
11             '#ffcccc','#ffe5cc','#ffffcc','#e5ffcc','#ccffcc','#ccffe5','#ccffff','#cce5ff','#ccccff','#e5ccff','#ffccff','#ffcce5',
12             '#ff9999','#ffcc99','#ffff99','#ccff99','#99ff99','#99ffcc','#99ffff','#99ccff','#9999ff','#cc99ff','#ff99ff','#ff99cc',
13             '#ff6666','#ffb266','#ffff66','#b2ff66','#66ff66','#66ffb2','#66ffff','#66b2ff','#6666ff','#b266ff','#ff66ff','#ff66b2',
14             '#ff3333','#ff9933','#ffff33','#99ff33','#33ff33','#33ff99','#33ffff','#3399ff','#3333ff','#9933ff','#ff33ff','#ff3399',
15             '#cc0000','#cc6600','#cccc00','#66cc00','#00cc00','#00cc66','#00cccc','#0066cc','#0000cc','#6600cc','#cc00cc','#cc0066',
16             '#990000','#994c00','#999900','#4c9900','#009900','#00994c','#009999','#004c99','#000099','#4c0099','#990099','#99004c',
17             '#660000','#663300','#666600','#336600','#006600','#006633','#006666','#003366','#000066','#330066','#660066','#660033'],
18    offElementTags: {
19        img: 1, hr: 1, table: 1, embed: 1, object: 1, input: 1, form: 1, select: 1, textarea: 1, button: 1, fieldset: 1
20    },
21    emptyElementTags: {
22        area: 1, base: 1, basefont: 1, col: 1, frame: 1, hr: 1, img: 1, br: 1, input: 1, isindex: 1, link: 1, meta: 1,
23        param: 1, source: 1, track: 1, wbr: 1, keygen: 1, menuitem: 1
24    },
25    textFormatTags: {
26        addr: 1, acronym: 1, b: 1, bdo: 1, big: 1, cite: 1, code: 1, del: 1, dfn: 1, em: 1, font: 1, i: 1, ins: 1, kbd: 1, q: 1,
27        samp: 1, small: 1, strike: 1, strong: 1, sub: 1, sup: 1, time: 1, tt: 1, u: 1, 'var': 1, a: 1, span: 1
28    },
29    textFormatBlockTags: {
30        address: 1, div: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, p: 1,  pre: 1, code: 1, section: 1, aside: 1, article: 1, figcaption: 1
31    },
32    newLineBeforeTags: {
33        address: 1, aside: 1, article: 1, audio: 1, blockquote: 1, canvas: 1, code: 1, dd: 1, div: 1, dl: 1, fieldset: 1,
34        figcaption: 1, figure: 1, footer: 1, form: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, header: 1, hggroup: 1,
35        hr: 1, noscript: 1, ol: 1, output: 1, p: 1, pre: 1, section: 1, table: 1, tfoot: 1, ul: 1, video: 1,
36        thead: 1, tbody: 1, tr: 1, th: 1, td: 1, title: 1, body: 1, head: 1, script: 1, comment: 1, li: 1
37    },
38    lineHeightBlockTags: {
39        address: 1, blockquote: 1, li: 1, dd: 1, dt: 1, div: 1, h1: 1, h2: 1, h3: 1, h4: 1, h5: 1, h6: 1, p: 1, pre: 1, td: 1,
40        th: 1, code: 1, section: 1, aside: 1, article: 1, figure: 1, figcaption: 1
41    },
42    listTags: { li: 1, dd: 1, dt: 1 },
43    lineBreakTags: { address: 1, dd: 1, dt: 1, div: 1, li: 1, p: 1, section: 1, aside: 1, article: 1, figcaption: 1 },
44    doctype: '<!DOCTYPE html>',
45    popupWindow: {
46        ImageUpload :   {tmpl : 'image.html',           width : 700, title : '내 PC 사진 넣기'},
47        ImageUrl :      {tmpl : 'image_url.html',       width : 350, title : '웹 사진 넣기'},
48        Embed :         {tmpl : 'media.html',           width : 430, title : '미디어'},
49        Table :         {tmpl : 'table.html',           width : 430, title : '표 만들기'},
50        ModifyTable :   {tmpl : 'table_modify.html',    width : 430, title : '표 고치기'},
51        Layout :        {tmpl : 'layout.html',          width : 430, title : '레이아웃'},
52        Link :          {tmpl : 'link.html',            width : 350, title : '하이퍼링크'},
53        EmotionIcon :   {tmpl : 'icon.html',            width : 300, title : '표정 아이콘'},
54        Symbol :        {tmpl : 'symbol.html',          width : 450, title : '특수 문자'},
55        GoogleMap :     {tmpl : 'google_map.html',      width : 538, title : '구글 지도'},
56        ColorPicker :   {tmpl : 'color_picker.html',    width : 420, title : '색상 선택'},
57        FlashMovie :    {tmpl : 'flash.html',           width : 584, title : '플래쉬 동영상'}
58    },
59    fontName: {
60        kr : ['맑은 고딕', '돋움', '굴림', '바탕', '궁서'],
61        en : ['Arial', 'Comic Sans MS', 'Courier New', 'Georgia', 'HeadLineA', 'Impact', 'Tahoma', 'Times New Roman', 'Verdana']
62    },
63    fontStyle: {
64        FontSize: 'font-size', FontName: 'font-family', ForeColor: 'color', BackColor: 'background-color'
65    },
66    textAlign: {
67        JustifyLeft: '', JustifyCenter: 'center', JustifyRight: 'right', JustifyFull: 'justify'
68    },
69    listStyle: {
70        ordered: {
71            decimal: '숫자', 'lower-alpha': '영문 소문자', 'upper-alpha': '영문 대문자', 'lower-roman': '로마 소문자', 'upper-roman': '로마 대문자'
72        },
73        unOrdered: {desc: '동그라미', circle: '빈 원', square: '사각형'}
74    },
75    fontSize: {
76        pt: [7, 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36],
77        px: [9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 36, 48, 72]
78    },
79    formatBlock: {
80        P: '일반 텍스트',
81        H1: '제목 1',
82        H2: '제목 2',
83        H3: '제목 3',
84        H4: '제목 4',
85        H5: '제목 5',
86        H6: '제목 6',
87        ADDRESS: 'Address',
88        DIV: 'DIV',
89        PRE: 'Preformatted (PRE)'
90    },
91    lineHeight: {
92        '한 줄 간격': 1, '1.15': 1.15, '1.5': 1.5, '1.7': 1.7, '1.8': 1.8, '두 줄 간격': 2
93    },
94    textBlock: [
95        ['1px #dedfdf solid','#f7f7f7'],
96        ['1px #aee8e8 solid','#bfffff'],
97        ['1px #d3bceb solid','#e6ccff'],
98        ['1px #e8e88b solid','#ffff99'],
99        ['1px #c3e89e solid','#d6ffad'],
100        ['1px #e8c8b7 solid','#ffdcc9'],
101        ['1px #666666 dashed','#ffffff'],
102        ['1px #d4d4d4 solid','#ffffff'],
103        ['1px #cccccc inset','#f7f7f7']
104    ],
105    node: {
106        element: 1, attribute: 2, text: 3, cdata_section: 4, entity_reference: 5, entity: 6,
107        processing_instruction: 7, comment: 8, document: 9, document_type: 10, document_fragment: 11,
108        notation: 12
109    },
110
111    selection: { none: 1, text: 2, element: 3 },
112    readyState: { 0: 'uninitialized', 1: 'loading', 2: 'loaded', 3: 'interactive', 4: 'complete' },
113    dragWindow: null,
114    colorDropper: null,
115    readyEditor: 0,
116    browser: {}
117};
118
119function isUndefined(obj) {
120    return obj === void(0); // obj === undefined;
121}
122
123function detechBrowser() {
124    function detect(ua) {
125        var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase(),
126            likeAndroid = /like android/i.test(ua),
127            android = !likeAndroid && /android/i.test(ua),
128            versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i),
129            tablet = /tablet/i.test(ua),
130            mobile = !tablet && /[^\-]mobi/i.test(ua),
131            result,
132            osVersion = '',
133            osMajorVersion,
134            osname,
135            app;
136
137        function getFirstMatch(regex) {
138            var match = ua.match(regex);
139            return (match && match.length > 1 && match[1]) || '';
140        }
141
142        if (/opera|opr/i.test(ua)) {
143            result = {
144                name: 'Opera', opera: true,
145                version: versionIdentifier || getFirstMatch(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i)
146            };
147        } else if (/windows phone/i.test(ua)) {
148            result = {
149                name: 'Windows Phone', windowsphone: true, msie: true,
150                version: getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i)
151            };
152        } else if (/msie|trident/i.test(ua)) {
153            result = {
154                name: 'Internet Explorer', msie: true, version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i)
155            };
156        } else if (/edge/i.test(ua)) {
157            result = {
158                name: 'edge', edge: true, version: getFirstMatch(/(?:edge)\/(\d+(\.\d+)?)/i)
159            };
160        } else if (/chrome|crios|crmo/i.test(ua)) {
161            result = {
162                name: 'Chrome', chrome: true, version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
163            };
164        } else if (iosdevice) {
165            result = {
166                name: iosdevice === 'iphone' ? 'iPhone' : iosdevice === 'ipad' ? 'iPad' : 'iPod'
167            };
168            if (versionIdentifier) {
169                result.version = versionIdentifier;
170            }
171        } else if (/firefox|iceweasel/i.test(ua)) {
172            result = {
173                name: 'Firefox', firefox: true,
174                version: getFirstMatch(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i)
175            };
176            if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) {
177                result.firefoxos = true;
178            }
179        } else if (/silk/i.test(ua)) {
180            result =  {
181                name: 'Amazon Silk', silk: true, version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i)
182            };
183        } else if (android) {
184            result = { name: 'Android', version: versionIdentifier };
185        } else if (/phantom/i.test(ua)) {
186            result = {
187                name: 'PhantomJS', phantom: true, version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i)
188            };
189        } else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) {
190            result = {
191                name: 'BlackBerry', blackberry: true,
192                version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i)
193            };
194        } else if (/(web|hpw)os/i.test(ua)) {
195            result = {
196                name: 'WebOS', webos: true,
197                version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)
198            };
199            if (/touchpad\//i.test(ua)) {
200                result.touchpad = true;
201            }
202        } else if (/safari/i.test(ua)) {
203            result = {
204                name: 'Safari', safari: true, version: versionIdentifier
205            };
206        } else {
207            result = {};
208        }
209
210        if (/(apple)?webkit/i.test(ua)) {
211            result.name = result.name || 'Webkit';
212            result.webkit = true;
213            if (!result.version && versionIdentifier) {
214                result.version = versionIdentifier;
215            }
216        } else if (!result.opera && /gecko\//i.test(ua)) {
217            result.gecko = true;
218            result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i);
219            result.name = result.name || 'Gecko';
220        }
221        if (android || result.silk) {
222            result.android = true;
223        } else if (iosdevice) {
224            result[iosdevice] = true;
225            result.ios = true;
226        }
227
228        if (iosdevice) {
229            osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i);
230            osVersion = osVersion.replace(/[_\s]/g, '.');
231        } else if (android) {
232            osVersion = getFirstMatch(/android[ \/\-](\d+(\.\d+)*)/i);
233        } else if (result.windowsphone) {
234            osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i);
235        } else if (result.webos) {
236            osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i);
237        } else if (result.blackberry) {
238            osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i);
239        }
240
241        if (osVersion) {
242            result.osversion = osVersion;
243        }
244
245        osMajorVersion = osVersion.split('.')[0];
246        if (tablet || iosdevice === 'ipad' ||
247            (android && (osMajorVersion === 3 || (osMajorVersion === 4 && !mobile))) ||
248            result.silk) {
249            result.tablet = true;
250        } else if (mobile || iosdevice === 'iphone' || iosdevice === 'ipod' || android ||
251                result.blackberry || result.webos) {
252            result.mobile = true;
253        }
254
255        if (result.edge ||
256            (result.msie && result.version >= 10) ||
257            (result.chrome && result.version >= 20) ||
258            (result.firefox && result.version >= 20.0) ||
259            (result.safari && result.version >= 6) ||
260            (result.opera && result.version >= 10.0) ||
261            (result.ios && result.osversion && result.osversion.split('.')[0] >= 6) ||
262            (result.blackberry && result.version >= 10.1)) {
263            result.a = true;
264        } else if ((result.msie && result.version < 10) ||
265            (result.chrome && result.version < 20) ||
266            (result.firefox && result.version < 20.0) ||
267            (result.safari && result.version < 6) ||
268            (result.opera && result.version < 10.0) ||
269            (result.ios && result.osversion && result.osversion.split('.')[0] < 6)) {
270            result.c = true;
271        } else {
272            result.x = true;
273        }
274
275        osname = '';
276        if (/windows/i.test(ua)) {
277            osname = 'Windows';
278        } else if (/mac/i.test(ua)) {
279            osname = 'MacOS';
280        } else if (/x11/i.test(ua)) {
281            osname = 'UNIX';
282        } else if (/linux/i.test(ua)) {
283            osname = 'Linux';
284        } else if (/sunos/i.test(ua)) {
285            osname = 'Solaris';
286        } else {
287            osname = 'Unknown OS';
288        }
289        result.osname = osname;
290
291        if (osname === 'Windows') {
292            app = getFirstMatch(/(Windows NT\s(\d+)\.(\d+))/i);
293            switch (app) {
294                case 'Windows NT 5.1' : result.os = 'Windows XP'; break;
295                case 'Windows NT 5.2' : result.os = 'Windows 2003'; break;
296                case 'Windows NT 6.0' : result.os = 'Windows Vista'; break;
297                case 'Windows NT 6.1' : result.os = 'Windows 7'; break;
298                case 'Windows NT 6.2' : result.os = 'Windows 8'; break;
299                case 'Windows NT 6.3' : result.os = 'Windows 8.1'; break;
300                case 'Windows NT 10.0' : result.os = 'Windows 10'; break;
301                default : result.os = app;
302            }
303        }
304
305        if (result.msie) {
306            if (result.version > 10) {
307                result.msie_a = true;
308                result.msie_bogus = true;
309            } else if (result.version > 8) {
310                result.msie_b = true;
311                result.msie_bogus = false;
312            } else {
313                result.msie_c = true;
314                result.msie_bogus = (result.os === 'Windows XP');
315            }
316        }
317        return result;
318    }
319    return detect(!isUndefined(navigator) ? navigator.userAgent : null);
320}
321
322function URI(uri) {
323    this.scheme = null;
324    this.authority = null;
325    this.path = '';
326    this.query = null;
327    this.fragment = null;
328
329    this.parseUri = function (uri) {
330        var m = uri.match(/^(([A-Za-z][0-9A-Za-z+.\-]*)(:))?((\/\/)([^\/?#]*))?([^?#]*)((\?)([^#]*))?((#)(.*))?/);
331        this.scheme = m[3] ? m[2] : null;
332        this.authority = m[5] ? m[6] : null;
333        this.path = m[7];
334        this.query = m[9] ? m[10] : null;
335        this.fragment = m[12] ? m[13] : null;
336        return this;
337    };
338
339    this.azToString = function () {
340        var result = '';
341        if (this.scheme !== null) {
342            result = result + this.scheme + ':';
343        }
344        if (this.authority !== null) {
345            result = result + '//' + this.authority;
346        }
347        if (this.path !== null) {
348            result = result + this.path;
349        }
350        if (this.query !== null) {
351            result = result + '?' + this.query;
352        }
353        if (this.fragment !== null) {
354            result = result + '#' + this.fragment;
355        }
356        return result;
357    };
358
359    this.toAbsolute = function (location) {
360        var baseUri = new URI(location),
361            URIAbs = this,
362            target = new URI(),
363            removeDotSegments = function (path) {
364                var result = '', rm;
365                while (path) {
366                    if (path.substr(0, 3) === '../' || path.substr(0, 2) === './') {
367                        path = path.replace(/^\.+/, '').substr(1);
368                    } else if (path.substr(0, 3) === '/./' || path === '/.') {
369                        path = '/' + path.substr(3);
370                    } else if (path.substr(0, 4) === '/../' || path === '/..') {
371                        path = '/' + path.substr(4);
372                        result = result.replace(/\/?[^\/]*$/, '');
373                    } else if (path === '.' || path === '..') {
374                        path = '';
375                    } else {
376                        rm = path.match(/^\/?[^\/]*/)[0];
377                        path = path.substr(rm.length);
378                        result = result + rm;
379                    }
380                }
381                return result;
382            };
383
384        if (baseUri.scheme === null) {
385            return false;
386        }
387        if (URIAbs.scheme !== null && URIAbs.scheme.toLowerCase() === baseUri.scheme.toLowerCase()) {
388            URIAbs.scheme = null;
389        }
390
391        if (URIAbs.scheme !== null) {
392            target.scheme = URIAbs.scheme;
393            target.authority = URIAbs.authority;
394            target.path = removeDotSegments(URIAbs.path);
395            target.query = URIAbs.query;
396        } else {
397            if (URIAbs.authority !== null) {
398                target.authority = URIAbs.authority;
399                target.path = removeDotSegments(URIAbs.path);
400                target.query = URIAbs.query;
401            } else {
402                if (URIAbs.path === '') {
403                    target.path = baseUri.path;
404                    target.query = URIAbs.query || baseUri.query;
405                } else {
406                    if (URIAbs.path.substr(0, 1) === '/') {
407                        target.path = removeDotSegments(URIAbs.path);
408                    } else {
409                        if (baseUri.authority !== null && baseUri.path === '') {
410                            target.path = '/' + URIAbs.path;
411                        } else {
412                            target.path = baseUri.path.replace(/[^\/]+$/, '') + URIAbs.path;
413                        }
414                        target.path = removeDotSegments(target.path);
415                    }
416                    target.query = URIAbs.query;
417                }
418                target.authority = baseUri.authority;
419            }
420            target.scheme = baseUri.scheme;
421        }
422        target.fragment = URIAbs.fragment;
423        return target;
424    };
425    if (uri) {
426        this.parseUri(uri);
427    }
428}
429
430function setConfig() {
431    var config = {
432        editorWidth         : '100%',
433        editorHeight        : '300px',
434        editorFontSize      : '12px',
435        editorFontName      : '"맑은 고딕", "Malgun Gothic", gulim',
436        editorFontColor     : '#000',
437        editorBgColor       : '#fff',
438        lineHeight          : 1.7,
439        editAreaMargin      : '5px 10px',
440        tabIndex            : 0,
441        editorPath          : null,
442        fullHTMLSource      : false,
443        linkTarget          : '_blank',
444        showTagPath         : false,
445        colorToHex          : true,
446        includeHostname     : true,
447        paragraphCss        : false, // true = <p style='margin:0'></p>, false = <p></p>
448        docTitle            : '내 문서',
449        fontSizeValue       : 'px', // [pt, px]
450        removeIndent        : false,
451        tabIndent           : 3,
452        imgMaxWidth         : 1200,
453        imgJpegQuality      : 0.9,
454        imgUploadNumber     : 12,
455        imgUploadSortName   : false,
456        imgSetAttrWidth     : 0, // -1 = (width="100%"; height="auto"), 0 = 설정 안함, 1 = 기본값
457        imgSetAttrAlt       : true,
458        imgDefaultAlign     : 'left', // [left, center, right]
459        imgBlockMargin      : '5px 0px',
460        imgCaptionText      : 'margin: 5px 5px; text-align: left; line-height: 17px',
461        imgCaptionFigure    : 'border: 1px #ccc solid; background-color: #f0f0f0; margin: 0',
462        imgCaptionWrapper   : '',
463        makeThumbnail       : false,
464        thumbnailWidth      : 120,
465        thumbnailHeight     : 90,
466        exceptedElements    : { script: true, style: true, iframe: false },
467        allowedOnEvent      : false,
468
469        // 버튼 사용 유무
470        useSource           : true,
471        usePreview          : true,
472        usePrint            : false,
473        useNewDocument      : false,
474        useUndo             : false,
475        useRedo             : false,
476        useCopy             : false,
477        useCut              : false,
478        usePaste            : false,
479        usePasteFromWord    : false,
480        useSelectAll        : false,
481        useStrikethrough    : false,
482        useUnderline        : false,
483        useItalic           : true,
484        useSuperscript      : false,
485        useSubscript        : false,
486        useJustifyLeft      : true,
487        useJustifyCenter    : true,
488        useJustifyRight     : true,
489        useJustifyFull      : true,
490        useBold             : true,
491        useOrderedList      : false,
492        useUnOrderedList    : false,
493        useOutdent          : false,
494        useIndent           : false,
495        useFontName         : true,
496        useFormatBlock      : false,
497        useFontSize         : true,
498        useLineHeight       : false,
499        useBackColor        : true,
500        useForeColor        : true,
501        useRemoveFormat     : true,
502        useClearTag         : true,
503        useSymbol           : false,
504        useLink             : true,
505        useUnLink           : true,
506        useFlash            : true,
507        useMedia            : true,
508        useImage            : true,
509        useImageUrl         : false,
510        useSmileyIcon       : false,
511        useHR               : false,
512        useTable            : false,
513        useModifyTable      : false,
514        useMap              : false,
515        useTextBlock        : false,
516        useFullScreen       : true,
517        usePageBreak        : false
518    },
519    base, elem, i, editorUri, locationAbs;
520
521    if (config.editorPath === null) {
522        base = location.href;
523        elem = document.getElementsByTagName('base');
524        for (i = 0; i < elem.length; i++) {
525            if (elem[i].href) {
526                base = elem[i].href;
527            }
528        }
529        elem = document.getElementsByTagName('script');
530        for (i = 0; i < elem.length; i++) {
531            if (elem[i].src) {
532                editorUri = new URI(elem[i].src);
533                if (/\/cheditor\.js$/.test(editorUri.path)) {
534                    locationAbs = editorUri.toAbsolute(base).azToString();
535                    delete locationAbs.query;
536                    delete locationAbs.fragment;
537                    config.editorPath = locationAbs.replace(/[^\/]+$/, '');
538                }
539            }
540        }
541        if (config.editorPath === null) {
542            throw 'CHEditor 경로가 바르지 않습니다.\nmyeditor.config.editorPath를 설정하여 주십시오.';
543        }
544    }
545
546    this.storedSelections = [];
547    this.keyPressStoredSelections = [];
548    this.images = [];
549    this.editImages = {};
550    this.cheditor = {};
551    this.toolbar = {};
552    this.pulldown = {};
553    this.currentRS = {};
554    this.resizeEditor = {};
555    this.setFullScreenMode = false;
556    this.modalElementZIndex = 1001;
557    this.config = config;
558    this.templateFile = 'template.xml';
559    this.templatePath = config.editorPath + this.templateFile;
560    this.W3CRange = !(this.undefined(window.getSelection));
561    this.inputForm = 'textAreaId';
562    this.range = null;
563    this.tempTimer = null;
564    this.cheditor.tabSpaces = '';
565    this.cheditor.modifyState = false;
566    this.cheditor.tabSpaces = new Array(this.config.tabIndent + 1).join(' ');
567}
568
569function cheditor() {
570    this.toType = (function (global) {
571        var toString = cheditor.prototype.toString,
572            re = /^.*\s(\w+).*$/;
573
574        return function (obj) {
575            if (obj === global) {
576                return 'global';
577            }
578            return toString.call(obj).replace(re, '$1').toLowerCase();
579        };
580    }(this));
581
582    this.undefined = isUndefined;
583    GB.browser = this.browser = detechBrowser();
584
585    if (this.undefined(document.execCommand)) {
586        alert('현재 브라우저에서 CHEditor를 실행할 수 없습니다.');
587        return null;
588    }
589    if (this.browser.msie && this.browser.version < 7) {
590        alert('CHEditor는 Internet Explorer 7 이하 버전은 지원하지 않습니다.');
591        return null;
592    }
593
594    try {
595        setConfig.call(this);
596        this.cheditor.id = (this.undefined(GB.readyEditor)) ? 1 : GB.readyEditor++;
597    } catch (e) {
598        alert(e.toString());
599        return null;
600    }
601
602    return this;
603}
604
605cheditor.prototype = {
606    //----------------------------------------------------------------
607    resetData : function () {
608        if (GB.browser.msie) {
609            if (this.undefined(this.cheditor.editArea.onreadystatechange)) {
610                GB.browser.version = 11;
611            }
612            GB.browser.msie_bogus = (GB.browser.version < 8 || GB.browser.version > 10);
613            document.execCommand('BackgroundImageCache', false, true);
614        }
615        this.resetEditArea();
616    },
617
618    appendContents : function (contents) {
619        var div = this.doc.createElement('div');
620        this.editAreaFocus();
621        div.innerHTML = String(this.trimSpace(contents));
622
623        while (div.hasChildNodes()) {
624            this.doc.body.appendChild(div.firstChild);
625        }
626        this.editAreaFocus();
627    },
628
629    insertContents : function (contents) {
630        this.editAreaFocus();
631        this.doCmdPaste(String(this.trimSpace(contents)));
632    },
633
634    replaceContents : function (contents) {
635        this.editAreaFocus();
636        this.doc.body.innerHTML = '';
637        this.loadContents(contents);
638        this.editAreaFocus();
639    },
640
641    loadContents : function (contents) {
642        if (typeof contents === 'string') {
643            contents = this.trimSpace(contents);
644            if (contents) {
645                this.cheditor.editArea.style.visibility = 'hidden';
646                this.doc.body.innerHTML = contents;
647                this.cheditor.editArea.style.visibility = 'visible';
648            }
649        }
650    },
651
652    setFolderPath : function () {
653        if (this.config.editorPath.charAt(this.config.editorPath.length - 1) !== '/') {
654            this.config.editorPath += '/';
655        }
656        this.config.iconPath = this.config.editorPath + 'icons/';
657        this.config.cssPath = this.config.editorPath + 'css/';
658        this.config.popupPath = this.config.editorPath + 'popup/';
659    },
660
661    checkInputForm : function () {
662        var textarea = document.getElementById(this.inputForm);
663        if (!textarea) {
664            throw 'ID가 "' + this.inputForm + '"인 textarea 개체를 찾을 수 없습니다.';
665        }
666        textarea.style.display = 'none';
667        this.cheditor.textarea = textarea;
668    },
669
670    setDesignMode : function (designMode, doc) {
671        var mode = designMode ? 'on' : 'off';
672
673        doc = doc || this.doc;
674        if (GB.browser.msie) {
675            if (doc.body.contentEditable !== designMode) {
676                doc.body.contentEditable = designMode;
677            }
678            return;
679        }
680        if (doc.designMode !== mode) {
681            doc.designMode = mode;
682        }
683    },
684
685    openDoc : function (doc, contents) {
686        var html = '<html>' +
687            '<head><title>' + this.config.docTitle + '</title>' +
688            '<style></style></head><body>';
689
690        doc.open();
691
692        if (typeof contents === 'string') {
693            html += this.trimSpace(contents);
694        }
695
696        html += '</body></html>';
697        doc.write(html);
698        doc.close();
699    },
700
701    getWindowHandle : function (iframeObj) {
702        var iframeWin;
703        if (iframeObj.contentWindow) {
704            iframeWin = iframeObj.contentWindow;
705        } else {
706            throw '현재 브라우저에서 에디터를 실행할 수 없습니다.';
707        }
708        return iframeWin;
709    },
710
711    resetDoc : function () {
712        if (this.undefined(this.cheditor.editArea)) {
713            return false;
714        }
715        try {
716            this.editArea = this.getWindowHandle(this.cheditor.editArea);
717            this.doc = GB.browser.msie ? this.editArea.document : this.cheditor.editArea.contentDocument;
718            this.resetData();
719            return true;
720        } catch (e) {
721            alert(e.toString());
722            return false;
723        }
724    },
725
726    resetEditArea : function () {
727        this.openDoc(this.doc, this.cheditor.textarea.value);
728        this.setDocumentProp();
729    },
730
731    resetDocumentBody : function () {
732        this.doc.body.parentNode.replaceChild(this.doc.createElement('body'), this.doc.body);
733        this.setDocumentBodyProp();
734    },
735
736    setDocumentBodyProp : function () {
737        this.doc.body.setAttribute('spellcheck', 'false');
738        this.doc.body.setAttribute('hidefocus', '');
739    },
740
741    setDocumentProp : function () {
742        var oSheet,
743            bodyCss = 'font-size:' + this.config.editorFontSize +
744                '; font-family:' + this.config.editorFontName +
745                '; color:' + this.config.editorFontColor +
746                '; margin:' + this.config.editAreaMargin +
747                '; line-height:' + this.config.lineHeight,
748            tableCss = 'font-size:' + this.config.editorFontSize + '; line-height:' + this.config.lineHeight,
749            self = this;
750
751        this.setDefaultCss({css: 'editarea.css', doc: this.doc});
752
753        oSheet = this.doc.styleSheets[0];
754        if (!this.W3CRange) {
755            oSheet.addRule('body', bodyCss);
756            oSheet.addRule('table', tableCss);
757        } else {
758            oSheet.insertRule('body {' + bodyCss + '}', 0);
759            oSheet.insertRule('table {' + tableCss + '}', 1);
760        }
761
762        this.setDocumentBodyProp();
763        this.cheditor.bogusSpacerName = 'ch_bogus_spacer';
764
765        this.addEvent(this.doc, 'paste', function (event) {
766            self.handlePaste(event);
767        });
768
769        if (!GB.browser.msie) {
770            this.doc.execCommand('defaultParagraphSeparator', false, 'p');
771        }
772
773        this.setDesignMode(true);
774        this.initDefaultParagraphSeparator();
775    },
776
777    initDefaultParagraphSeparator : function () {
778        var p = this.doc.createElement('p'), br;
779
780        if (this.doc.body.firstChild && this.doc.body.firstChild.nodeName.toLowerCase() === 'br') {
781            this.doc.body.removeChild(this.doc.body.firstChild);
782        }
783
784        if (this.W3CRange) {
785            if (!this.doc.body.hasChildNodes()) {
786                this.doc.body.appendChild(p);
787                if (!GB.browser.msie && !GB.browser.edge) {
788                    br = this.doc.createElement('br');
789                    br.className = this.cheditor.bogusSpacerName;
790                    p.appendChild(br);
791                    this.placeCaretAt(p, false);
792                } else {
793                    this.placeCaretAt(p, false);
794                }
795            }
796        } else {
797            this.doc.body.appendChild(p);
798            this.placeCaretAt(p, false);
799        }
800    },
801
802    handleBeforePaste : function () {
803        var range = this.getRange(), commonAncestorContainer, startOffset, wrapper;
804        this.backupRange();
805
806        if (!range.collapsed) {
807            range.deleteContents();
808            range = this.getRange();
809        }
810
811        commonAncestorContainer = range.commonAncestorContainer;
812        startOffset = range.startOffset;
813        wrapper = this.doc.createElement('div');
814
815        if (startOffset < 1 && commonAncestorContainer.nodeType === GB.node.text) {
816            commonAncestorContainer.parentNode.insertBefore(wrapper, commonAncestorContainer);
817        } else {
818            range.insertNode(wrapper);
819        }
820
821        this.placeCaretAt(wrapper, false);
822        return wrapper;
823    },
824
825    handlePaste : function (ev) {
826        var text, clip, elem, wrapper, pNode, space = [], div, self = this;
827        if (this.cheditor.mode === 'preview') {
828            return;
829        }
830        if (this.cheditor.paste !== 'text' && this.cheditor.mode === 'rich' && this.W3CRange) {
831            wrapper = this.handleBeforePaste();
832            setTimeout(function () {
833                if (wrapper) {
834                    if (wrapper.hasChildNodes()) {
835                        text = wrapper.innerHTML;
836                        text = text.replace(/[\r\n]/g, '');
837                        text = text.replace(/<font\s?([^>]+)>(\s+|&nbsp;+)<\/font>/gi, '\u00a0');
838                        text = text.replace(/<span\s?([^>]+)>(\s+|&nbsp;+)<\/span>/gi, '\u00a0');
839                        text = text.replace(/<\/?(font)\s?([^>]+)?>/gi, '');
840                        text = text.replace(/<strong>([\s&nbsp;]+)<\/strong>/gi, '\u00a0');
841                        text = text.replace(/<b>([\s&nbsp;]+)<\/b>/gi, '\u00a0');
842                        text = text.replace(/<em>([\s&nbsp;]+)<\/em>/gi, '\u00a0');
843                        text = text.replace(/<i>([\s&nbsp;]+)<\/i>/gi, '\u00a0');
844                        text = text.replace(/<\/?(colgroup|col\s?([^>]+))>/gi, '');
845                        text = text.replace(/<(\/)?strong>/gi, '<$1b>');
846                        text = text.replace(/<(\/)?em>/gi, '<$1i>');
847
848                        wrapper.innerHTML = text;
849                        if (wrapper.firstChild.nodeType === GB.node.text) {
850                            text = wrapper.firstChild.data;
851                            text = text.replace(/^(&nbsp;+|\s+)/g, '');
852                            wrapper.firstChild.data = text;
853                        }
854
855                        elem = wrapper.firstChild;
856                        while (elem) {
857                            wrapper.parentNode.insertBefore(elem, wrapper);
858                            elem = wrapper.firstChild;
859                        }
860                    }
861
862                    pNode = wrapper.parentNode;
863                    if (pNode) {
864                        if (pNode.firstChild === wrapper && pNode.lastChild === wrapper) {
865                            pNode.parentNode.removeChild(pNode);
866                        } else {
867                            pNode.removeChild(wrapper);
868                        }
869                    }
870                    self.setImageEvent(true);
871                }
872            }, 50);
873            return;
874        }
875
876        if (ev !== null) {
877            clip = ev.clipboardData;
878            this.stopEvent(ev);
879        }
880
881        text = this.trimSpace((this.undefined(clip) || clip === null) ?
882            window.clipboardData.getData('Text') :
883                clip.getData('text/plain'));
884
885        if (text !== '') {
886            text = text.replace(/\r/g, '');
887            if (this.cheditor.mode === 'code') {
888                div = this.doc.createElement('div');
889                text = this.htmlEncode(text);
890                text = text.replace(/\s{2,}/gm, '\n');
891                text = text.replace(/[\u200b\ufeff\xa0\u3000]+/g, '');
892
893                if (GB.browser.msie && GB.browser.version < 9) {
894                    text = text.replace(/\n/g, '<br />');
895                    text = text.replace(/\t/g, '__CHEDITOR_TAB_SPACE__');
896                    text = text.replace(/\s/gm, '&nbsp;');
897                }
898                div.innerHTML = text;
899                div.id = 'clipboardData';
900                this.insertHTML(div);
901                return;
902            }
903
904            text = this.htmlEncode(text);
905            text = text.replace(/[\r\n]+/g, '\n');
906            text = text.split('\n').join('<br>');
907
908            text = text.replace(/(\s{2,})/g, function (a, b) {
909                space = b.split(/\s/);
910                space.shift();
911                return ' ' + space.join('&nbsp;');
912            });
913            this.insertHTML(text);
914            self.setImageEvent(true);
915        }
916    },
917
918    editAreaFocus : function () {
919	    this.editArea.focus();
920    },
921
922    resizeGetY : function (evt) {
923        return GB.browser.msie ?
924                window.event.clientY + document.documentElement.scrollTop + document.body.scrollTop :
925                    evt.clientY + window.pageYOffset;
926    },
927
928    resizeStart : function (evt) {
929        var self = this;
930        self.currentRS.elNode = self.cheditor.mode === 'code' ? self.cheditor.textContent : self.cheditor.editArea;
931        self.currentRS.cursorStartY = self.resizeGetY(evt);
932        self.currentRS.elStartTop = parseInt(self.currentRS.elNode.style.height, 10);
933
934        if (isNaN(self.currentRS.elStartTop)) {
935            self.currentRS.elStartTop = 0;
936        }
937
938        evt = evt || window.event;
939
940        self.resizeEditor.stopFunc = function (event) {
941            self.resizeStop(event);
942        };
943        self.resizeEditor.moveFunc = function (event) {
944            self.resizeMove(event);
945        };
946
947        if (GB.browser.msie) {
948            self.setDesignMode(false);
949        }
950
951        self.currentRS.elNode.style.visibility = 'hidden';
952        self.addEvent(document, 'mousemove', self.resizeEditor.moveFunc);
953        self.addEvent(document, 'mouseup', self.resizeEditor.stopFunc);
954        self.stopEvent(evt);
955    },
956
957    resizeMove : function (evt) {
958        var offset = this.resizeGetY(evt),
959            height = this.currentRS.elStartTop + offset - this.currentRS.cursorStartY;
960        if (height < 1) {
961            this.resizeStop(evt);
962            height = 1;
963        }
964        this.config.editorHeight = this.currentRS.elNode.style.height = height + 'px';
965        this.stopEvent(evt);
966    },
967
968    resizeStop : function (evt) {
969        this.stopEvent(evt);
970        this.removeEvent(document, 'mouseup', this.resizeEditor.stopFunc);
971        this.removeEvent(document, 'mousemove', this.resizeEditor.moveFunc);
972        this.currentRS.elNode.style.visibility = 'visible';
973        if (GB.browser.msie) {
974            this.setDesignMode(true);
975        }
976        if (this.cheditor.mode === 'code') {
977            this.config.editorHeight = (parseInt(this.config.editorHeight, 10)
978                + parseInt(this.cheditor.textContent.getAttribute('xbar-height'), 10)) + 'px';
979            this.cheditor.textContent.focus();
980        } else if (this.cheditor.mode === 'rich') {
981            this.editAreaFocus();
982        }
983    },
984
985    switchEditorMode : function (changeMode) {
986        var self = this, i, className, interval;
987
988        this.editAreaFocus();
989        if (this.cheditor.mode === changeMode) {
990            return;
991        }
992
993        for (i in this.cheditor.modetab) {
994            if (this.cheditor.modetab.hasOwnProperty(i)) {
995                className = this.cheditor.modetab[i].className;
996                className = className.replace(/\-off$/, '');
997                if (i !== changeMode) {
998                    this.cheditor.modetab[i].className = className + '-off';
999                } else {
1000                    this.cheditor.modetab[i].className = className;
1001                }
1002            }
1003        }
1004
1005        switch (changeMode) {
1006            case 'rich' :
1007                this.richMode();
1008                this.showTagSelector(true);
1009                break;
1010            case 'code' :
1011                if (this.cheditor.modifyState) {
1012                    interval = setInterval(function () {
1013                        if (!self.cheditor.modifyState) {
1014                            clearInterval(interval);
1015                            self.editMode();
1016                        }
1017                    }, 10);
1018                } else {
1019                    this.editMode();
1020                }
1021                this.showTagSelector(false);
1022                break;
1023            case 'preview' :
1024                this.previewMode();
1025                this.showTagSelector(false);
1026        }
1027        this.cheditor.mode = changeMode;
1028    },
1029
1030    initTemplate : function () {
1031        var self = this,
1032            httpRequest = null,
1033            showError = function (msg) {
1034                alert(self.templateFile + ' 파일 로딩 중 오류가 발생하였습니다.\n원인: ' + msg);
1035            },
1036            templateReady = function () {
1037                var event;
1038                if (httpRequest.readyState === 4) {
1039                    if (httpRequest.status === 200) {
1040                        try {
1041                            self.xmlDoc =  httpRequest.responseXML || httpRequest;
1042                            self.loadTemplate(self.xmlDoc);
1043                            if (self.W3CRange) {
1044                                event = document.createEvent('Event');
1045                                event.initEvent(self.cheditor.id, true, true);
1046                                document.dispatchEvent(event);
1047                            } else {
1048                                document.documentElement.loadEvent = self.cheditor.id;
1049                            }
1050                        } catch (e) {
1051                            showError(e.toString());
1052                        }
1053                    } else {
1054                        showError('XMLHttpRequest. Status ' + httpRequest.status);
1055                    }
1056                }
1057            };
1058
1059        if (window.XMLHttpRequest) {
1060            httpRequest = new XMLHttpRequest();
1061            if (httpRequest.overrideMimeType) {
1062                httpRequest.overrideMimeType('text/xml');
1063            }
1064            httpRequest.onreadystatechange = templateReady;
1065            try {
1066                httpRequest.open('GET', self.templatePath, true);
1067            }
1068            catch (e) {
1069                showError(e + '참고: 에디터를 웹 서버에서 실행하여 주십시오.');
1070            }
1071            httpRequest.send();
1072        } else if (window.ActiveXObject) {
1073            httpRequest = new window.ActiveXObject('Microsoft.XMLDOM');
1074            httpRequest.async = true;
1075            httpRequest.onreadystatechange = templateReady;
1076            httpRequest.load(self.templatePath);
1077        } else {
1078            showError('현재 브라우저에서 ' + self.templateFile + ' 파일ì
1078„ 사용할 수 없습니다.');
1079        }
1080    },
1081
1082	getCDATASection : function (node) {
1083        var text = node.textContent || node.text;
1084        text = text.replace(/\n/g, '');
1085        text = text.replace(/(\s+?)<([^>]*)>/g, '<$2>');
1086        text = this.trimSpace(text);
1087        return text;
1088    }, 
1089
1090    setToolbarBgPosition : function (elem, attr) {
1091        elem.style.backgroundPosition = attr;
1092    },
1093
1094    getToolbarBgPosition : function (elem) {
1095        var pos;
1096        switch (elem.className) {
1097            case 'cheditor-tb-bg'           : pos = 3; break;
1098            case 'cheditor-tb-bg-last'      : pos = 6; break;
1099            case 'cheditor-tb-bg-single'    : pos = 9; break;
1100            case 'cheditor-tb-bg30-first'   : pos = 12; break;
1101            case 'cheditor-tb-bg30'         : pos = 15; break;
1102            case 'cheditor-tb-bg30-last'    : pos = 18; break;
1103            case 'cheditor-tb-bg55'         : pos = 21; break;
1104            case 'cheditor-tb-bg40'         : pos = 24; break;
1105            case 'cheditor-tb-bg44'         : pos = 27; break;
1106            case 'cheditor-tb-bgcombo'      : pos = 30; break;
1107            case 'cheditor-tb-bgcombo-last' : pos = 33; break;
1108            default : pos = 0;
1109        }
1110        return pos;
1111    },
1112
1113    toolbarMouseOverUp : function (elem) {
1114        var pos, obj;
1115        if (elem.checked) {
1116            return;
1117        }
1118        this.setToolbarBgPosition(elem.button, '0 ' + (~(((elem.pos + 1) * elem.height)) + 1) + 'px');
1119
1120        if ((elem.name === 'combobox' && elem.prev && elem.prev.checked) ||
1121                (elem.name === 'combo' && elem.next && elem.next.checked)) {
1122            return;
1123        }
1124        if (elem.type === 'combobox') {
1125            if (elem.prev.checked) {
1126                return;
1127            }
1128            obj = elem.prev;
1129            pos = '0px ' + (~(((obj.pos + 1) * obj.height)) + 1) + 'px';
1130            this.setToolbarBgPosition(obj.button, pos);
1131        } else if (elem.type === 'combo') {
1132            if (elem.prev && !elem.prev.checked && !elem.prev.active) {
1133                obj = elem.prev;
1134                pos = (~(obj.width) + 1) + 'px ' + (~(obj.pos * obj.height) + 1) + 'px';
1135                this.setToolbarBgPosition(obj.button, pos);
1136            }
1137            if (elem.next) {
1138                if (elem.next.checked) {
1139                    return;
1140                }
1141                obj = elem.next;
1142                pos = (~(obj.width) + 1) + 'px ' + (~(((obj.pos + 1) * obj.height)) + 1) + 'px';
1143                this.setToolbarBgPosition(obj.button, pos);
1144            }
1145        } else {
1146            if (!elem.prev || (elem.prev && elem.prev.checked)) {
1147                return;
1148            }
1149            obj = elem.prev;
1150            if (obj.className === 'cheditor-tb-bg-first') {
1151                pos = (~(obj.width) + 1) + 'px 0';
1152            } else {
1153                pos = (~(obj.width) + 1) + 'px ' + (~(obj.pos * obj.height) + 1) + 'px';
1154            }
1155            this.setToolbarBgPosition(obj.button, pos);
1156        }
1157    },
1158
1159    toolbarMouseDownOut : function (elem, mousedown) {
1160        if (elem.next && elem.next.checked && !mousedown) {
1161            this.setToolbarBgPosition(elem.button, (~(elem.width * 2) + 1) + 'px ' +
1162                (~(elem.pos * elem.height) + 1) + 'px');
1163        }
1164        if (elem.prev) {
1165            if (elem.prev.active || (elem.prev.type === 'combo' && elem.checked)) {
1166                return;
1167            }
1168            if (elem.prev.checked) {
1169                this.setToolbarBgPosition(elem.prev.button, '0 ' +
1170                    (~((elem.prev.pos + 2) * elem.prev.height) + 1) + 'px');
1171                return;
1172            }
1173            if (mousedown) {
1174                this.setToolbarBgPosition(elem.prev.button, (~(elem.prev.width * 2) + 1) + 'px ' +
1175                    (~(elem.prev.pos * elem.prev.height) + 1) + 'px');
1176            } else {
1177                this.setToolbarBgPosition(elem.prev.button,
1178                    '0 ' + (~(elem.prev.pos * elem.prev.height) + 1) + 'px');
1179            }
1180        }
1181    },
1182
1183    toolbarButtonChecked : function (elem) {
1184        this.setToolbarBgPosition(elem.button, '0 ' + (~((elem.pos + 2) * elem.height) + 1) + 'px');
1185        if (elem.prev && elem.prev.type === 'combo') {
1186            if (elem.prev.checked || elem.checked) {
1187                return;
1188            }
1189            this.setToolbarBgPosition(elem.prev.button, (~(elem.prev.width * 2) + 1) + 'px ' +
1190                (~(elem.prev.pos * elem.prev.height) + 1) + 'px');
1191        }
1192        if (elem.prev && !elem.prev.checked) {
1193            if (elem.checked) {
1194                this.setToolbarBgPosition(elem.prev.button, (~(elem.prev.width * 2) + 1) + 'px ' +
1195                    (~(elem.prev.pos * elem.prev.height) + 1) + 'px');
1196            } else {
1197                this.setToolbarBgPosition(elem.prev.button, '0 ' + (~(elem.prev.pos * elem.prev.height) + 1) + 'px');
1198            }
1199        }
1200    },
1201
1202    toolbarButtonUnchecked : function (elem) {
1203        if (elem.type === 'combobox' && !elem.checked) {
1204            if (elem.prev.checked) {
1205                this.setToolbarBgPosition(elem.button,
1206                    (~(elem.width) + 1) + 'px ' + (~(((elem.pos + 1) * elem.height)) + 1) + 'px');
1207                return;
1208            }
1209            this.setToolbarBgPosition(elem.prev.button, '0 ' + (~(elem.prev.pos * elem.prev.height) + 1) + 'px');
1210        }
1211        this.setToolbarBgPosition(elem.button, '0 ' + (~(elem.pos * elem.height) + 1) + 'px');
1212        if (elem.prev && elem.prev.name === 'BackColor') {
1213            this.setToolbarBgPosition(elem.prev.button, '0 ' + (~(elem.prev.pos * elem.prev.height) + 1) + 'px');
1214        }
1215    },
1216
1217    makeToolbarGrayscale : function (image) {
1218        var context, imageData, filter, imgWidth = image.width, imgHeight = image.height,
1219            canvas = this.doc.createElement('canvas');
1220
1221        filter = function (pixels) {
1222            var d = pixels.data, i, r, g, b;
1223            for (i = 0; i < d.length; i += 4) {
1224                r = d[i];
1225                g = d[i + 1];
1226                b = d[i + 2];
1227                d[i] = d[i + 1] = d[i + 2] = (r + g + b) / 3;
1228            }
1229            return pixels;
1230        };
1231
1232        context = canvas.getContext('2d');
1233        canvas.width = imgWidth;
1234        canvas.height = imgHeight;
1235        context.drawImage(image, 0, 0);
1236
1237        imageData = context.getImageData(0, 0, imgWidth, imgHeight);
1238        filter(imageData);
1239        context.putImageData(imageData, 0, 0);
1240        return canvas.toDataURL();
1241    },
1242
1243    toolbarSetBackgroundImage : function (elem, disable) {
1244        var css = elem.firstChild.className,
1245            tbEnable = (this.cheditor.toolbarGrayscale && elem.firstChild.style.backgroundImage);
1246
1247        css = css.replace(/-disable$/i, '');
1248        if (disable) {
1249            if (tbEnable) {
1250                elem.firstChild.style.backgroundImage = 'url(' + this.cheditor.toolbarGrayscale + ')';
1251            }
1252            css = css + '-disable';
1253            elem.style.cursor = 'default';
1254        } else {
1255            if (tbEnable) {
1256                elem.firstChild.style.backgroundImage = 'url(' + this.toolbar.icon + ')';
1257            }
1258            elem.style.cursor = 'pointer';
1259        }
1260        elem.firstChild.className = css;
1261    },
1262
1263    toolbarDisable : function (elem, disable) {
1264        if (disable) {
1265            this.toolbarSetBackgroundImage(elem.button, true);
1266            this.toolbarButtonUnchecked(elem);
1267            this.toolbarMouseDownOut(elem);
1268            this.toolbar[elem.name].disabled = true;
1269            return true;
1270        }
1271        this.toolbarSetBackgroundImage(elem.button, false);
1272        this.toolbar[elem.name].disabled = false;
1273        return false;
1274    },
1275
1276    colorConvert : function (color, which, opacity) {
1277        var colorDefs = [
1278            {
1279                re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
1280                process : function (bits) {
1281                    return [
1282                        parseInt(bits[1], 10),
1283                        parseInt(bits[2], 10),
1284                        parseInt(bits[3], 10),
1285                        1
1286                    ];
1287                }
1288            },
1289            {
1290                re : /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*(\d+(?:\.\d+)?|\.\d+)\s*\)/,
1291                process : function (bits) {
1292                    return [
1293                        parseInt(bits[1], 10),
1294                        parseInt(bits[2], 10),
1295                        parseInt(bits[3], 10),
1296                        parseFloat(bits[4])
1297                    ];
1298                }
1299            },
1300            {
1301                re: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
1302                process : function (bits) {
1303                    return [
1304                        parseInt(bits[1], 16),
1305                        parseInt(bits[2], 16),
1306                        parseInt(bits[3], 16),
1307                        1
1308                    ];
1309                }
1310            },
1311            {
1312                re: /^([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])$/,
1313                process : function (bits) {
1314                    return [
1315                        parseInt(bits[1] * 2, 16),
1316                        parseInt(bits[2] * 2, 16),
1317                        parseInt(bits[3] * 2, 16),
1318                        1
1319                    ];
1320                }
1321            }
1322        ], r = null, g = null, b = null, a = null, i, re, processor, bits, channels, min, rData = null;
1323
1324        if (!which) {
1325            which = 'rgba';
1326        }
1327
1328        color = color.replace(/^\s*#|\s*$/g, '');
1329        if (color.length === 3) {
1330            color = color.replace(/(.)/g, '$1$1');
1331        }
1332
1333        color = color.toLowerCase();
1334        which = which.toLowerCase();
1335
1336        for (i = 0; i < colorDefs.length; i++) {
1337            re = colorDefs[i].re;
1338            processor = colorDefs[i].process;
1339            bits = re.exec(color);
1340            if (bits) {
1341                channels = processor(bits);
1342                r = channels[0];
1343                g = channels[1];
1344                b = channels[2];
1345                a = channels[3];
1346            }
1347        }
1348
1349        r = (r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r);
1350        g = (g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g);
1351        b = (b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b);
1352        a = (a < 0 || isNaN(a)) ? 0 : ((a > 1) ? 1 : a);
1353
1354        function hex(x) {
1355            return ('0' + parseInt(x, 10).toString(16)).slice(-2);
1356        }
1357
1358        switch (which) {
1359            case 'rgba':
1360                if (opacity) {
1361                    a = (255 - (min = Math.min(r, g, b))) / 255;
1362                    r = ((r - min) / a).toFixed(0);
1363                    g = ((g - min) / a).toFixed(0);
1364                    b = ((b - min) / a).toFixed(0);
1365                    a = a.toFixed(4);
1366                }
1367                rData = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
1368                break;
1369            case 'rgb':
1370                rData = 'rgb(' + r + ',' + g + ',' + b + ')';
1371                break;
1372            case 'hex':
1373                if (isNaN(parseInt(r, 10)) || isNaN(parseInt(g, 10)) || isNaN(parseInt(b, 10))) {
1374                    return color;
1375                }
1376                rData = '#' + hex(r) + hex(g) + hex(b);
1377                break;
1378        }
1379        return rData;
1380    },
1381
1382    toolbarUpdate : function (srcElement) {
1383        var toolbar = this.toolbar,
1384            range = this.getRange(),
1385            isCollapsed = this.rangeCollapsed(range),
1386            sType = GB.selection.text,
1387            bControl = false, bTable = false, ancestorsLen = 0, bNoOff = { 'Link': 1 }, ancestors = [],
1388            i, j, btn, cmd, autoOff, bDisable, el, wrapper, fontAttr, oldName, span, newAttr, defaultAttr,
1389            state, css, node, alignment, pNode;
1390
1391        pNode = srcElement || this.getRangeElement(range);
1392        switch (pNode.nodeType) {
1393            case GB.node.element:
1394                sType = GB.selection.element;
1395                break;
1396            case GB.node.text:
1397                sType = GB.selection.text;
1398                pNode = pNode.parentNode;
1399                break;
1400            default:
1401                return;
1402        }
1403
1404        if (sType === GB.selection.element && !isCollapsed) {
1405            bControl = GB.offElementTags[pNode.nodeName.toLowerCase()];
1406        } else {
1407            node = pNode;
1408            while (node && node.nodeType === GB.node.element && node.nodeName.toLowerCase() !== 'body') {
1409                ancestors.push(node);
1410                if (node.nodeName.toLowerCase() === 'td' || node.nodeName.toLowerCase() === 'th') {
1411                    bTable = true;
1412                }
1413                node = node.parentNode;
1414            }
1415            ancestorsLen = ancestors.length;
1416        }
1417
1418        if (!bTable && sType === GB.selection.element &&
1419            (pNode.nodeName.toLowerCase() === 'table' || pNode.nodeName.toLowerCase() === 'td' ||
1420             pNode.nodeName.toLowerCase() === 'th')) {
1421            bTable = true;
1422        }
1423
1424        alignment = { JustifyCenter : 'center', JustifyRight : 'right', JustifyFull : 'justify' };
1425
1426        for (i in toolbar) {
1427            if (!toolbar.hasOwnProperty(i)) {
1428                continue;
1429            }
1430
1431            btn = toolbar[i];
1432            if (!btn.cmd) {
1433                continue;
1434            }
1435
1436            cmd = btn.cmd;
1437            autoOff = false;
1438
1439            if (bControl && sType === GB.selection.element) {
1440                if (btn.group !== 'Alignment') {
1441                    autoOff = !(pNode.nodeName.toLowerCase() === 'img' && bNoOff[cmd]);
1442                }
1443            }
1444
1445            if (btn.name === 'ModifyTable') {
1446                autoOff = !bTable;
1447            }
1448
1449            bDisable = this.toolbarDisable(btn, autoOff);
1450
1451            if (btn.name === 'ForeColor' || btn.name === 'BackColor') {
1452                btn.button.lastChild.style.display = bDisable ? 'none' : 'block';
1453            }
1454            if (btn.autocheck === null) {
1455                continue;
1456            }
1457
1458            switch (cmd) {
1459                case 'Copy' :
1460                case 'Cut'  :
1461                    this.toolbarDisable(btn, isCollapsed);
1462                    break;
1463                case 'UnLink' :
1464                    if (GB.browser.firefox) {
1465                        this.toolbarDisable(btn, (pNode.nodeName.toLowerCase() !== 'a' && !pNode.getAttribute('href')));
1466                    } else {
1467                        this.toolbarDisable(btn, this.doc.queryCommandEnabled(cmd) === false);
1468                    }
1469                    break;
1470                case 'FormatBlock' :
1471                    wrapper = btn.button.firstChild;
1472                    oldName = wrapper.firstChild;
1473                    el = false;
1474                    span = document.createElement('span');
1475                    for (j = 0; j < ancestorsLen; j++) {
1476                        if (GB.formatBlock[ancestors[j].nodeName]) {
1477                            span.appendChild(document.createTextNode(ancestors[j].nodeName));
1478                            wrapper.replaceChild(span, oldName);
1479                            el = true;
1480                            break;
1481                        }
1482                    }
1483                    if (!el) {
1484                        span.appendChild(document.createTextNode('스타일'));
1485                        wrapper.replaceChild(span, oldName);
1486                    }
1487                    this.unselectionElement(span);
1488                    break;
1489                case 'ForeColor' :
1490                case 'BackColor' :
1491                    if (cmd === 'BackColor' && !GB.browser.msie) {
1492                        cmd = 'HiliteColor';
1493                    }
1494                    fontAttr = this.doc.queryCommandValue(cmd);
1495                    if (fontAttr && !/^[rgb|#]/.test(fontAttr)) {
1496                        fontAttr = (((fontAttr & 0x0000ff) << 16) | (fontAttr & 0x00ff00) | ((fontAttr & 0xff0000) >>> 16)).toString(16);
1497                        fontAttr = '#000000'.slice(0, 7 - fontAttr.length) + fontAttr;
1498                    } else {
1499                        fontAttr = (cmd === 'ForeColor') ? this.config.editorFontColor : this.config.editorBgColor;
1500                    }
1501                    btn.button.lastChild.style.backgroundColor = fontAttr;
1502                    break;
1503                case 'FontName' :
1504                case 'FontSize' :
1505                    fontAttr = this.doc.queryCommandValue(cmd);
1506                    wrapper = btn.button.firstChild;
1507                    span = this.doc.createElement('span');
1508
1509                    if (cmd === 'FontSize') {
1510                        fontAttr = pNode.style.fontSize;
1511                        if (!fontAttr) {
1512                            for (i = 0; i < ancestors.length; i++) {
1513                                fontAttr = ancestors[i].style.fontSize;
1514                                if (fontAttr) {
1515                                    break;
1516                                }
1517                            }
1518                        }
1519                    }
1520                    if (fontAttr) {
1521                        newAttr = fontAttr;
1522                        newAttr = newAttr.replace(/'/g, '');
1523                        span.appendChild(this.doc.createTextNode(newAttr));
1524                        wrapper.replaceChild(span, wrapper.firstChild);
1525                    }
1526                    if (!span.hasChildNodes()) {
1527                        defaultAttr = (cmd === 'FontSize') ? this.config.editorFontSize : this.config.editorFontName;
1528                        if (wrapper.hasChildNodes()) {
1529                            wrapper.removeChild(wrapper.firstChild);
1530                        }
1531                        defaultAttr = defaultAttr.replace(/'/g, '');
1532                        span.appendChild(this.doc.createTextNode(defaultAttr));
1533                        wrapper.appendChild(span);
1534                    }
1535                    this.unselectionElement(span);
1536                    break;
1537                case 'LineHeight':
1538                    wrapper = btn.button.firstChild;
1539                    this.unselectionElement(wrapper.firstChild);
1540                    break;
1541                default :
1542                    if (!this.doc.queryCommandSupported(cmd)) {
1543                        continue;
1544                    }
1545                    state = this.doc.queryCommandState(cmd);
1546                    if (state === null) {
1547                        continue;
1548                    }
1549
1550                    if (GB.browser.msie && state === false && alignment[cmd]) {
1551                        el = pNode;
1552                        while (el && el.nodeName.toLowerCase() !== 'body') {
1553                            if (GB.lineHeightBlockTags[el.nodeName.toLowerCase()]) {
1554                                css = this.getCssValue(el);
1555                                if (css) {
1556                                    for (j = 0; j < css.length; j++) {
1557                                        if (css[j].name.toLowerCase() === 'text-align' && css[j].value === alignment[cmd]) {
1558                                            state = true;
1559                                            break;
1560                                        }
1561                                    }
1562                                }
1563                            }
1564                            el = el.parentNode;
1565                        }
1566                    }
1567
1568                    if (state) {
1569                        btn.checked = true;
1570                        this.toolbarButtonChecked(btn);
1571                        if (btn.type === 'combo' && btn.name === btn.next.node) {
1572                            btn.next.active = true;
1573                            this.setToolbarBgPosition(btn.next.button,
1574                                (~(btn.next.width) + 1) + 'px ' + (~(((btn.next.pos + 1) * btn.next.height)) + 1) + 'px');
1575                        }
1576                    } else {
1577                        this.toolbarButtonUnchecked(btn);
1578                        btn.checked = false;
1579                        if (btn.next) {
1580                            btn.next.active = false;
1581                            if (btn.type === 'combo' && btn.name === btn.next.node) {
1582                                this.toolbarButtonUnchecked(btn.next);
1583                            }
1584                        }
1585                    }
1586
1587            }
1588        }
1589    },
1590
1591    createButton : function (name, attr, prev) {
1592        var self = this,
1593            elem, icon, btnIcon, iconPos, method, cmd, check, type, node, btnHeight, btnWidth, text,
1594            span, obj, btnClass, comboOut;
1595
1596        method = attr.getElementsByTagName('Execution')[0].getAttribute('method');
1597        cmd = attr.getElementsByTagName('Execution')[0].getAttribute('value');
1598        check = attr.getAttribute('check');
1599        type = attr.getAttribute('type');
1600        node = attr.getAttribute('node');
1601
1602        btnClass = attr.getAttribute('class');
1603        btnWidth = attr.getAttribute('width');
1604        btnHeight = attr.getAttribute('height');
1605
1606        elem = document.createElement('div');
1607        elem.style.width = btnWidth + 'px';
1608        elem.setAttribute('name', name);
1609        elem.style.height = btnHeight + 'px';
1610        elem.style.border = '0px solid transparent';
1611
1612        icon = attr.getElementsByTagName('Icon')[0];
1613        btnIcon = document.createElement('div');
1614        btnIcon.className = icon.getAttribute('class');
1615        btnIcon.style.marginLeft = icon.getAttribute('margin') || '3px';
1616
1617        iconPos = icon.getAttribute('position');
1618        if (iconPos) {
1619            btnIcon.style.backgroundImage = 'url(' + self.toolbar.icon + ')';
1620            btnIcon.style.backgroundRepeat = 'no-repeat';
1621            self.setToolbarBgPosition(btnIcon, (~iconPos + 1) + 'px center');
1622        } else {
1623            text = icon.getAttribute('alt');
1624            if (text) {
1625                span = document.createElement('span');
1626                span.appendChild(document.createTextNode(text));
1627                btnIcon.appendChild(span);
1628            }
1629        }
1630
1631        elem.appendChild(btnIcon);
1632        obj = { 'autocheck': check,
1633                'button': elem,
1634                'className': btnClass,
1635                'checked': false,
1636                'cmd': cmd,
1637                'colorNode': {},
1638                'disabled': false,
1639                'group': '',
1640                'height': btnHeight,
1641                'method': method,
1642                'name': name,
1643                'next': null,
1644                'node': node,
1645                'num': 0,
1646                'pos': 0,
1647                'prev': prev,
1648                'type': type,
1649                'width': btnWidth };
1650
1651        if (prev) {
1652            prev.next = obj;
1653        }
1654
1655        elem.attr = obj;
1656        self.toolbar[name] = obj;
1657
1658        self.addEvent(elem, 'mouseover', function (ev) {
1659            if (!obj.disabled) {
1660                self.toolbarMouseOverUp(obj);
1661            }
1662            self.stopEvent(ev || window.event);
1663        });
1664
1665        self.addEvent(elem, 'mousedown', function (ev) {
1666            if (!obj.checked && !obj.disabled) {
1667                self.toolbarButtonChecked(obj);
1668                self.toolbarMouseDownOut(obj, true);
1669                if (obj.prev && obj.prev.type === 'combo' && !obj.prev.checked) {
1670                    self.setToolbarBgPosition(obj.prev.button,
1671                        '0 ' + (~((self.getToolbarBgPosition(obj.prev.button) + 1) * obj.prev.height) + 1) + 'px');
1672                }
1673            }
1674            if (obj.next) {
1675                obj.next.button.style.visibility = 'hidden';
1676                obj.next.button.style.visibility = 'visible';
1677            }
1678            self.stopEvent(ev || window.event);
1679        });
1680
1681        self.addEvent(elem, 'click', function (ev) {
1682            if (obj.disabled) {
1683                return;
1684            }
1685            switch (obj.method) {
1686                case 'doCmd' :
1687                    self.backupRange();
1688                    self.doCmd(obj.cmd, null);
1689                    break;
1690                case 'windowOpen' :
1691                    self.windowOpen(obj.cmd);
1692                    break;
1693                case 'showPulldown' :
1694                    if (obj.checked) {
1695                        obj.checked = false;
1696                        self.boxHideAll();
1697                        self.toolbarButtonUnchecked(obj);
1698                        return;
1699                    }
1700                    obj.checked = true;
1701                    self.showPulldown(obj.cmd, obj.button);
1702                    self.toolbarButtonChecked(obj);
1703                    self.toolbarMouseDownOut(obj, true);
1704                    break;
1705                default :
1706                    alert('지원하지 않는 명령입니다.');
1707            }
1708            self.stopEvent(ev || window.event);
1709        });
1710
1711        comboOut = function (combo, startPos) {
1712            self.setToolbarBgPosition(combo.button,
1713                startPos + 'px ' + (~(((self.getToolbarBgPosition(combo.button) + (combo.checked ? 2 : 1)) * combo.height)) + 1) + 'px');
1714        };
1715
1716        self.addEvent(elem, 'mouseout', function () {
1717            if (!obj.checked) {
1718                if (obj.type === 'combo') {
1719                    if (obj.next) {
1720                        if (!obj.next.checked) {
1721                            self.toolbarButtonUnchecked(obj.next);
1722                            self.toolbarMouseDownOut(obj.next, false);
1723                        } else {
1724                            return;
1725                        }
1726                    }
1727                }
1728                if (obj.type === 'combobox' && obj.prev.checked) {
1729                    self.setToolbarBgPosition(obj.button,
1730                        (~(obj.width) + 1) + 'px ' + (~(((obj.pos + 1) * obj.height)) + 1) + 'px');
1731                    return;
1732                }
1733                self.toolbarButtonUnchecked(obj);
1734                self.toolbarMouseDownOut(obj, false);
1735            } else {
1736                if (obj.node && obj.node === obj.prev.name) {
1737                    if (!obj.prev.checked) {
1738                        self.setToolbarBgPosition(obj.prev.button,
1739                            '0 ' + (~((self.getToolbarBgPosition(obj.prev.button) + 1) * obj.prev.height) + 1) + 'px');
1740                    }
1741                    comboOut(obj, 0);
1742                }
1743            }
1744        });
1745
1746        return obj;
1747    },
1748
1749    showToolbar : function (toolbar, toolbarWrapper) {
1750        var self = this,
1751            i, j, grpName, btn, btnLen, prevObj, attr, btnName, btnObj = null, btnNum, spacer,
1752            currentColor, fullscreen, child, len,
1753            toolbarIcon = toolbar.getElementsByTagName('Image').item(0).getAttribute('file'),
1754            tmpArr = toolbarIcon.split(/\./),
1755            group = toolbar.getElementsByTagName('Group'),
1756            grpNum = group.length,
1757            appendSpaceBlock = function (pNode) {
1758                var split = document.createElement('div');
1759                split.className = 'cheditor-tb-split';
1760                pNode.appendChild(split);
1761            },
1762            onClickEventHandler = function () {
1763                if (self.setFullScreenMode) {
1764                    this.className = 'cheditor-tb-fullscreen';
1765                    this.setAttribute('title', '전체 화면');
1766                } else {
1767                    this.className = 'cheditor-tb-fullscreen-actual';
1768                    this.setAttribute('title', '이전 크기로 복원');
1769                }
1770                self.fullScreenMode();
1771            };
1772
1773        self.toolbar.icon = self.config.iconPath + toolbarIcon;
1774        self.toolbar.iconDisable = self.config.iconPath + tmpArr[0] + '-disable' + '.' + tmpArr[1];
1775        toolbarWrapper.className = 'cheditor-tb-wrapper';
1776
1777        fullscreen = document.createElement('span');
1778        if (self.config.useFullScreen === true) {
1779            fullscreen.appendChild(document.createTextNode('\u00a0'));
1780            fullscreen.className = 'cheditor-tb-fullscreen';
1781            fullscreen.setAttribute('title', '전체 화면');
1782            (function () {
1783                fullscreen.onclick = onClickEventHandler;
1784            })();
1785        } else {
1786            fullscreen.clsaaName = 'cheditor-tb-fullscreen-disable';
1787        }
1788        toolbarWrapper.appendChild(fullscreen);
1789
1790        for (i = 0; i < grpNum; i++) {
1791            grpName = group[i].getAttribute('name');
1792            if (grpName === 'Split') {
1793                appendSpaceBlock(toolbarWrapper);
1794                continue;
1795            }
1796
1797            btn = group[i].getElementsByTagName('Button');
1798            btnLen = btn.length;
1799            btnNum = 0; btnObj = null;
1800
1801            for (j = 0; j < btnLen; j++) {
1802                attr = btn[j].getElementsByTagName('Attribute')[0];
1803                btnName = btn[j].getAttribute('name');
1804                if (!attr.getAttribute('node') && self.config['use' + btnName] !== true) {
1805                    continue;
1806                }
1807                if (attr.getAttribute('type') === 'combobox' && self.config['use' + attr.getAttribute('node')] !== true) {
1808                    continue;
1809                }
1810
1811                btnObj = self.createButton(btnName, attr, btnObj);
1812                self.toolbar[btnObj.name].num = btnNum++;
1813                self.toolbar[btnObj.name].group = grpName;
1814
1815                if (btn[j].getAttribute('tooltip') !== null) {
1816                    btnObj.button.setAttribute('title', btn[j].getAttribute('tooltip'));
1817                }
1818
1819                if (btnObj.name === 'ForeColor' || btnObj.name === 'BackColor') {
1820                    currentColor = document.createElement('div');
1821                    currentColor.className = 'cheditor-tb-color-btn';
1822                    currentColor.style.backgroundColor = attr.getAttribute('default');
1823                    btnObj.button.appendChild(currentColor);
1824                }
1825                toolbarWrapper.appendChild(btnObj.button);
1826            }
1827
1828            if (btnObj === null) {
1829                continue;
1830            }
1831
1832            prevObj = btnObj.prev;
1833
1834            if (!prevObj) {
1835                btnObj.button.className = btnObj.className;
1836                if (btnObj.className === 'cheditor-tb-bg') {
1837                    btnObj.className = btnObj.className + '-single';
1838                    btnObj.button.className = btnObj.className;
1839                }
1840                btnObj.pos = self.getToolbarBgPosition(btnObj.button);
1841            } else {
1842                btnObj.className = btnObj.className + '-last';
1843                btnObj.button.className = btnObj.className;
1844                btnObj.pos = self.getToolbarBgPosition(btnObj.button);
1845                while (prevObj) {
1846                    prevObj.button.className = prevObj.className;
1847                    prevObj.pos = self.getToolbarBgPosition(prevObj.button);
1848                    btnObj = prevObj;
1849                    prevObj = prevObj.prev;
1850                }
1851                btnObj.className = btnObj.className + '-first';
1852                btnObj.button.className = btnObj.className;
1853                btnObj.pos = self.getToolbarBgPosition(btnObj.button);
1854            }
1855            spacer = document.createElement('div');
1856            spacer.className = 'cheditor-tb-button-spacer';
1857            toolbarWrapper.appendChild(spacer);
1858        }
1859
1860        appendSpaceBlock(toolbarWrapper);
1861
1862        if (GB.browser.msie) {
1863            child = toolbarWrapper.getElementsByTagName('div');
1864            len = child.length;
1865            for (i = 0; i < len; i++) {
1866                self.unselectionElement(child[i]);
1867            }
1868            self.unselectionElement(toolbarWrapper);
1869        } else {
1870            self.unselectionElement(toolbarWrapper);
1871        }
1872    },
1873
1874    unselectionElement : function (elem) {
1875        if (!elem || elem.nodeType !== GB.node.element) {
1876            return;
1877        }
1878        if (GB.browser.msie) {
1879            elem.setAttribute('unselectable', 'on');
1880            elem.setAttribute('contentEditable', 'false');
1881        } else {
1882            elem.onselectstart = new Function('return false');
1883        }
1884    },
1885
1886    createEditorElement : function (container, toolbar) {
1887        var child = container.firstChild,
1888            self = this,
1889            i, id, tab, tabId, editArea, done = false, frameEl = false, tryScroll, textContent, node,
1890
1891            onClickEventHandler = function () {
1892                self.switchEditorMode(this.getAttribute('mode'));
1893            },
1894            onMouseDownEventHandler = function (evt) {
1895                self.resizeStart(evt);
1896            },
1897            modeOnMouseDownEventHandler = function (evt) {
1898                self.backupRange();
1899                self.stopEvent(evt);
1900            },
1901
1902            pNode = self.cheditor.textarea.parentNode,
1903            nNode = self.cheditor.textarea.nextSibling;
1904
1905        if (!child) {
1906            return;
1907        }
1908
1909        do {
1910            id = child.getAttribute('id');
1911            switch (id) {
1912                case 'toolbar' :
1913                    self.showToolbar(toolbar, child);
1914                    self.cheditor.toolbarWrapper = child;
1915                    break;
1916                case 'viewMode' :
1917                    self.cheditor[id] = child;
1918                    self.cheditor.mode = 'rich';
1919
1920                    if (child.hasChildNodes()) {
1921                        tab = child.childNodes;
1922                        self.cheditor.modetab = {};
1923                        for (i = 0; i < tab.length; i++) {
1924                            tabId = tab[i].getAttribute('id');
1925                            if (!tabId) {
1926                                continue;
1927                            }
1928                            if ((tabId === 'code' && self.config.useSource === false) ||
1929                                (tabId === 'preview' && self.config.usePreview === false)) {
1930                                tab[i].style.display = 'none';
1931                                tab[i].removeAttribute('id');
1932                                continue;
1933                            }
1934
1935                            tab[i].setAttribute('mode', tabId);
1936                            tab[i].onclick = onClickEventHandler;
1937                            tab[i].onmousedown = modeOnMouseDownEventHandler;
1938                            tab[i].removeAttribute('id');
1939                            self.cheditor.modetab[tabId] = tab[i];
1940                            self.unselectionElement(tab[i]);
1941                        }
1942                    }
1943                    break;
1944                case 'editWrapper' :
1945                    node = child.firstChild;
1946                    while (node) {
1947                        if (node.nodeName.toLowerCase() === 'iframe') {
1948                            editArea = node;
1949                        } else if (node.nodeName.toLowerCase() === 'textarea') {
1950                            textContent = node;
1951                        }
1952                        node = node.nextSibling;
1953                    }
1954
1955                    editArea.style.height = self.config.editorHeight;
1956                    editArea.style.backgroundColor = this.config.editorBgColor;
1957
1958                    self.cheditor.editArea = editArea;
1959                    self.cheditor.editWrapper = child;
1960                    self.cheditor.textContent = textContent;
1961                    break;
1962                case 'modifyBlock' :
1963                    self.cheditor.editBlock = child;
1964                    break;
1965                case 'tagPath' :
1966                    if (self.config.showTagPath) {
1967                        self.cheditor.tagPath = child.firstChild;
1968                        child.style.display = 'block';
1969                    }
1970                    break;
1971                case 'resizeBar' :
1972                    self.cheditor.resizeBar = child;
1973                    child.onmousedown = onMouseDownEventHandler;
1974                    self.unselectionElement(child);
1975                    break;
1976                default : break;
1977            }
1978            child.removeAttribute('id');
1979            child = child.nextSibling;
1980        } while (child);
1981
1982        if (!nNode) {
1983            pNode.appendChild(container);
1984        } else {
1985            pNode.insertBefore(container, nNode);
1986        }
1987
1988        function ready() {
1989            if (done) {
1990                return;
1991            }
1992            done = true;
1993        }
1994
1995        if (GB.browser.msie) {
1996            frameEl = window.frameElement !== null;
1997            if (document.documentElement.doScroll && !frameEl) {
1998                tryScroll = function () {
1999                    if (done) {
2000                        return;
2001                    }
2002                    try {
2003                        document.documentElement.doScroll('left');
2004                        ready();
2005                    } catch (e) {
2006                        setTimeout(tryScroll, 10);
2007                    }
2008                };
2009                tryScroll();
2010            }
2011            self.addEvent(document, 'readystatechange', function () {
2012                if (document.readyState === 'complete') {
2013                    ready();
2014                }
2015            });
2016        } else {
2017            self.addEvent(document, 'DOMContentLoaded', function () {
2018                ready();
2019            });
2020        }
2021
2022        container.style.width = self.config.editorWidth;
2023        self.cheditor.container = container;
2024    },
2025
2026    loadTemplate : function (xmlDoc) {
2027        var cdata, container, dragHandle, html, modalFrame, popupWindow, tmpDiv, tmpl, toolbar;
2028        tmpl = xmlDoc.getElementsByTagName('Template').item(0);
2029        if (!tmpl) {
2030            throw 'Template 노드를 설정할 수 없습니다.';
2031        }
2032        cdata = tmpl.getElementsByTagName('Container').item(0).getElementsByTagName('Html').item(0);
2033        if (!cdata) {
2034            throw 'XML CDATA 오류';
2035        }
2036        html = this.getCDATASection(cdata);
2037        tmpDiv = document.createElement('div');
2038        tmpDiv.innerHTML = html;
2039        container = tmpDiv.firstChild;
2040
2041        toolbar = tmpl.getElementsByTagName('Toolbar').item(0);
2042        this.createEditorElement(container, toolbar);
2043
2044        cdata = tmpl.getElementsByTagName('PopupWindow').item(0).getElementsByTagName('Html').item(0);
2045        if (!cdata) {
2046            throw 'XML CDATA 오류';
2047        }
2048        html = this.getCDATASection(cdata);
2049        tmpDiv.innerHTML = html;
2050        popupWindow = tmpDiv.firstChild;
2051        this.cheditor.popupElem = popupWindow;
2052
2053        dragHandle = popupWindow.firstChild;
2054        this.cheditor.dragHandle = dragHandle;
2055        this.cheditor.popupTitle = dragHandle.getElementsByTagName('label')[0];
2056        this.cheditor.popupFrameWrapper = dragHandle.nextSibling;
2057        container.appendChild(popupWindow);
2058
2059        modalFrame = document.createElement('div');
2060        modalFrame.className = 'cheditor-modalPopupTransparent';
2061        this.cheditor.modalBackground = modalFrame;
2062        this.cheditor.modalBackground.id = 'popupModalBackground';
2063        this.cheditor.modalBackground.className = 'cheditor-popupModalBackground';
2064        container.parentNode.insertBefore(modalFrame, container);
2065
2066        this.cheditor.htmlEditable = document.createElement('iframe');
2067        this.cheditor.htmlEditable.style.display = 'none';
2068        this.cheditor.htmlEditable.style.width = '1px';
2069        this.cheditor.htmlEditable.style.height = '1px';
2070        this.cheditor.htmlEditable.style.visibility = 'hidden';
2071        container.appendChild(this.cheditor.htmlEditable);
2072    },
2073
2074    imageEvent : function (img, action) {
2075        var self = this,
2076            onMouseUpEventHandler = function () {
2077                self.cheditor.editBlock.style.display = 'block';
2078                self.modifyImage(this);
2079            },
2080            onClickEventHandler = function () {
2081                self.cheditor.editBlock.style.display = 'block';
2082                self.modifyImage(this);
2083            };
2084
2085        if (GB.browser.msie) {
2086            if (!action) {
2087                img.onmouseup = null;
2088                return;
2089            }
2090            (function () {
2091                img.onmouseup = onMouseUpEventHandler;
2092            })();
2093        } else {
2094            if (!action) {
2095                self.removeEvent(img, 'click', onClickEventHandler);
2096                return;
2097            }
2098            this.addEvent(img, 'click', onClickEventHandler);
2099        }
2100    },
2101
2102    setImageEvent : function (action) {
2103        var images = this.doc.images, i,
2104            len = images.length;
2105
2106        for (i = 0; i < len; i++) {
2107            if (/icons\/em\//.test(images[i].src)) {
2108                continue;
2109            }
2110            this.imageEvent(images[i], action);
2111        }
2112    },
2113
2114    run : function () {
2115        var self = this,
2116            showEditor = function () {
2117                var grayImage = null;
2118
2119                if (!self.resetDoc()) {
2120                    return;
2121                }
2122                // self.editAreaFocus();  // lbjtree 처음로딩시 포커스 오는것을 방지함.
2123                self.setEditorEvent();
2124
2125                if (GB.browser.msie && GB.browser.version > 8 || GB.browser.a) {
2126                    grayImage = new Image();
2127                    grayImage.onload = function () {
2128                        self.cheditor.toolbarGrayscale = self.makeToolbarGrayscale(this);
2129                        self.toolbarUpdate();
2130                    };
2131                    grayImage.src = self.toolbar.icon;
2132                    grayImage.style.width = '750px'; grayImage.style.height = '16px';
2133                } else {
2134                    self.cheditor.toolbarGrayscale = null;
2135                    self.toolbarUpdate();
2136                }
2137                self.setImageEvent(true);
2138                self.removeEvent(document, self.cheditor.id, showEditor);
2139            };
2140
2141        try {
2142            this.setFolderPath();
2143            this.checkInputForm();
2144        }
2145        catch (e) {
2146            alert(e.toString());
2147            return;
2148        }
2149
2150        self.setDefaultCss({css: 'ui.css', doc: window.document});
2151
2152        if (this.W3CRange) {
2153            this.addEvent(document, this.cheditor.id, showEditor);
2154        } else {
2155            document.documentElement.loadEvent = 0;
2156            document.documentElement.attachEvent('onpropertychange', function (evt) {
2157                if (evt.propertyName === 'loadEvent') {
2158                    showEditor();
2159                }
2160            });
2161        }
2162
2163        this.initTemplate();
2164    },
2165
2166    fullScreenMode : function () {
2167        var self = this,
2168            container = self.cheditor.container,
2169            windowSize, height,
2170            child = container.firstChild,
2171            except = 0,
2172            editorHeight = parseInt(self.config.editorHeight, 10),
2173
2174            containerReSize = function () {
2175                windowSize = self.getWindowSize();
2176                container.style.width = windowSize.width + 'px';
2177                if (self.cheditor.mode === 'code') {
2178                    self.resizeTextContent();
2179                    height = (windowSize.height - except - 6 - parseInt(self.cheditor.textContent.getAttribute('xbar-height'), 10));
2180                    self.cheditor.textContent.style.height = height + 'px';
2181                }
2182                self.cheditor.editArea.style.height = (windowSize.height - except - 6) + 'px';
2183            },
2184            onMouseDownEventHandler = function (evt) {
2185                self.resizeStart(evt);
2186            };
2187
2188        self.editAreaFocus();
2189        self.boxHideAll();
2190        self.cheditor.editArea.style.visibility = 'hidden';
2191
2192        if (!self.setFullScreenMode) {
2193            container.className = 'cheditor-container-fullscreen';
2194
2195            if (GB.browser.msie && GB.browser.version < 7) {
2196                self.cheditor.fullScreenFlag = document.createElement('span');
2197                self.cheditor.fullScreenFlag.style.display = 'none';
2198                container.parentNode.insertBefore(self.cheditor.fullScreenFlag, container);
2199                document.body.insertBefore(container, document.body.firstChild);
2200            }
2201
2202            while (child) {
2203                if (child.className !== 'cheditor-editarea-wrapper' &&
2204                    child.className !== 'cheditor-popup-window' &&
2205                    child.className !== '') {
2206                    except += child.offsetHeight;
2207                }
2208                child = child.nextSibling;
2209            }
2210
2211            (function () {
2212                window.onresize = containerReSize;
2213            })();
2214
2215            containerReSize();
2216            self.cheditor.resizeBar.onmousedown = null;
2217            self.cheditor.resizeBar.className = 'cheditor-resizebar-off';
2218        } else {
2219            window.onresize = null;
2220            container.removeAttribute('style');
2221            container.className = 'cheditor-container';
2222            container.style.width = self.config.editorWidth;
2223
2224            if (self.cheditor.mode === 'code') {
2225                height = editorHeight - parseInt(self.cheditor.textContent.getAttribute('xbar-height'), 10);
2226                self.cheditor.textContent.style.height = height + 'px';
2227            } else {
2228                self.cheditor.editArea.style.height = editorHeight + 'px';
2229            }
2230
2231            (function () {
2232                self.cheditor.resizeBar.onmousedown = onMouseDownEventHandler;
2233            })();
2234            self.cheditor.resizeBar.className = 'cheditor-resizebar';
2235
2236            if (GB.browser.msie && GB.browser.version < 7) {
2237                self.cheditor.fullScreenFlag.parentNode.replaceChild(container, self.cheditor.fullScreenFlag);
2238            }
2239        }
2240
2241        self.cheditor.editArea.style.visibility = 'visible';
2242        self.setFullScreenMode = !(self.setFullScreenMode);
2243        self.editAreaFocus();
2244    },
2245
2246    showPulldown : function (cmd, btn) {
2247        switch (cmd) {
2248            case 'FontName' :
2249                this.showFontTypeMenu(btn);
2250                break;
2251            case 'FontSize' :
2252                this.showFontSizeMenu(btn);
2253                break;
2254            case 'FormatBlock' :
2255                this.showFormatBlockMenu(btn);
2256                break;
2257            case 'ForeColor' :
2258            case 'BackColor' :
2259                this.showColorMenu(btn);
2260                break;
2261            case 'TextBlock' :
2262                this.showTextBlockMenu(btn);
2263                break;
2264            case 'LineHeight' :
2265                this.showLineHeightMenu(btn);
2266                break;
2267            case 'OrderedList' :
2268            case 'UnOrderedList' :
2269                this.showOrderedListMenu(btn);
2270        }
2271    },
2272
2273    setPulldownClassName : function (labels, pNode) {
2274        var i = 0, label;
2275        for (; i < labels.length; i++) {
2276            label = labels[i];
2277            if (label.getAttribute('name') === pNode.firstChild.firstChild.firstChild.nodeValue) {
2278                label.parentNode.style.backgroundImage = 'url(' + this.config.editorPath + 'icons/checked.png)';
2279                label.parentNode.style.backgroundPosition = '0 center';
2280                label.parentNode.style.backgroundRepeat = 'no-repeat';
2281            } else {
2282                label.parentNode.style.backgroundImage = '';
2283            }
2284            label.parentNode.className = 'cheditor-pulldown-mouseout';
2285        }
2286    },
2287
2288    showOrderedListMenu : function (pNode) {
2289        var self = this,
2290            menu = pNode.getAttribute('name'),
2291            elem = self.pulldown[menu];
2292
2293        (function () {
2294            if (!elem) {
2295                var cmd = (menu === 'UnOrderedListCombo') ? 'InsertUnOrderedList' : 'InsertOrderedList',
2296                    outputHtml = document.createElement('div'),
2297                    onClickEventHandler = function () {
2298                        self.doCmdPopup(cmd, this.id, self.toolbar[menu].prev.checked);
2299                    },
2300                    onMouseOverEventHandler = function () {
2301                        self.pulldownMouseOver(this);
2302                    },
2303                    onMouseOutEventHandler = function () {
2304                        self.pulldownMouseOut(this);
2305                    },
2306                    list = (cmd === 'InsertUnOrderedList') ? GB.listStyle.unOrdered : GB.listStyle.ordered,
2307                    i, div, label, li, ol;
2308
2309                for (i in list) {
2310                    if (list.hasOwnProperty(i)) {
2311                        div = document.createElement('div');
2312                        label = document.createElement('label');
2313                        div.id = i;
2314
2315                        (function () {
2316                            div.onclick = onClickEventHandler;
2317                            div.onmouseover = onMouseOverEventHandler;
2318                            div.onmouseout = onMouseOutEventHandler;
2319                        })();
2320
2321                        self.pulldownMouseOut(div);
2322
2323                        label.style.fontFamily = 'verdana';
2324                        label.style.textAlign = 'center';
2325                        label.style.width = '15px';
2326                        label.setAttribute('name', i);
2327
2328                        li = document.createElement('li');
2329                        li.appendChild(document.createTextNode(list[i]));
2330
2331                        ol = document.createElement('ul');
2332                        ol.style.width = '90px';
2333                        ol.style.padding = '0 15px';
2334                        ol.style.margin = '0px';
2335                        ol.style.listStyleType = i;
2336                        ol.style.cursor = 'default';
2337                        ol.style.textAlign = 'left';
2338                        ol.appendChild(li);
2339                        label.appendChild(ol);
2340                        div.appendChild(label);
2341                        outputHtml.appendChild(div);
2342                    }
2343                }
2344                self.createWindow(110, outputHtml);
2345                self.createPulldownFrame(outputHtml, menu);
2346            }
2347        })();
2348
2349        self.windowPos(pNode, menu);
2350        self.displayWindow(pNode, menu);
2351    },
2352
2353    showColorMenu : function (pNode) {
2354        var menu = pNode.getAttribute('name'),
2355            elem = this.pulldown[menu],
2356            selectedColor = this.colorConvert(pNode.lastChild.style.backgroundColor, 'hex'),
2357            i, len, nodes, node, outputHtml;
2358
2359        if (!elem) {
2360            outputHtml = this.setColorTable(menu);
2361            this.createWindow(220, outputHtml);
2362            this.createPulldownFrame(outputHtml, menu);
2363            elem = this.pulldown[menu];
2364            elem.firstChild.className = 'cheditor-pulldown-color-container';
2365        }
2366
2367        this.toolbar[menu].colorNode.selectedValue.style.backgroundColor = selectedColor;
2368        this.toolbar[menu].colorNode.colorPicker.hidePicker();
2369        this.toolbar[menu].colorNode.colorPicker.fromString(selectedColor);
2370        this.toolbar[menu].colorNode.showPicker = false;
2371
2372        nodes = elem.getElementsByTagName('span');
2373        len = nodes.length;
2374
2375        for (i = 0; i < len; i++) {
2376            node = nodes[i];
2377            node.style.backgroundImage = '';
2378            if (node.id && node.id.toLowerCase() === selectedColor.toLowerCase()) {
2379                node.style.backgroundImage = 'url("' + this.config.iconPath + '/color_picker_tick.png")';
2380                node.style.backgroundRepeat = 'no-repeat';
2381                node.style.backgroundPosition = 'center center';
2382
2383            }
2384        }
2385        this.toolbar[menu].colorNode.selectedValue.style.backgroundImage = 'url("' +
2386            this.config.iconPath + '/color_picker_tick.png")';
2387        this.toolbar[menu].colorNode.selectedValue.style.backgroundRepeat = 'no-repeat';
2388        this.toolbar[menu].colorNode.selectedValue.style.backgroundPosition = 'center center';
2389        this.windowPos(pNode, menu);
2390        this.displayWindow(pNode, menu);
2391    },
2392
2393    showFontTypeMenu : function (pNode) {
2394        var self = this,
2395            menu = pNode.getAttribute('name'),
2396            elem = self.pulldown[menu];
2397
2398        (function () {
2399            if (!elem) {
2400                var fonts = null, type, i, div, label,
2401                    outputHtml = self.doc.createElement('div'),
2402                    onClickEventHandler = function () {
2403                        self.doCmdPopup(menu, this.id);
2404                    },
2405                    onMouseOverEventHandler = function () {
2406                        self.pulldownMouseOver(this);
2407                    },
2408                    onMouseOutEventHandler = function () {
2409                        self.pulldownMouseOut(this);
2410                    };
2411
2412                for (type in GB.fontName) {
2413                    if (GB.fontName.hasOwnProperty(type)) {
2414                        fonts = GB.fontName[type];
2415                        for (i = 0; i < fonts.length; i++) {
2416                            div = self.doc.createElement('div');
2417                            label = self.doc.createElement('label');
2418                            div.id = fonts[i];
2419                            (function () {
2420                                div.onclick = onClickEventHandler;
2421                                div.onmouseover = onMouseOverEventHandler;
2422                                div.onmouseout = onMouseOutEventHandler;
2423                            })();
2424                            label.style.fontFamily = fonts[i];//(type !== 'kr') ? fonts[i] : this.config.editorFontName;
2425                            label.appendChild(self.doc.createTextNode(fonts[i]));
2426                            label.setAttribute('name', fonts[i]);
2427                            div.appendChild(label);
2428                            outputHtml.appendChild(div);
2429                        }
2430                    }
2431                }
2432                self.createWindow(155, outputHtml);
2433                self.createPulldownFrame(outputHtml, menu);
2434                elem = self.pulldown[menu];
2435            }
2436        })();
2437
2438        self.setPulldownClassName(elem.firstChild.getElementsByTagName('LABEL'), pNode);
2439        self.windowPos(pNode, menu);
2440        self.displayWindow(pNode, menu);
2441    },
2442
2443    showFormatBlockMenu : function (pNode) {
2444        var self = this,
2445            menu = pNode.getAttribute('name'),
2446            elem = self.pulldown[menu];
2447
2448        (function () {
2449            if (!elem) {
2450                var para, label, fontSize, div,
2451                    outputHtml = document.createElement('div'),
2452                    onClickEventHandler = function () {
2453                        self.doCmdPopup('FormatBlock', '<' + this.id + '>');
2454                    },
2455                    onMouseOverEventHandler = function () {
2456                        self.pulldownMouseOver(this);
2457                    },
2458                    onMouseOutEventHandler = function () {
2459                        self.pulldownMouseOut(this);
2460                    };
2461
2462                for (para in GB.formatBlock) {
2463                    if (GB.formatBlock.hasOwnProperty(para)) {
2464                        div = document.createElement('div');
2465                        div.id = para;
2466                        (function () {
2467                            div.onclick = onClickEventHandler;
2468                            div.onmouseover = onMouseOverEventHandler;
2469                            div.onmouseout = onMouseOutEventHandler;
2470                        })();
2471                        label = document.createElement('label');
2472                        if (para.match(/H[123456]/)) {
2473                            fontSize = {'H1': '2em','H2': '1.5em','H3': '1.17em','H4': '1em','H5': '0.83em','H6': '0.75em'};
2474                            label.style.fontWeight = 'bold';
2475                            label.style.fontSize = fontSize[para];
2476                            label.style.lineHeight = 1.4;
2477                        } else if (para === 'ADDRESS') {
2478                            label.style.fontStyle = 'italic';
2479                        }
2480
2481                        label.appendChild(document.createTextNode(GB.formatBlock[para]));
2482                        div.appendChild(label);
2483                        label.setAttribute('name', GB.formatBlock[para]);
2484                        outputHtml.appendChild(div);
2485
2486                    }
2487                }
2488                self.createWindow(150, outputHtml);
2489                self.createPulldownFrame(outputHtml, menu);
2490                elem = self.pulldown[menu];
2491            }
2492        })();
2493
2494        self.setPulldownClassName(elem.firstChild.getElementsByTagName('label'), pNode);
2495        self.windowPos(pNode, menu);
2496        self.displayWindow(pNode, menu);
2497    },
2498
2499    showFontSizeMenu : function (pNode) {
2500        var self = this,
2501            menu = pNode.getAttribute('name'),
2502            elem = self.pulldown[menu];
2503
2504        (function () {
2505            if (!elem) {
2506                var size, div, label, text, i,
2507                    value = GB.fontSize[self.config.fontSizeValue],
2508                    len = value.length,
2509                    outputHtml = document.createElement('div'),
2510                    onClickEventHandler = function (e) {
2511                        self.stopEvent(e);
2512                        self.doCmdPopup(menu, this.id);
2513                    },
2514                    onMouseOverEventHandler = function () {
2515                        self.pulldownMouseOver(this);
2516                    },
2517                    onMouseOutEventHandler = function () {
2518                        self.pulldownMouseOut(this);
2519                    };
2520
2521                for (i = 0; i < len; i++) {
2522                    size = value[i];
2523                    div = document.createElement('div');
2524                    label = document.createElement('label');
2525                    text = size > 48 ? '가' : (size > 28 ? '가나다' : '가나다라');
2526                    size = size + self.config.fontSizeValue;
2527                    div.id = size;
2528                    (function () {
2529                        div.onclick = onClickEventHandler;
2530                        div.onmouseover = onMouseOverEventHandler;
2531                        div.onmouseout = onMouseOutEventHandler;
2532                    })();
2533                    div.style.fontSize = size;
2534                    label.style.fontFamily = self.config.editorFontName;
2535                    label.setAttribute('name', size);
2536                    label.appendChild(document.createTextNode(text + '(' + size + ')'));
2537                    div.appendChild(label);
2538                    outputHtml.appendChild(div);
2539                }
2540                self.createWindow(350, outputHtml);
2541                outputHtml.style.height = '300px';
2542                outputHtml.style.overflow = 'auto';
2543                self.createPulldownFrame(outputHtml, menu);
2544                elem = self.pulldown[menu];
2545            }
2546        })();
2547
2548        self.setPulldownClassName(elem.firstChild.getElementsByTagName('LABEL'), pNode);
2549        self.windowPos(pNode, menu);
2550        self.displayWindow(pNode, menu);
2551    },
2552
2553    showLineHeightMenu : function (pNode) {
2554        var self = this,
2555            menu = pNode.getAttribute('name'),
2556            elem = self.pulldown[menu];
2557
2558        (function () {
2559            if (!elem) {
2560                var i, div, label, text,
2561                    outputHtml = document.createElement('div'),
2562                    onClickEventHandler = function () {
2563                        self.doCmdPopup('LineHeight', this.id);
2564                    },
2565                    onMouseOverEventHandler = function () {
2566                        self.pulldownMouseOver(this);
2567                    },
2568                    onMouseOutEventHandler = function () {
2569                        self.pulldownMouseOut(this);
2570                    };
2571
2572                for (i in GB.lineHeight) {
2573                    if (!(GB.lineHeight.hasOwnProperty(i))) {
2574                        continue;
2575                    }
2576                    if (!GB.lineHeight[i]) {
2577                        break;
2578                    }
2579                    div = document.createElement('div');
2580                    label = document.createElement('label');
2581                    text = i;
2582
2583                    div.id = GB.lineHeight[i];
2584                    (function () {
2585                        div.onclick = onClickEventHandler;
2586                        div.onmouseover = onMouseOverEventHandler;
2587                        div.onmouseout = onMouseOutEventHandler;
2588                    })();
2589
2590                    label.style.fontFamily = self.config.editorFontName;
2591                    label.setAttribute('name', GB.lineHeight[i]);
2592                    label.appendChild(document.createTextNode(text));
2593                    div.appendChild(label);
2594                    outputHtml.appendChild(div);
2595                }
2596                self.createWindow(100, outputHtml);
2597                self.createPulldownFrame(outputHtml, menu);
2598                elem = self.pulldown[menu];
2599            }
2600        })();
2601
2602        self.setPulldownClassName(elem.firstChild.getElementsByTagName('LABEL'), pNode);
2603        self.windowPos(pNode, menu);
2604        self.displayWindow(pNode, menu);
2605    },
2606
2607    showTextBlockMenu : function (pNode) {
2608        var self = this,
2609            menu = pNode.getAttribute('name'),
2610            elem = self.pulldown[menu];
2611
2612        (function () {
2613            if (!elem) {
2614                var i, wrapper, div, label,
2615                    outputHtml = document.createElement('div'),
2616                    onClickEventHandler = function () {
2617                        self.boxStyle(this);
2618                    },
2619                    onMouseOverEventHandler = function () {
2620                        this.className = 'cheditor-pulldown-textblock-over';
2621                    },
2622                    onMouseOutEventHandler = function () {
2623                        this.className = 'cheditor-pulldown-textblock-out';
2624                    },
2625                    quote = GB.textBlock;
2626
2627                for (i = 0; i < quote.length; i++) {
2628                    wrapper = document.createElement('div');
2629                    div = document.createElement('div');
2630                    (function () {
2631                        div.onclick = onClickEventHandler;
2632                        wrapper.onmouseover = onMouseOverEventHandler;
2633                        wrapper.onmouseout = onMouseOutEventHandler;
2634                    })();
2635                    wrapper.className = 'cheditor-pulldown-textblock-out';
2636                    div.id = i;
2637                    div.style.border = quote[i][0];
2638                    div.style.backgroundColor = quote[i][1];
2639                    div.style.fontFamily = self.config.editorFontName;
2640
2641                    label = document.createElement('label');
2642                    label.appendChild(document.createTextNode('가나다라 ABC'));
2643                    div.appendChild(label);
2644                    wrapper.appendChild(div);
2645                    outputHtml.appendChild(wrapper);
2646                }
2647                self.createWindow(160, outputHtml);
2648                self.createPulldownFrame(outputHtml, menu);
2649                elem = self.pulldown[menu];
2650                elem.firstChild.className = 'cheditor-pulldown-textblock-container';
2651            }
2652        })();
2653
2654        self.windowPos(pNode, menu);
2655        self.displayWindow(pNode, menu);
2656    },
2657
2658    createPulldownFrame : function (contents, id) {
2659        var div = document.createElement('div');
2660        div.className = 'cheditor-pulldown-frame';
2661        div.appendChild(contents);
2662        this.pulldown[id] = div;
2663        this.cheditor.container.firstChild.appendChild(div);
2664    },
2665
2666    setDefaultCss : function (ar) {
2667        var cssFile, head, found = false, children, i, href, css;
2668
2669        ar = ar || {css: 'editarea.css', doc: this.doc};
2670        cssFile = this.config.cssPath + ar.css;
2671        head = ar.doc.getElementsByTagName('head')[0];
2672
2673        if (this.undefined(head)) {
2674            return;
2675        }
2676
2677        if (head.hasChildNodes()) {
2678            children = head.childNodes;
2679            for (i = 0; i < children.length; i++) {
2680                if (children[i].nodeName.toLowerCase() === 'link') {
2681                    href = children[i].getAttribute('href');
2682                    if (href && href === cssFile) {
2683                        found = true;
2684                        break;
2685                    }
2686                }
2687            }
2688        }
2689
2690        if (!found) {
2691            css = head.appendChild(ar.doc.createElement('link'));
2692            css.setAttribute('type', 'text/css');
2693            css.setAttribute('rel', 'stylesheet');
2694            css.setAttribute('media', 'all');
2695            css.setAttribute('href', this.config.cssPath + ar.css);
2696        }
2697    },
2698
2699    setEditorEvent : function () {
2700        var self = this,
2701            onKeyDownEventHandler = function (evt) {
2702                if (self.cheditor.mode === 'preview') {
2703                    self.stopEvent(evt);
2704                    return;
2705                }
2706                self.doOnKeyDown(evt);
2707            },
2708            onKeyPressEventHandler = function (evt) {
2709                if (self.cheditor.mode === 'preview') {
2710                    self.stopEvent(evt);
2711                    return;
2712                }
2713                self.doOnKeyPress(evt);
2714            },
2715            onKeyUpEventHandler = function (evt) {
2716                if (self.cheditor.mode === 'preview') {
2717                    self.stopEvent(evt);
2718                    return;
2719                }
2720                self.doOnKeyUp(evt);
2721            },
2722            onMouseUpEventHandler = function (evt) {
2723                if (self.cheditor.mode === 'rich') {
2724                    if (evt.clientX <= self.doc.body.offsetWidth) {
2725                        self.doEditorEvent(evt);
2726                    } else {
2727                        self.restoreRange();
2728                    }
2729                    return;
2730                }
2731                if (self.cheditor.mode === 'preview') {
2732                    self.stopEvent(evt);
2733                }
2734            },
2735            onMouseDownEventHandler = function (evt) {
2736                if (self.cheditor.mode === 'rich') {
2737                    if (evt.clientX <= self.doc.body.offsetWidth) {
2738                        // self.clearSelection();
2739                    } else {
2740                        self.backupRange();
2741                    }
2742                    self.boxHideAll();
2743                    return;
2744                }
2745                if (self.cheditor.mode === 'preview') {
2746                    self.stopEvent(evt);
2747                }
2748            };
2749
2750        (function () {
2751            self.addEvent(self.doc, 'keydown', onKeyDownEventHandler);
2752            self.addEvent(self.doc, 'keypress', onKeyPressEventHandler);
2753            self.addEvent(self.doc, 'keyup', onKeyUpEventHandler);
2754            self.addEvent(self.doc, 'mouseup', onMouseUpEventHandler);
2755            self.addEvent(self.doc, 'mousedown', onMouseDownEventHandler);
2756        })();
2757    },
2758
2759    addEvent : function (evTarget, evType, evHandler) {
2760        if (evTarget.addEventListener) {
2761            evTarget.addEventListener(evType, evHandler, false);
2762        } else {
2763            evTarget.attachEvent('on' + evType, evHandler);
2764        }
2765    },
2766
2767    removeEvent : function (elem, ev, func) {
2768        if (elem.removeEventListener) {
2769            elem.removeEventListener(ev, func, false);
2770        } else {
2771            elem.detachEvent('on' + ev, func);
2772        }
2773    },
2774
2775    stopEvent : function (ev) {
2776        if (ev && ev.preventDefault) {
2777            ev.preventDefault();
2778            ev.stopPropagation();
2779        } else {
2780            ev = ev || window.event;
2781            ev.cancelBubble = true;
2782            ev.returnValue = false;
2783        }
2784    },
2785
2786    toolbarButtonOut : function (elemButton, nTop) {
2787        elemButton.style.top = -nTop + 'px';
2788    },
2789
2790    toolbarButtonOver : function (elemButton) {
2791        var nTop = elemButton.style.top.substring(0, elemButton.style.top.length - 2);
2792        elemButton.style.top = nTop - 22 + 'px';
2793    },
2794
2795    getElement : function (elem, tag) {
2796        if (!elem || !tag) {
2797            return null;
2798        }
2799        while (elem && elem.nodeName.toLowerCase() !== tag.toLowerCase()) {
2800            if (elem.nodeName.toLowerCase() === 'body') {
2801                break;
2802            }
2803            elem = elem.parentNode;
2804        }
2805        return elem;
2806    },
2807
2808    hyperLink : function (href, target, title) {
2809        var self = this,
2810            links = null, i,
2811            createLinks = function () {
2812                var range = self.restoreRange(),
2813                    selectedLinks = [],
2814                    linkRange = self.createRange(), selection = null, container = null, k;
2815
2816                self.backupRange(range);
2817
2818                if (self.W3CRange) {
2819                    self.doc.execCommand("CreateLink", false, href);
2820                    selection = self.getSelection();
2821
2822                    for (i = 0; i < selection.rangeCount; ++i) {
2823                        range = selection.getRangeAt(i);
2824                        container = range.commonAncestorContainer;
2825
2826                        if (self.getSelectionType(range) === GB.selection.text) {
2827                            container = container.parentNode;
2828                        }
2829
2830                        if (container.nodeName.toLowerCase() === 'a') {
2831                            selectedLinks.push(container);
2832                        } else {
2833                            links = container.getElementsByTagName('a');
2834                            for (k = 0; k < links.length; ++k) {
2835                                linkRange.selectNodeContents(links[k]);
2836                                if (linkRange.compareBoundaryPoints(range.END_TO_START, range) < 1 &&
2837                                    linkRange.compareBoundaryPoints(range.START_TO_END, range) > -1)
2838                                {
2839                                    selectedLinks.push(links[k]);
2840                                }
2841                            }
2842                        }
2843                    }
2844                    linkRange.detach();
2845                } else {
2846                    range = self.doc.selection.createRange();
2847                    range.execCommand("UnLink", false);
2848                    range.execCommand("CreateLink", false, href);
2849
2850                    switch (self.getSelectionType(range)) {
2851                        case GB.selection.text :
2852                            container = range.parentElement();
2853                            break;
2854                        case GB.selection.element :
2855                            container = range.item(0).parentNode;
2856                            break;
2857                        default : return null;
2858                    }
2859
2860                    if (container.nodeName.toLowerCase() === 'a') {
2861                        selectedLinks.push(container);
2862                    } else {
2863                        links = container.getElementsByTagName('a');
2864                        for (i = 0; i < links.length; ++i) {
2865                            linkRange.moveToElementText(links[i]);
2866                            if (linkRange.compareEndPoints("StartToEnd", range) > -1 &&
2867                                linkRange.compareEndPoints("EndToStart", range) < 1)
2868                            {
2869                                selectedLinks.push(links[i]);
2870                            }
2871                        }
2872                    }
2873                }
2874                return selectedLinks;
2875            };
2876
2877        this.editArea.focus();
2878        links = createLinks();
2879        if (links) {
2880            for (i = 0; i < links.length; ++i) {
2881                if (target) {
2882                    links[i].setAttribute("target", target);
2883                }
2884                if (title) {
2885                    links[i].setAttribute("title", title);
2886                }
2887            }
2888        }
2889    },
2890
2891    getOffsetBox : function (el) {
2892        var box = el.getBoundingClientRect(),
2893            doc = this.doc.documentElement,
2894            body = this.doc.body,
2895            scrollTop = doc.scrollTop || body.scrollTop,
2896            scrollLeft = doc.scrollLeft || body.scrollLeft,
2897            clientTop = doc.clientTop || body.clientTop || 0,
2898            clientLeft = doc.clientLeft || body.clientLeft || 0,
2899            top = box.top + scrollTop - clientTop,
2900            left = box.left + scrollLeft - clientLeft;
2901
2902        return { top: Math.round(top), left: Math.round(left) };
2903    },
2904
2905    makeSpacerElement : function () {
2906        var elem,
2907            para = this.doc.createElement('p');
2908
2909        if (GB.browser.msie && GB.browser.version < 11 && GB.browser.version > 8) {
2910            elem = this.doc.createComment(this.cheditor.bogusSpacerName);
2911        } else if (GB.browser.msie_c) {
2912            elem = this.createNbspTextNode();
2913        } else {
2914            elem = this.doc.createElement('br');
2915            elem.className = this.cheditor.bogusSpacerName;
2916        }
2917
2918        para.appendChild(elem);
2919        return para;
2920    },
2921
2922    boxStyle : function (el) {
2923        var range, elem, ctx, textRange, frag, pNode,
2924            blockQuote = this.doc.createElement('blockquote'),
2925            para = null;
2926
2927        this.editAreaFocus();
2928        range = this.range || this.getRange()
2929
2930        blockQuote.style.border = GB.textBlock[el.id][0];
2931        blockQuote.style.backgroundColor = GB.textBlock[el.id][1];
2932        blockQuote.style.padding = '5px 10px';
2933
2934        if (!this.W3CRange) {
2935            ctx = range.htmlText;
2936            blockQuote.innerHTML = ctx || '&nbsp;';
2937            range.select();
2938            this.insertHTML(blockQuote);
2939            textRange = this.getRange();
2940            elem = range.parentElement();
2941            textRange.moveToElementText(elem);
2942            textRange.collapse(false);
2943            textRange.select();
2944        } else {
2945            try {
2946                frag = range.extractContents();
2947                if (!frag.firstChild) {
2948                    para = this.makeSpacerElement();
2949                    blockQuote.appendChild(para);
2950                } else {
2951                    blockQuote.appendChild(frag);
2952                }
2953
2954                range.insertNode(blockQuote);
2955                pNode = blockQuote.parentNode;
2956
2957                while (pNode && pNode.nodeName.toLowerCase() !== 'body') {
2958                    if (pNode.nodeName.toLowerCase() === 'p' || pNode.nodeName.toLowerCase() === 'div') {
2959                        pNode.parentNode.insertBefore(blockQuote, pNode.nextSibling);
2960                        break;
2961                    }
2962                    pNode = pNode.parentNode;
2963                }
2964                this.placeCaretAt(para || blockQuote, false);
2965            } catch (ignore) {
2966                // --
2967            }
2968        }
2969        this.boxHideAll();
2970    },
2971
2972    insertFlash : function (elem) {
2973        var embed = null, pos, str, obj, child, movieHeight, params = [], movieWidth, i,
2974            div = this.doc.createElement('div');
2975
2976        this.editAreaFocus();
2977        this.restoreRange();
2978
2979        if (typeof elem === 'string') {
2980            elem = this.trimSpace(elem);
2981            pos = elem.toLowerCase().indexOf('embed');
2982
2983            if (pos !== -1) {
2984                str = elem.substr(pos);
2985                pos = str.indexOf('>');
2986                div.innerHTML = '<' + str.substr(0, pos) + '>';
2987                embed = div.firstChild;
2988            } else {
2989                div.innerHTML = elem;
2990                obj = div.getElementsByTagName('object')[0];
2991
2992                if (obj && obj.hasChildNodes()) {
2993                    child = obj.firstChild;
2994                    movieWidth  = (isNaN(obj.width) !== true) ? obj.width : 320;
2995                    movieHeight = (isNaN(obj.height) !== true) ? obj.height : 240;
2996                    do {
2997                        if ((child.nodeName.toLowerCase() === 'param') &&
2998                            (!this.undefined(child.name) && !this.undefined(child.value))) {
2999                            params.push({key: (child.name === 'movie') ? 'src' : child.name, val: child.value});
3000                        }
3001                        child = child.nextSibling;
3002                    } while (child);
3003
3004                    if (params.length > 0) {
3005                        embed = this.doc.createElement('embed');
3006                        embed.setAttribute('width', movieWidth);
3007                        embed.setAttribute('height', movieHeight);
3008                        for (i = 0; i < params.length; i++) {
3009                            embed.setAttribute(params[i].key, params[i].val);
3010                        }
3011                        embed.setAttribute('type', 'application/x-shockwave-flash');
3012                    }
3013                }
3014            }
3015
3016            if (embed) {
3017                if (this.W3CRange) {
3018                    this.insertNodeAtSelection(embed);
3019                } else {
3020                    this.doCmdPaste(embed.outerHTML);
3021                }
3022            }
3023        }
3024    },
3025
3026    insertHtmlPopup : function (elem) {
3027        this.editAreaFocus();
3028        this.restoreRange();
3029
3030        if (!this.W3CRange) {
3031            this.doCmdPaste((this.toType(elem) === 'string') ? elem : elem.outerHTML);
3032        } else {
3033            this.insertNodeAtSelection(elem);
3034        }
3035        this.clearStoredSelections();
3036    },
3037
3038    insertHTML : function (html) {
3039        if (!this.W3CRange) {
3040            this.getRange().pasteHTML((this.toType(html) === 'string') ? html : html.outerHTML);
3041        } else {
3042            this.insertNodeAtSelection(html);
3043        }
3044    },
3045
3046    placeCaretAt : function (elem, az) {
3047        var range = this.createRange(),
3048            selection = this.getSelection();
3049
3050        if (this.undefined(az)) {
3051            az = false;
3052        }
3053
3054        if (this.W3CRange) {
3055            selection.removeAllRanges();
3056            try {
3057                if (elem.lastChild && elem.lastChild.nodeName.toLowerCase() === 'br') {
3058                    az = true;
3059                }
3060                range.selectNodeContents(elem);
3061            } catch (e) {
3062                range.selectNode(elem);
3063            }
3064
3065            range.collapse(az);
3066
3067            try {
3068                selection.addRange(range);
3069            } catch (e) {
3070                this.placeCaretAt(this.doc.body, az);
3071            }
3072        } else if (elem.nodeType === GB.node.element) {
3073            range.moveToElementText(elem);
3074            range.collapse(az);
3075            range.select();
3076        }
3077    },
3078
3079    selectNodeContents : function (node, pos) {
3080        var collapsed = !this.undefined(pos),
3081            selection = this.getSelection(),
3082            range = this.getRange();
3083
3084        if (node.nodeType === GB.node.element) {
3085            range.selectNode(node);
3086            if (collapsed) {
3087                range.collapse(pos);
3088            }
3089        }
3090        selection.removeAllRanges();
3091        selection.addRange(range);
3092        return range;
3093    },
3094
3095    insertNodeAtSelection : function (insertNode) {
3096        var range = this.getRange(),
3097            selection = this.getSelection(),
3098            frag = this.doc.createDocumentFragment(),
3099            lastNode = null,
3100            elem, commonAncestorContainer, startOffset, pNode, tmpWrapper;
3101
3102        if (!range.collapsed) {
3103            range.deleteContents();
3104            range = this.getRange();
3105        }
3106
3107        commonAncestorContainer = range.commonAncestorContainer;
3108        startOffset = range.startOffset;
3109        pNode = commonAncestorContainer;
3110
3111        if (pNode.nodeType === GB.node.text) {
3112            pNode = pNode.parentNode;
3113        }
3114
3115        this.removeBogusSpacer(pNode);
3116
3117        if (typeof insertNode === 'string') {
3118            tmpWrapper = this.doc.createElement('div');
3119            tmpWrapper.innerHTML = insertNode;
3120
3121            elem = tmpWrapper.firstChild;
3122            while (elem) {
3123                lastNode = frag.appendChild(elem);
3124                elem = tmpWrapper.firstChild;
3125            }
3126        } else {
3127            lastNode = frag.appendChild(insertNode);
3128        }
3129
3130        if (startOffset < 1 && commonAncestorContainer.nodeType === GB.node.text) {
3131            commonAncestorContainer.parentNode.insertBefore(frag, commonAncestorContainer);
3132        } else {
3133            range.insertNode(frag);
3134        }
3135
3136        if (lastNode) {
3137            range = range.cloneRange();
3138            range.setStartAfter(lastNode);
3139            selection.removeAllRanges();
3140            selection.addRange(range);
3141        }
3142        this.toolbarUpdate();
3143        return lastNode;
3144    },
3145
3146    findBogusSpacer : function (elem, all) {
3147        var self = this, result = [];
3148        (function findBogusSpacer(elem) {
3149            var i = 0, node;
3150            for (; i < elem.childNodes.length; i++) {
3151                node = elem.childNodes[i];
3152                if ((node.nodeType === GB.node.element && node.className === self.cheditor.bogusSpacerName) ||
3153                    (node.nodeType === GB.node.comment && node.nodeValue === self.cheditor.bogusSpacerName)) {
3154                    result.push(node);
3155                }
3156                if (node.nodeType === GB.node.text && node.nodeValue === '\u00a0' && !node.nextSibling) {
3157                    result.push(node);
3158                }
3159                if (all) {
3160                    findBogusSpacer(node);
3161                }
3162            }
3163        })(elem);
3164        return result;
3165    },
3166
3167    removeBogusSpacer : function (elem, removeEmpty, all) {
3168        var remove = this.findBogusSpacer(elem, all), i = 0;
3169        for (; i < remove.length; i++) {
3170            remove[i].parentNode.removeChild(remove[i]);
3171        }
3172        if (removeEmpty && !(elem.hasChildNodes())) {
3173            elem.parentNode.removeChild(elem);
3174        }
3175    },
3176
3177    ieGetRangeAt : function (range) {
3178        var self = this, start = {}, end = {};
3179
3180        function convert(result, bStart) {
3181            var point = range.duplicate(),
3182                span = self.doc.createElement('span'),
3183                parent = point.parentElement(),
3184                cursor = self.createRange(),
3185                compareStr = bStart ? 'StartToStart' : 'StartToEnd';
3186
3187            point.collapse(bStart);
3188            parent.appendChild(span);
3189            cursor.moveToElementText(span);
3190
3191            while (cursor.compareEndPoints(compareStr, point) > 0 && span.previousSibling) {
3192                parent.insertBefore(span, span.previousSibling);
3193                cursor.moveToElementText(span);
3194            }
3195
3196            result.container = span.nextSibling || span.previousSibling;
3197            if (result.container === null) {
3198                result.container = span.parentNode;
3199            }
3200            parent.removeChild(span);
3201        }
3202
3203        convert(start, true); convert(end, false);
3204        return { startContainer: start.container, endContainer: end.container };
3205    },
3206
3207    applyLineHeight : function (opt) {
3208        var range = this.getRange(),
3209            isBlockElement = function (elem) {
3210                return GB.lineHeightBlockTags[elem.toLowerCase()];
3211            },
3212            getNextLeaf = function (elem, endLeaf, value) {
3213                while (!elem.nextSibling) {
3214                    elem = elem.parentNode;
3215                    if (!elem) {
3216                        return elem;
3217                    }
3218                }
3219
3220                if (elem === endLeaf) {
3221                    return elem;
3222                }
3223
3224                var leaf = elem.nextSibling;
3225                if (isBlockElement(leaf.nodeName)) {
3226                    leaf.style.lineHeight = value;
3227                }
3228
3229                while (leaf.firstChild) {
3230                    leaf = leaf.firstChild;
3231                    if (leaf.nodeType !== GB.node.text && isBlockElement(leaf.nodeName)) {
3232                        leaf.style.lineHeight = value;
3233                    }
3234                }
3235                return leaf;
3236            },
3237            applyBlockElement = function (elem) {
3238                while (elem) {
3239                    if (elem.nodeName.toLowerCase() === "body") {
3240                        para = self.doc.createElement("p");
3241                        para.style.lineHeight = opt;
3242
3243                        if (elem.firstChild) {
3244                            elem.insertBefore(para, elem.firstChild);
3245                        } else {
3246                            elem.appendChild(para);
3247                            break;
3248                        }
3249
3250                        nextNode = para.nextSibling;
3251                        while (nextNode) {
3252                            if (isBlockElement(nextNode.nodeName)) {
3253                                break;
3254                            }
3255                            para.appendChild(nextNode);
3256                            nextNode = para.nextSibling;
3257                        }
3258                        break;
3259                    }
3260
3261                    if (isBlockElement(elem.nodeName)) {
3262                        elem.style.lineHeight = opt;
3263                        break;
3264                    }
3265                    elem = elem.parentNode;
3266                }
3267            },
3268            ieRange, startContainer, endContainer, para, nextNode, startLeaf, endLeaf, nextLeaf;
3269
3270        if (!this.W3CRange) {
3271            ieRange = this.ieGetRangeAt(range);
3272            startContainer = ieRange.startContainer;
3273            endContainer = ieRange.endContainer;
3274        } else {
3275            startContainer = range.startContainer;
3276            endContainer = range.endContainer;
3277        }
3278
3279        if (!this.doc.body.hasChildNodes() || !startContainer || !endContainer) {
3280            throw "Object Error";
3281        }
3282
3283        if (startContainer && startContainer.nodeName.toLowerCase() === "body") {
3284            startContainer = startContainer.firstChild;
3285        }
3286
3287        try {
3288            if (startContainer === endContainer) {
3289                applyBlockElement(startContainer);
3290            } else {
3291                startLeaf = startContainer;
3292                while (startLeaf) {
3293                    if (startLeaf.nodeName.toLowerCase() === "body" || isBlockElement(startLeaf.nodeName)) {
3294                        break;
3295                    }
3296                    startLeaf = startLeaf.parentNode;
3297                }
3298
3299                endLeaf = endContainer;
3300                while (endLeaf) {
3301                    if (endLeaf.nodeName.toLowerCase() === "body" || isBlockElement(endLeaf.nodeName)) {
3302                        break;
3303                    }
3304                    endLeaf = endLeaf.parentNode;
3305                }
3306
3307                if (startLeaf === endLeaf) {
3308                    if (isBlockElement(startLeaf.nodeName)) {
3309                        startLeaf.style.lineHeight = opt;
3310                    } else {
3311                        para = this.doc.createElement("p");
3312                        para.style.lineHeight = opt;
3313                        startLeaf.insertBefore(para, startLeaf.firstChild);
3314
3315                        nextNode = para.nextSibling;
3316                        while (nextNode) {
3317                            if (isBlockElement(nextNode.nodeName)) {
3318                                break;
3319                            }
3320                            para.appendChild(nextNode);
3321                            nextNode = para.nextSibling;
3322                        }
3323                    }
3324                } else {
3325                    applyBlockElement(startLeaf);
3326                    while (startLeaf) {
3327                        nextLeaf = getNextLeaf(startLeaf, endLeaf, opt);
3328                        if (startLeaf === endLeaf) {
3329                            break;
3330                        }
3331                        startLeaf = nextLeaf;
3332                    }
3333                }
3334            }
3335        } catch (ignore) {
3336            // --
3337        }
3338    },
3339
3340    doInsertImage : function (imgs, para, insertSpace) {
3341        var range, i, count = 0, imgAttr, img, space, lastNode = null, pNode, div, selection,
3342            len = imgs.length, self = this,
3343            fragment = this.doc.createDocumentFragment();
3344
3345        function checkPara(pNode) {
3346            var result = true, text;
3347            if (!pNode.hasChildNodes()) {
3348                return false;
3349            }
3350            self.getNodeTree(pNode, function (node) {
3351                if (!node.node || node === pNode) {
3352                    return;
3353                }
3354                if (node.type === GB.node.text) {
3355                    text = self.trimSpace(node.node.nodeValue);
3356                    if (!text || text === '\u00a0') {
3357                        result = false;
3358                    }
3359                } else if (node.type === GB.node.element
3360                    && (node.name === 'br' && node.node.className === self.cheditor.bogusSpacerName)) {
3361                    result = false;
3362                }
3363            });
3364            return result;
3365        }
3366
3367        this.editAreaFocus();
3368        range = this.restoreRange();
3369        pNode = this.getRangeElement(range);
3370        if (!pNode) {
3371            return;
3372        }
3373
3374        if (pNode.nodeName.toLowerCase() === 'body') {
3375            pNode = this.doc.createElement('p');
3376            if (this.W3CRange) {
3377                range.insertNode(pNode);
3378            } else {
3379                range.pasteHTML(pNode.outerHTML);
3380            }
3381        }
3382
3383        if (para) {
3384            do {
3385                if (GB.lineHeightBlockTags[pNode.nodeName.toLowerCase()]) {
3386                    break;
3387                }
3388                pNode = pNode.parentNode;
3389            } while (pNode && pNode.nodeName.toLowerCase() !== 'body');
3390        }
3391
3392        for (i in imgs) {
3393            if (!imgs.hasOwnProperty(i) || this.undefined(imgs[i])) {
3394                continue;
3395            }
3396            imgAttr = imgs[i];
3397            img = this.doc.createElement('img');
3398            img.setAttribute('src', imgAttr.fileUrl);
3399
3400            if (this.config.imgSetAttrWidth === 1) {
3401                img.style.width = imgAttr.width;
3402                img.style.height = imgAttr.height;
3403            } else if (this.config.imgSetAttrWidth === -1) {
3404                img.style.width = '100%';
3405                img.style.height = 'auto';
3406            }
3407
3408            if (this.config.imgSetAttrAlt) {
3409                img.setAttribute('alt', imgAttr.alt || imgAttr.origName);
3410            } else {
3411                img.removeAttribute('alt');
3412            }
3413
3414            count++;
3415            if (para) {
3416                lastNode = fragment.appendChild(this.doc.createElement('p'));
3417                if (imgAttr.align !== 'left') {
3418                    lastNode.style.textAlign = imgAttr.align;
3419                }
3420                lastNode.appendChild(img);
3421                if (insertSpace && count < len) {
3422                    space = this.makeSpacerElement();
3423                    fragment.appendChild(space);
3424                }
3425            } else {
3426                lastNode = fragment.appendChild(img);
3427                if (insertSpace && count < len) {
3428                    fragment.appendChild(this.doc.createTextNode('\u00a0'));
3429                }
3430            }
3431            this.images.push(imgAttr);
3432        }
3433
3434        if (lastNode) {
3435            if (para) {
3436                if (pNode.nodeName.toLowerCase() === 'p') {
3437                    if (!checkPara(pNode)) {
3438                        pNode.parentNode.replaceChild(fragment, pNode);
3439                    } else {
3440                        pNode.parentNode.insertBefore(fragment, pNode.nextSibling);
3441                    }
3442                } else {
3443                    if (!this.W3CRange) {
3444                        div = this.doc.createElement('div');
3445                        div.appendChild(fragment);
3446                        range.pasteHTML(div.innerHTML);
3447                    } else {
3448                        range.insertNode(fragment);
3449                    }
3450                }
3451                this.placeCaretAt(lastNode.nextSibling ? lastNode.nextSibling : lastNode, false);
3452            } else {
3453                if (!this.W3CRange) {
3454                    div = this.doc.createElement('div');
3455                    div.appendChild(fragment);
3456                    range.pasteHTML(div.innerHTML);
3457                } else {
3458                    range.deleteContents();
3459                    range.insertNode(fragment);
3460                    range.setStartAfter(lastNode);
3461                    range.setEndAfter(lastNode);
3462                    selection = this.getSelection();
3463                    selection.removeAllRanges();
3464                    selection.addRange(range);
3465                }
3466            }
3467            this.setImageEvent(true);
3468        }
3469    },
3470
3471    showTagSelector : function (on) {
3472        if (this.config.showTagPath !== true) {
3473            return;
3474        }
3475        this.cheditor.tagPath.style.display = on ? 'block' : 'none';
3476    },
3477
3478    getTextContentSelectionPos : function (newline) {
3479        var textContent = this.cheditor.textContent,
3480            start, end, docRange, startRange, endRange, textContentLength, normalizedText;
3481
3482        if (typeof textContent.selectionStart === 'number') {
3483            start = textContent.selectionStart;
3484            end = textContent.selectionEnd;
3485        } else {
3486            textContentLength = textContent.value.length;
3487            normalizedText = textContent.value.replace(/\r\n/g, '\n');
3488            docRange = document.selection.createRange();
3489            startRange = textContent.createTextRange();
3490            endRange = startRange.duplicate();
3491            endRange.collapse(false);
3492            startRange.moveToBookmark(docRange.getBookmark());
3493
3494            if (startRange.compareEndPoints('StartToEnd', endRange) > -1) {
3495                start = end = textContentLength;
3496            } else {
3497                start = -startRange.moveStart('character', -textContentLength);
3498                if (newline) {
3499                    start += normalizedText.slice(0, start).split('\n').length - 1;
3500                }
3501                if (startRange.compareEndPoints('EndToEnd', endRange) > -1) {
3502                    end = textContentLength;
3503                } else {
3504                    end = -startRange.moveEnd('character', -textContentLength);
3505                    if (newline) {
3506                        end += normalizedText.slice(0, end).split('\n').length - 1;
3507                    }
3508                }
3509            }
3510        }
3511        return { startPos: start, endPos: end };
3512    },
3513
3514    setTextContentSelection : function (startPos, endPos, content) {
3515        var textContent = this.cheditor.textContent, range, top;
3516        if (!content) {
3517            textContent.focus();
3518            return;
3519        }
3520        if (startPos === 0 && endPos === 0) {
3521            textContent.value = content;
3522            textContent.focus();
3523            return;
3524        }
3525        textContent.select();
3526        if (typeof textContent.setSelectionRange === 'function') {
3527            textContent.value = content;
3528            textContent.setSelectionRange(startPos, startPos);
3529            textContent.focus();
3530            if (this.browser.msie || this.browser.edge) {
3531                setTimeout(function () {
3532                    top = textContent.scrollTop;
3533                    if (top > 0) {
3534                        textContent.scrollTop = top + textContent.clientHeight / 2;
3535                    }
3536                    textContent.selectionEnd = endPos;
3537                }, 0);
3538            } else {
3539                textContent.selectionEnd = endPos;
3540            }
3541        } else {
3542            range = document.selection.createRange();
3543            textContent.value = content;
3544            range.moveEnd('character', endPos - content.length);
3545            range.moveStart('character', startPos);
3546            range.select();
3547            top = textContent.scrollTop;
3548            if (top > 0) {
3549                textContent.scrollTop = top + textContent.clientHeight / 2;
3550            }
3551        }
3552    },
3553
3554    richMode : function () {
3555        var startPos, endPos, char, cursor, outputHTML = null, textContentLength, collapsed,
3556            range, startRange, endRange, selection, startNode, endNode, scrollTop, pNode, pos,
3557            textContent = null;
3558        if (this.cheditor.mode === 'code' && typeof this.resizeTextContent !== 'undefined') {
3559            this.cheditor.textContent.focus();
3560            textContent = this.makeHtmlContent();
3561            textContentLength = textContent.length;
3562
3563            pos = this.getTextContentSelectionPos(true);
3564            startPos = pos.startPos;
3565            endPos = pos.endPos;
3566
3567            collapsed = startPos === endPos;
3568            cursor = startPos;
3569
3570            if (textContent.charAt(startPos) === '>') {
3571                startPos++;
3572                collapsed = true;
3573            } else {
3574                while (cursor > -1) {
3575                    char = textContent.charAt(cursor);
3576                    if (char === '&'
3577                        && textContent.charAt(cursor + 1) === 'n' && textContent.charAt(cursor + 2) === 'b'
3578                        && textContent.charAt(cursor + 3) === 's' && textContent.charAt(cursor + 4) === 'p'
3579                        && textContent.charAt(cursor + 5) === ';')
3580                    {
3581                        startPos = cursor;
3582                        collapsed = endPos < (startPos + 6);
3583                        break;
3584                    }
3585                    if (char === '>') {
3586                        break;
3587                    }
3588                    if (char === '<') {
3589                        startPos = cursor;
3590                        collapsed = true;
3591                        break;
3592                    }
3593                    cursor--;
3594                }
3595            }
3596
3597            if (!collapsed) {
3598                cursor = endPos;
3599                if (textContent.charAt(endPos - 1) === '<' ||
3600                    (textContent.charAt(endPos) === '\n' && cursor === textContentLength - 1)) {
3601                    endPos = startPos;
3602                } else {
3603                    while (cursor < textContentLength) {
3604                        char = textContent.charAt(cursor);
3605                        if (char === '<') {
3606                            break;
3607                        }
3608                        if (char === '>') {
3609                            endPos = startPos;
3610                            break;
3611                        }
3612                        cursor++;
3613                    }
3614                }
3615            } else {
3616                endPos = startPos;
3617            }
3618
3619            if (startPos > 0 && endPos < textContentLength - 1) {
3620                outputHTML = textContent.substring(0, startPos);
3621                outputHTML += '<span id="startBogusNode"></span>';
3622                outputHTML += textContent.substring(startPos, endPos);
3623                outputHTML += '<span id="endBogusNode"></span>';
3624                outputHTML += textContent.substring(endPos, textContent.length);
3625                textContent = outputHTML;
3626            }
3627
3628            this.cheditor.textContent.value = '';
3629            this.removeEvent(window, 'resize', this.resizeTextContent);
3630            this.putContents(this.convertContentsSpacer(textContent));
3631        }
3632
3633        this.range = null;
3634        this.cheditor.textContent.blur();
3635        this.cheditor.textContent.removeAttribute('start-pos');
3636        this.cheditor.textContent.removeAttribute('end-pos');
3637        this.cheditor.textContent.style.display = 'none';
3638        this.cheditor.toolbarWrapper.style.display = '';
3639        this.cheditor.toolbarWrapper.className = 'cheditor-tb-wrapper';
3640        this.cheditor.editArea.style.visibility = 'hidden';
3641        if (!this.setFullScreenMode) {
3642            this.cheditor.editArea.style.height = this.config.editorHeight;
3643        }
3644
3645        this.cheditor.editArea.style.display = 'block';
3646        this.cheditor.editArea.style.visibility = 'visible';
3647        this.setDesignMode(true);
3648        this.editAreaFocus();
3649
3650        if (outputHTML) {
3651            startNode = this.doc.getElementById('startBogusNode');
3652            endNode = this.doc.getElementById('endBogusNode');
3653            if (startNode && endNode) {
3654                scrollTop = 0;
3655                pNode = startNode;
3656                if (pNode) {
3657                    while (pNode.offsetParent) {
3658                        scrollTop += pNode.offsetTop;
3659                        pNode = pNode.offsetParent;
3660                    }
3661                    scrollTop -= this.getWindowSize(this.doc).height / 2;
3662                }
3663
3664                if (this.doc.compatMode === 'CSS1Compat') {
3665                    this.doc.documentElement.scrollTop = scrollTop;
3666                } else {
3667                    this.doc.body.scrollTop = scrollTop;
3668                }
3669
3670                if (this.W3CRange) {
3671                    selection = this.clearSelection();
3672                    range = this.createRange();
3673                    range.setStartAfter(startNode);
3674                    range.setEndBefore(endNode);
3675                    try {
3676                        selection.addRange(range);
3677                    } catch (ignore) {
3678                        // display: none?
3679                    }
3680                } else {
3681                    startRange = this.createRange();
3682                    endRange = startRange.duplicate();
3683                    startRange.moveToElementText(startNode);
3684                    endRange.moveToElementText(endNode);
3685                    startRange.setEndPoint('StartToEnd', startRange);
3686                    startRange.setEndPoint('EndToEnd', endRange);
3687                    startRange.select();
3688                }
3689
3690                pNode = startNode.parentNode;
3691                pNode.removeChild(startNode);
3692                pNode = endNode.parentNode;
3693                pNode.removeChild(endNode);
3694            }
3695        }
3696
3697        this.setImageEvent(true);
3698        this.toolbarUpdate();
3699    },
3700
3701    editMode : function () {
3702        var self = this,
3703            editorWidth, scrollBarWidth, scrollBarHeight, resize, content = null, borderWidth = 1, borderHeight = 1,
3704            startPos, endPos, startNode, endNode, startEndNode,
3705            editorHeight = this.cheditor.editWrapper.offsetHeight,
3706            textContent = this.cheditor.textContent,
3707            startNodeValue = 'startBogusNode', endNodeValue = 'endBogusNode',
3708            startNodeCommentTag = '<!--' + startNodeValue + '-->', endNodeCommentTag = '<!--' + endNodeValue + '-->',
3709            range = this.restoreRange();
3710
3711        if (this.cheditor.mode === 'preview') {
3712            if (textContent.getAttribute('start-pos')) {
3713                startPos = parseInt(textContent.getAttribute('start-pos'), 10);
3714                textContent.removeAttribute('start-pos');
3715
3716                if (textContent.getAttribute('end-pos')) {
3717                    endPos = parseInt(textContent.getAttribute('end-pos'), 10);
3718                    textContent.removeAttribute('end-pos');
3719                } else {
3720                    endPos = startPos;
3721                }
3722                content = textContent.value.replace(/\r\n/g, '\n');
3723            } else {
3724                this.placeCaretAt(this.doc.body.firstChild || this.doc.body, true);
3725                range = this.getRange();
3726            }
3727        }
3728
3729        if (!content) {
3730            startEndNode = this.insertStartEndNode(range);
3731            startNode = this.doc.createComment(startNodeValue);
3732            endNode = this.doc.createComment(endNodeValue);
3733            startEndNode.startNode.parentNode.replaceChild(startNode, startEndNode.startNode);
3734            startEndNode.endNode.parentNode.replaceChild(endNode, startEndNode.endNode);
3735            startEndNode.startNode = startNode;
3736            startEndNode.endNode = endNode;
3737
3738            content = this.getContents(startEndNode);
3739
3740            startPos = content.search(startNodeCommentTag);
3741            endPos = content.search(endNodeCommentTag);
3742            endPos -= endNodeCommentTag.length + 2;
3743            content = content.replace(startNodeCommentTag, '').replace(endNodeCommentTag, '');
3744        }
3745
3746        this.resetDocumentBody();
3747        this.cheditor.editArea.style.display = 'none';
3748        this.cheditor.toolbarWrapper.className = 'cheditor-tb-wrapper-code';
3749        this.cheditor.editBlock.style.display = 'none';
3750
3751        textContent.value = '';
3752        textContent.style.lineHeight = '17px';
3753        textContent.style.width = '100px';
3754        textContent.style.height = '100px';
3755        textContent.style.display = 'block';
3756
3757        scrollBarWidth = textContent.offsetWidth - 100;
3758        scrollBarHeight = textContent.offsetHeight - 100;
3759        if (this.browser.msie && this.browser.version < 8) {
3760            scrollBarHeight += 2;
3761        }
3762
3763        textContent.setAttribute('xbar-height', scrollBarHeight.toString());
3764        textContent.setAttribute('ybar-width', scrollBarWidth.toString());
3765
3766        resize = textContent.offsetHeight + (editorHeight - textContent.offsetHeight) - scrollBarHeight - borderHeight;
3767        textContent.style.height = resize + 'px';
3768
3769        this.resizeTextContent = function () {
3770            editorWidth = self.cheditor.editWrapper.offsetWidth;
3771            resize = textContent.offsetWidth + (editorWidth - textContent.offsetWidth) - scrollBarWidth - borderWidth;
3772            self.cheditor.textContent.style.width = resize + 'px';
3773        };
3774
3775        (function () {
3776            self.addEvent(window, 'resize', self.resizeTextContent);
3777            self.resizeTextContent();
3778        })();
3779
3780        this.setTextContentSelection(startPos, endPos, content);
3781        this.setDesignMode(false);
3782    },
3783
3784    makeHtmlContent : function () {
3785        var content = this.trimSpace(this.cheditor.textContent.value);
3786        content = this.trimZeroSpace(content);
3787        return content || '<p>&nbsp;</p>';
3788    },
3789
3790    resetStatusBar : function () {
3791        if (this.config.showTagPath) {
3792            this.cheditor.tagPath.innerHTML = '&lt;html&gt; &lt;body&gt; ';
3793        }
3794    },
3795
3796    previewMode : function () {
3797        var content, oSheet, pos = this.getTextContentSelectionPos(false);
3798
3799        if (this.cheditor.mode === 'code' && typeof this.resizeTextContent !== 'undefined') {
3800            this.cheditor.textContent.setAttribute('start-pos', pos.startPos.toString());
3801            this.cheditor.textContent.setAttribute('end-pos', pos.endPos.toString());
3802            content = this.makeHtmlContent();
3803            this.cheditor.textContent.blur();
3804            this.cheditor.textContent.style.display = 'none';
3805            this.removeEvent(window, 'resize', this.resizeTextContent);
3806            this.putContents(content);
3807        }
3808
3809        this.clearSelection();
3810        this.cheditor.editBlock.style.display = 'none';
3811        this.cheditor.toolbarWrapper.className = 'cheditor-tb-wrapper-preview';
3812        if (!this.setFullScreenMode) {
3813            this.cheditor.editArea.style.height = this.config.editorHeight;
3814        }
3815        this.cheditor.editArea.style.display = 'block';
3816
3817        if (GB.browser.msie && parseInt(GB.browser.version, 10) === 8) {
3818            try {
3819                oSheet = this.doc.styleSheets[0];
3820                oSheet.addRule('p:before', 'content:"\u200b"');
3821            } catch (ignore) {
3822                // ignore
3823            }
3824        }
3825        this.setImageEvent(false);
3826        this.setDesignMode(false);
3827    },
3828
3829    convertContentsSpacer : function (content) {
3830        var self = this, bogusBr = true,
3831            excepted = '<span id="startBogusNode"><\/span><span id="endBogusNode"><\/span>',
3832            reSpacer = new RegExp('<([^>]+)>(' + excepted + ')?(?:&nbsp;|\s+)(' + excepted + ')?<\/([^>]+)>', 'g');
3833
3834        if (GB.browser.msie && GB.browser.msie_bogus === false) {
3835            bogusBr = false;
3836        }
3837        content = content.replace(/\s{2,}|[\r\n\t]+?/gm, '');
3838        content = content.replace(reSpacer,
3839            function (all, open, excepted_a, excepted_b, close) {
3840                var tagName = self.trimSpace(open.split(' ')[0]).toLowerCase(), rdata = null;
3841                if (GB.lineHeightBlockTags[tagName] || GB.textFormatTags[tagName]) {
3842                    rdata = '<' + open + '>' + (excepted_a || '');
3843                    rdata += (bogusBr) ? '<br class="' + self.cheditor.bogusSpacerName + '" />' :
3844                        '<!--' + self.cheditor.bogusSpacerName + '-->';
3845                    rdata += (excepted_b || '') + '</' + close + '>';
3846                }
3847                return rdata || all;
3848            }
3849        );
3850        return content;
3851    },
3852
3853    putContents : function (content) {
3854        if (this.config.fullHTMLSource) {
3855            content = content.substr(content.search(/<html/ig) + 1);
3856            content = content.substr(content.indexOf('>') + 1);
3857            content = '<html>' + content;
3858            this.doc.open();
3859            this.doc.write('<body>' + content + '</body>');
3860            this.doc.close();
3861        } else {
3862            content = '<span>remove_this</span>' + content;
3863            this.doc.body.innerHTML = content;
3864            this.doc.body.removeChild(this.doc.body.firstChild);
3865        }
3866    },
3867
3868    getImages : function () {
3869        var img = this.doc.body.getElementsByTagName('img'),
3870            imgLength = this.images.length,
3871            imgs = [], i, imgId, j;
3872
3873        for (i = 0; i < img.length; i++) {
3874            if (img[i].src) {
3875                imgId = img[i].src;
3876                imgId = imgId.slice(imgId.lastIndexOf('/') + 1);
3877                for (j = 0; j < imgLength; j++) {
3878                    if (this.images[j].fileName === imgId) {
3879                        imgs.push(this.images[j]);
3880                        break;
3881                    }
3882                }
3883            }
3884        }
3885        return imgs.length > 0 ? imgs : null;
3886    },
3887
3888    getElementStyle : function (elem) {
3889        return (window.getComputedStyle) ? this.doc.defaultView.getComputedStyle(elem, null) : elem.currentStyle;
3890    },
3891
3892    getElementDefaultDisplay : function (elem) {
3893        return (window.getComputedStyle ? this.doc.defaultView.getComputedStyle(elem, null) : elem.currentStyle).display;
3894    },
3895
3896    tabRepeat : function (count) {
3897        var i = 0, tab = '';
3898        if (count < 1) {
3899            return tab;
3900        }
3901        for (; i < count; i++) {
3902            tab += this.cheditor.tabSpaces;
3903        }
3904        return tab;
3905    },
3906
3907    htmlEncode : function (text) {
3908        //text = text.replace(/\n{2,}$/g, '\n');
3909        //text = text.replace(/&/g, '&amp;');
3910        text = text.replace(/</g, '&lt;');
3911        text = text.replace(/>/g, '&gt;');
3912        text = text.replace(/\u00a0/g, '&nbsp;');
3913        //text = text.replace(/<font ([^>]+)>&nbsp;<\/font>/mgi, '');
3914        //text = text.replace(/\x22/g, '&quot;');
3915        return text;
3916    },
3917
3918    checkDocLinks : function () {
3919        var links = this.doc.links,
3920            len = links.length,
3921            host = location.host,
3922            i, href;
3923
3924        this.cheditor.links = [];
3925
3926        for (i = 0; i < len; i++) {
3927            if (!this.config.includeHostname) {
3928                href = links[i].href;
3929                if (href.indexOf(host) !== -1) {
3930                    links[i].setAttribute('href', href.substring(href.indexOf(host) + host.length));
3931                }
3932            }
3933            if (this.config.linkTarget !== '' && this.config.linkTarget !== null) {
3934                if (!(links[i].getAttribute('target'))) {
3935                    links[i].setAttribute('target', this.config.linkTarget);
3936                }
3937            }
3938            if (GB.browser.msie) {
3939                this.cheditor.links.push(links[i]);
3940            }
3941        }
3942    },
3943
3944    checkDocImages : function () {
3945        var img = this.doc.images,
3946            len = img.length,
3947            host = location.host,
3948            i = 0, imgUrl;
3949
3950        for (; i < len; i++) {
3951            if (!this.config.includeHostname) {
3952                imgUrl = img[i].src;
3953                if (imgUrl) {
3954                    if (imgUrl.indexOf(host) !== -1) {
3955                        img[i].src = imgUrl.substring(imgUrl.indexOf(host) + host.length);
3956                    }
3957                }
3958            }
3959            if (img[i].style.width) {
3960                img[i].removeAttribute('width');
3961            }
3962            if (img[i].style.height) {
3963                img[i].removeAttribute('height');
3964            }
3965        }
3966    },
3967
3968    createNbspTextNode : function () {
3969        return this.doc.createTextNode('\u00a0');
3970    },
3971
3972    getNodeTree : function (pNode, callback) {
3973        function Node(node) {
3974            this.node = node;
3975            this.name = node.nodeName.toLowerCase();
3976            this.type = node.nodeType;
3977            this.parent = node.parentNode;
3978            this.indent = 0;
3979        }
3980        (function recurse(cNode, indent) {
3981            var i, child,
3982                node = new Node(cNode),
3983                children = cNode.childNodes,
3984                len = children.length;
3985
3986            node.indent = indent;
3987
3988            for (i = 0; i < len; i++) {
3989                child = children[i];
3990                if (child) {
3991                    recurse(child, indent + 1);
3992                }
3993            }
3994
3995            if (node.name !== 'body') {
3996                callback(node);
3997            }
3998        })(pNode, -1);
3999    },
4000
4001    getContents : function (startEndNode) {
4002        var self = this,
4003            mydoc, indentNodes = [], i, node, msie_c = typeof this.browser.msie_c !== 'undefined',
4004            allowedIndent = this.getContents.caller !== this.getBodyContents,
4005            insertTabSpace = function (indent) {
4006                return msie_c ? self.doc.createComment('Tab Size:' + indent) :
4007                    self.doc.createTextNode('\n' + self.tabRepeat(indent));
4008            };
4009        function checkChildNodes(child) {
4010            if (!child) {
4011                return null;
4012            }
4013            if (!startEndNode) {
4014                return child;
4015            }
4016            do {
4017                if (child !== startEndNode.startNode && child !== startEndNode.endNode) {
4018                    break;
4019                }
4020                child = child.nextSibling;
4021            } while (child);
4022
4023            return child;
4024        }
4025
4026        this.checkDocLinks();
4027        this.checkDocImages();
4028        this.getNodeTree(this.doc.body, function (node) {
4029            if (!node.node) {
4030                return;
4031            }
4032            if (self.config.exceptedElements[node.name]) {
4033                node.parent.replaceChild(self.doc.createTextNode(''), node.node);
4034                return;
4035            }
4036
4037            switch (node.type) {
4038                case GB.node.text :
4039                    if (!self.isTextVisible(node.node.nodeValue)) {
4040                        node.parent.replaceChild(self.doc.createTextNode(''), node.node);
4041                    }
4042                    break;
4043                case GB.node.element :
4044                    if (node.node.className === self.cheditor.bogusSpacerName) {
4045                        if (node.node.firstChild === null) {
4046                            if (node.name === 'br') {
4047                                node.parent.removeChild(node.node);
4048                                if (!checkChildNodes(node.parent.firstChild)) {
4049                                    node.parent.appendChild(self.createNbspTextNode());
4050                                }
4051                            } else {
4052                                node.node.appendChild(self.createNbspTextNode());
4053                            }
4054                        } else if (!checkChildNodes(node.node.firstChild)) {
4055                            node.node.appendChild(self.createNbspTextNode());
4056                        }
4057                        node.node.className = '';
4058                    }
4059                    if ((node.name === 'p' || node.name === 'div') && !c
4059heckChildNodes(node.node.firstChild)) {
4060                        node.node.appendChild(self.createNbspTextNode());
4061                    }
4062                    if (GB.newLineBeforeTags[node.name] && allowedIndent) {
4063                        if (node.node.firstChild && (node.node.firstChild.nodeType === GB.node.element)) {
4064                            node.node.insertBefore(insertTabSpace(node.indent + 1), node.node.firstChild);
4065                            node.node.appendChild(insertTabSpace(node.indent));
4066                        }
4067                        indentNodes.push(node);
4068                    }
4069                    break;
4070                case GB.node.comment :
4071                    if (node.node.nodeValue === self.cheditor.bogusSpacerName) {
4072                        node.parent.removeChild(node.node);
4073                        if (!checkChildNodes(node.parent.firstChild)) {
4074                            node.parent.appendChild(self.createNbspTextNode());
4075                        } else if (node.parent.firstChild.nodeName.toLowerCase() === 'br') {
4076                            node.parent.replaceChild(self.createNbspTextNode(), node.node.firstChild);
4077                        }
4078                    }
4079            }
4080        });
4081
4082        for (i in indentNodes) {
4083            if (indentNodes.hasOwnProperty(i)) {
4084                node = indentNodes[i];
4085                node.parent.insertBefore(insertTabSpace(node.indent), node.node);
4086                if (node.node.nextSibling) {
4087                    node.node.nextSibling.parentNode.insertBefore(insertTabSpace(node.indent), node.node.nextSibling);
4088                } else {
4089                    node.parent.appendChild(insertTabSpace(node.indent));
4090                }
4091            }
4092        }
4093
4094        indentNodes = [];
4095        mydoc = this.doc.body.innerHTML;
4096
4097        if (msie_c) {
4098            mydoc = mydoc.replace(/<!--Tab Size:(\d+)-->(?:[\r\n]*)/g,
4099                function (a, b) {
4100                    return '\n' + self.tabRepeat(b);
4101                }).replace(/<(\/?)([A-Za-z]+)([^>]*)>/g,
4102                function (a, close, tag, attr) {
4103                    attr = attr.replace(/\s(\w+)=([^'"\s>]+)/g,
4104                        function (a, k, v) {
4105                            return ' ' + k.toLowerCase() + '="' + v + '"';
4106                        }).replace(/([A-Za-z\-]+)(?:\s*):\s+?/g,
4107                        function (a, k) {
4108                            return k.toLowerCase() + ': ';
4109                        });
4110                    return '<' + close + tag.toLowerCase() + attr + '>';
4111                }
4112            );
4113        }
4114
4115        mydoc = mydoc.replace(/^\s*[\r\n]/gm, '').replace(/\u200b/g, '');
4116
4117        if (this.config.allowedOnEvent !== true) {
4118            mydoc = mydoc.replace(/<[^>]+>/gm, function (match) {
4119                return match.replace(/\s+on([A-Za-z]+)=("[^"]*"|'[^']*'|[^\s>]*)/g, '');
4120            });
4121        }
4122
4123        if (this.config.colorToHex) {
4124            mydoc = mydoc.replace(/(background\-color|color)\s*([:=])\s*(rgba?)\(\s*(\d+)\s*,\s*(\d+),\s*(\d+)\)/ig,
4125                function (all, p, s, rgb, r, g, b) {
4126                    return p + s + ' ' + self.colorConvert(rgb + '(' + r + ',' + g + ',' + b + ')', 'hex');
4127                });
4128        } else {
4129            mydoc = mydoc.replace(/(background\-color|color)\s*([:=])\s*(#[A-Fa-f0-9]{3,6})/ig,
4130                function (all, p, s, hex) {
4131                    alert(hex);
4132                    return p + s + ' ' + self.colorConvert(hex, 'rgb');
4133                });
4134        }
4135        return mydoc;
4136    },
4137
4138    returnContents : function (mydoc) {
4139        this.setDesignMode(true);
4140        this.cheditor.textarea.value = mydoc;
4141        return mydoc;
4142    },
4143
4144    makeAmpTag : function (str) {
4145        return str.replace(/&lt;/g, '&amp;lt;').replace(/&gt;/g, '&amp;gt;');
4146    },
4147
4148    removeAmpTag : function (str) {
4149        if (this.config.removeIndent) {
4150            str = str.replace(/^[\t]+/gm, '');
4151        }
4152        return str.replace (/&amp;lt;/g, '&lt;').replace(/&amp;gt;/g, '&gt;');
4153    },
4154
4155    getOutputContents : function () {
4156        this.resetViewHTML();
4157        return this.removeAmpTag(this.getContents(null));
4158    },
4159
4160    outputHTML : function () {
4161        return '<!DOCTYPE html>\n' +
4162            '<html>\n' +
4163            '   <head>\n' +
4164            '      <title>' + this.config.docTitle + '</title>\n' +
4165            '   </head>\n' +
4166            '   <body>\n' +
4167            this.returnContents(this.getOutputContents()) +
4168            '   </body>\n' +
4169            '</html>';
4170    },
4171
4172    getBodyContents : function () {
4173        return (this.cheditor.mode === 'code') ? this.makeHtmlContent() : this.getContents(null);
4174    },
4175
4176    outputBodyHTML : function () {
4177        return this.returnContents(this.getOutputContents());
4178    },
4179
4180    outputBodyText : function () {
4181        return this.returnContents(this.getBodyText());
4182    },
4183
4184    getBodyText : function () {
4185        this.resetViewHTML();
4186        return this.trimSpace(String(GB.browser.msie ? this.doc.body.innerText : this.doc.body.textContent));
4187    },
4188
4189    returnFalse : function () {
4190        var img = this.doc.images, i;
4191        this.editAreaFocus();
4192
4193        for (i = 0; i < img.length; i++) {
4194            if (img[i].src) {
4195                if (img[i].getAttribute('onload')) {
4196                    img[i].onload = 'true';
4197                }
4198            } else {
4199                img[i].removeAttribute('onload');
4200                img[i].removeAttribute('className');
4201            }
4202        }
4203        return false;
4204    },
4205
4206    trimZeroSpace : function (str) {
4207        return str ? str.replace(/[\ufeff\u200b\xa0\u3000]+/gm, '') : '';
4208    },
4209
4210    trimSpace : function (str) {
4211        return str ? str.replace(/^[\s\ufeff\u200b\xa0\u3000]+|[\s\ufeff\u200b\xa0\u3000]+$/g, '') : '';
4212    },
4213
4214    makeRandomString : function () {
4215        var chars = '_-$@!#0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz',
4216            len = 32,
4217            clen = chars.length,
4218            rData = '', i, rnum;
4219
4220        for (i = 0; i < len; i++) {
4221            rnum = Math.floor(Math.random() * clen);
4222            rData += chars.substring(rnum, rnum + 1);
4223        }
4224        return rData;
4225    },
4226
4227    strLength : function (str) {
4228        var len = str.length, mbytes = 0, i, c;
4229        for (i = 0; i < len; i++) {
4230            c = str.charCodeAt(i);
4231            if (c > 128) {
4232                mbytes++;
4233            }
4234        }
4235        return (len - mbytes) + (mbytes * 2);
4236    },
4237
4238    resetViewHTML : function () {
4239        if (this.cheditor.mode === 'code') {
4240            this.switchEditorMode('rich');
4241        }
4242    },
4243
4244    contentsLengthAll : function () {
4245        return this.strLength(this.outputHTML());
4246    },
4247
4248    contentsLength : function () {
4249        var content = String(this.trimSpace(this.outputBodyHTML()));
4250        if (!content || content === '') {
4251            return 0;
4252        }
4253        return this.strLength(content);
4254    },
4255
4256    inputLength : function () {
4257        var content = this.getBodyText();
4258        if (content === '') {
4259            return 0;
4260        }
4261        return this.strLength(content);
4262    },
4263
4264    displayWindow : function (pNode, id) {
4265        var pullDown = this.pulldown[id];
4266        this.editAreaFocus();
4267        this.backupRange();
4268        this.boxHideAll(id);
4269        pullDown.style.visibility = 'visible';
4270        pullDown.style.zIndex = 10002;
4271        pullDown.focus();
4272    },
4273
4274    pulldownMouseOver : function (el) {
4275        if (el.className === 'cheditor-pulldown-selected') {
4276            return;
4277        }
4278        el.className = 'cheditor-pulldown-mouseover';
4279    },
4280    pulldownMouseOut  : function (el) {
4281        if (el.className === 'cheditor-pulldown-selected') {
4282            return;
4283        }
4284        el.className = 'cheditor-pulldown-mouseout';
4285    },
4286
4287    windowPos : function (pNode, id) {
4288        var left = pNode.offsetLeft, box = this.pulldown[id];
4289
4290        if (this.toolbar[id].type === 'combobox') {
4291            left -= parseInt(this.toolbar[this.toolbar[id].node].width, 10);
4292        }
4293        if (this.toolbar[id].prev && !this.toolbar[id].next) {
4294            left -= 1;
4295        }
4296        box.style.left = left + 'px';
4297        box.style.top  = pNode.offsetTop + parseInt(pNode.style.height, 10) + 'px';
4298    },
4299
4300    boxHideAll : function (showId) {
4301        var menu, box, ishide;
4302        for (menu in this.pulldown) {
4303            if (this.pulldown.hasOwnProperty(menu)) {
4304                box = this.pulldown[menu];
4305                if (box) {
4306                    box.style.visibility = 'hidden';
4307                    ishide = this.undefined(showId) ? true : (menu !== showId);
4308                    if (ishide && this.toolbar[menu].checked) {
4309                        this.toolbar[menu].checked = false;
4310                        this.toolbarButtonUnchecked(this.toolbar[menu]);
4311                    }
4312                }
4313            }
4314        }
4315        this.editAreaFocus();
4316    },
4317
4318    createWindow : function (width, elem) {
4319        elem.className = 'cheditor-pulldown-container';
4320        elem.style.width = width + 'px';
4321    },
4322
4323    setColorTable : function (menu) {
4324        var self = this,
4325            pulldown = document.createElement('div'),
4326            len = GB.colors.length,
4327            container = document.createElement('div'),
4328            selected = document.createElement('input'),
4329            selectedValue = document.createElement('input'),
4330            cellWrapper = document.createElement('div'),
4331            br = document.createElement('div'),
4332            reset = document.createElement('span'),
4333            pickerSwitch = document.createElement('span'),
4334            button = document.createElement('img'),
4335            showTooltip = '더 많은 색 보기',
4336            hideTooltip = '감추기',
4337            i, cell, color = 0, colorPicker, cellBorder,
4338            onMouseOverEventHandler = function () {
4339                colorPicker.fromString(this.id);
4340                this.parentNode.className = 'cheditor-pulldown-color-cell-over';
4341            },
4342            onMouseOutEventHandler = function () {
4343                this.parentNode.className = 'cheditor-pulldown-color-cell';
4344            },
4345            onClickEventHandler = function () {
4346                self.doCmdPopup(menu, this.id);
4347            },
4348            onResetEventHandler = function () {
4349                colorPicker.fromString(self.colorConvert(selectedValue.style.backgroundColor, 'hex'));
4350            },
4351            onPickerEventHandler = function () {
4352                if (self.toolbar[menu].colorNode.showPicker) {
4353                    colorPicker.hidePicker();
4354                    self.toolbar[menu].colorNode.showPicker = false;
4355                    pickerSwitch.setAttribute('title', showTooltip);
4356                } else {
4357                    colorPicker.showPicker();
4358                    self.toolbar[menu].colorNode.showPicker = true;
4359                    pickerSwitch.setAttribute('title', hideTooltip);
4360                }
4361            },
4362            onSubmitEventHandler = function () {
4363                self.doCmdPopup(menu, selected.value);
4364            };
4365
4366        selected.setAttribute('type', 'text');
4367        selected.setAttribute('maxlength', '7');
4368        selected.className = 'cheditor-pulldown-color-selected';
4369
4370        selectedValue.setAttribute('type', 'text');
4371        selectedValue.onfocus = function () {
4372            selected.focus();
4373        };
4374
4375        selectedValue.style.cursor = 'default';
4376        selectedValue.className = 'cheditor-pulldown-color-selected';
4377        selected.style.marginLeft = '-1px';
4378        selected.style.borderLeft = 'none';
4379        selected.spellcheck = false;
4380
4381        cellWrapper.style.margin = '2px';
4382        cellWrapper.style.position = 'relative';
4383        container.style.position = 'relative';
4384
4385        br.style.clear = 'both';
4386        br.style.height = '0px';
4387        colorPicker = new GB.colorDropper(selected, {'iconDir': this.config.iconPath});
4388
4389        for (i = 0; i < len; i++) {
4390            if (i % 13 === 0) {
4391                cellWrapper.appendChild(br.cloneNode(true));
4392                if (i === 26) {
4393                    cellWrapper.lastChild.style.height = '4px';
4394                }
4395                len++;
4396                continue;
4397            }
4398            cellBorder = document.createElement('span');
4399            cellBorder.className = 'cheditor-pulldown-color-cell';
4400            cell = document.createElement('span');
4401            cell.id = GB.colors[color];
4402            cell.style.backgroundColor = GB.colors[color++];
4403            cell.appendChild(document.createTextNode('\u00a0'));
4404            cellBorder.appendChild(cell);
4405            cellWrapper.appendChild(cellBorder);
4406            (function () {
4407                cell.onclick = onClickEventHandler;
4408                cell.onmouseover = onMouseOverEventHandler;
4409                cell.onmouseout = onMouseOutEventHandler;
4410            })();
4411        }
4412
4413        cellWrapper.appendChild(br);
4414        cellWrapper.appendChild(selectedValue);
4415        cellWrapper.appendChild(selected);
4416
4417        reset.appendChild(document.createTextNode('\u00a0'));
4418        reset.className = 'cheditor-pulldown-color-reset';
4419        reset.onclick = onResetEventHandler;
4420
4421        cellWrapper.appendChild(reset);
4422
4423        pickerSwitch.appendChild(document.createTextNode('\u00a0'));
4424        pickerSwitch.className = 'cheditor-pulldown-color-show-picker';
4425        pickerSwitch.setAttribute('title', showTooltip);
4426        pickerSwitch.onclick = onPickerEventHandler;
4427        cellWrapper.appendChild(pickerSwitch);
4428
4429        button.className = 'cheditor-pulldown-color-submit';
4430        button.src = this.config.iconPath + 'button/input_color.gif';
4431        button.onclick = onSubmitEventHandler;
4432        cellWrapper.appendChild(button);
4433        container.appendChild(cellWrapper);
4434
4435        self.toolbar[menu].colorNode.selectedValue = selectedValue;
4436        self.toolbar[menu].colorNode.colorPicker = colorPicker;
4437
4438        pulldown.appendChild(container);
4439        return pulldown;
4440    },
4441
4442    onKeyPressToolbarUpdate : function () {
4443        var self = this;
4444        if (this.tempTimer) {
4445            clearTimeout(this.tempTimer);
4446        }
4447        this.tempTimer = setTimeout(function () {
4448            if (self.config.showTagPath) {
4449                self.doEditorEvent();
4450            } else {
4451                self.toolbarUpdate();
4452            }
4453            self.tempTimer = null;
4454        }, 50);
4455    },
4456
4457    doOnKeyDown : function (evt) {
4458        switch (evt.keyCode) {
4459            case 37: case 38: case 39: case 40: case 46: case 8:
4460                this.onKeyPressToolbarUpdate(evt);
4461        }
4462    },
4463
4464    doOnKeyUp : function (evt) {
4465        var keyCode = evt.keyCode, self = this,
4466            node, caretRange, storedRange, enterNode, storedNode, css, i,
4467            clearBackgroundColor = function (cNode) {
4468                if (cNode.nodeType !== GB.node.element || cNode.hasChildNodes() || !cNode.getAttribute('style')) {
4469                    return cNode;
4470                }
4471                if (GB.textFormatTags[cNode.nodeName.toLowerCase()]) {
4472                    css = self.checkCssValue(cNode, 'background-color');
4473                    if (css) {
4474                        css = self.clearCss(cNode, 'background-color');
4475                        if (cNode.nodeName.toLowerCase() === 'span' && !css) {
4476                            node = cNode.parentNode;
4477                            node.removeChild(cNode);
4478                            return node;
4479                        }
4480                    }
4481                }
4482                return cNode;
4483            };
4484
4485        if (keyCode !== 13 || this.cheditor.mode !== 'rich') {
4486            return;
4487        }
4488
4489        if (typeof GB.browser.msie_c !== 'undefined') {
4490            node = this.storedSelections[0];
4491            if (!node) {
4492                return;
4493            }
4494            if (node.className === this.cheditor.bogusSpacerName) {
4495                node.className = '';
4496            }
4497            while (node.firstChild) {
4498                node = node.firstChild;
4499            }
4500            if (node.nodeType === GB.node.element && node.canHaveChildren) {
4501                node.className = this.cheditor.bogusSpacerName;
4502            }
4503            return;
4504        }
4505
4506        caretRange = this.getRange();
4507        enterNode = caretRange.commonAncestorContainer;
4508
4509        if (GB.browser.msie || GB.browser.edge) {
4510            this.backupRange(caretRange);
4511            if (enterNode.nodeType === GB.node.element) {
4512                enterNode = clearBackgroundColor(enterNode);
4513                enterNode.className = this.cheditor.bogusSpacerName;
4514            }
4515            for (i = 0; i < this.keyPressStoredSelections.length; i++) {
4516                storedRange = this.keyPressStoredSelections[i];
4517                storedNode = storedRange.commonAncestorContainer;
4518                if (storedNode && storedNode.nodeType === GB.node.element) {
4519                    node = storedNode.childNodes[storedRange.startOffset];
4520                    if (!node) {
4521                        break;
4522                    }
4523                    while (node.firstChild) {
4524                        node = node.firstChild;
4525                    }
4526                    node = clearBackgroundColor(node);
4527                    node.className = this.cheditor.bogusSpacerName;
4528                }
4529            }
4530            this.restoreRange();
4531            this.keyPressStoredSelections = [];
4532        } else {
4533            this.applyBogusClassName(caretRange);
4534        }
4535    },
4536
4537    doOnKeyPress : function (evt) {
4538        var keyCode = evt.keyCode, caretRange;
4539        if (keyCode && keyCode === 13 && this.cheditor.mode === 'rich') {
4540            caretRange = this.getRange();
4541            if (typeof this.browser.msie_c !== 'undefined') {
4542                try {
4543                    this.storedSelections[0] = caretRange.parentElement();
4544                } catch (e) {
4545                    this.keyPressBackupRange();
4546                }
4547            } else if (GB.browser.msie || GB.browser.edge) {
4548                this.keyPressBackupRange();
4549            } else {
4550                this.applyBogusClassName(caretRange);
4551            }
4552        }
4553    },
4554
4555    applyBogusClassName : function (range) {
4556        var node = range.commonAncestorContainer;
4557        if (range.startOffset < 1 && (!node.lastChild || node.lastChild.nodeName.toLowerCase() !== 'br')) {
4558            do {
4559                if (node.parentNode.nodeName.toLowerCase() === 'body') {
4560                    break;
4561                }
4562                node = node.parentNode;
4563            } while (GB.textFormatTags[node.nodeName.toLowerCase()]);
4564
4565            node = node.previousSibling;
4566            if (node) {
4567                while (node.firstChild) {
4568                    node = node.firstChild;
4569                }
4570                if (node.nodeType === GB.node.element && node.nodeName.toLowerCase() === 'br') {
4571                    node.className = this.cheditor.bogusSpacerName;
4572                }
4573            }
4574        } else {
4575            if (!node || node.nodeType !== GB.node.element) {
4576                return;
4577            }
4578            if (node.lastChild
4579                && node.lastChild.nodeName.toLowerCase() === 'br'
4580                && node.lastChild.className !== this.cheditor.bogusSpacerName)
4581            {
4582                node.lastChild.className = this.cheditor.bogusSpacerName;
4583            }
4584        }
4585    },
4586
4587    setWinPosition : function (oWin, popupAttr, windowSize) {
4588        oWin.style.width = popupAttr.width + 'px';
4589        oWin.style.left = Math.round(((this.cheditor.editArea.clientWidth - popupAttr.width) / 2) +
4590                windowSize.offsetLeft) + 'px';
4591
4592		// lbjtree 추가 
4593		var a = Math.round(((this.cheditor.editArea.clientWidth - popupAttr.width) / 2) + windowSize.offsetLeft);
4594		if(a<0) a = 0;
4595        oWin.style.left = a + 'px';
4596
4597        oWin.style.top = Math.round(windowSize.offsetTop) + 'px';
4598    },
4599
4600    getWindowSize : function (doc) {
4601        var mydoc = doc || document,
4602            docMode = mydoc.compatMode === 'CSS1Compat',
4603            docBody = mydoc.body,
4604            docElem = mydoc.documentElement,
4605            factor, rect, physicalWidth, logicalWidth,
4606            editAreaRect,
4607            rData = {
4608                width: docMode ? docElem.clientWidth : docBody.clientWidth,
4609                height: docMode ? docElem.clientHeight : docBody.clientHeight,
4610                scrollHeight: docMode ? docElem.scrollHeight : docBody.scrollHeight,
4611                scrollWidth: docMode ? docElem.scrollWidth : docBody.scrollWidth
4612            };
4613
4614        if (this.undefined(window.pageXOffset)) {
4615            factor = 1;
4616            if (docBody.getBoundingClientRect) {
4617                rect = docBody.getBoundingClientRect();
4618                physicalWidth = rect.right - rect.left;
4619                logicalWidth = mydoc.body.offsetWidth;
4620                factor = Math.round ((physicalWidth / logicalWidth) * 100) / 100;
4621            }
4622            rData.scrollY = Math.round(docElem.scrollTop / factor);
4623            rData.scrollX = Math.round(docElem.scrollLeft / factor);
4624        } else {
4625            rData.scrollY = window.pageYOffset;
4626            rData.scrollX = window.pageXOffset;
4627        }
4628
4629        editAreaRect = this.cheditor.editArea.getBoundingClientRect();
4630        rData.clientTop = docElem.clientTop || docBody.clientTop || 0;
4631        rData.clientLeft = docElem.clientLeft || docBody.clientLeft || 0;
4632        rData.offsetTop = rData.scrollY + (rData.height / 2);
4633        rData.offsetLeft = editAreaRect.left + rData.scrollX - rData.clientLeft;
4634        return rData;
4635    },
4636
4637    popupWinLoad : function (popupAttr) {
4638        var self = this,
4639            windowSize = self.getWindowSize(),
4640            iframe = document.createElement('iframe'),
4641            body = document.getElementsByTagName('body')[0],
4642            done = false,
4643
4644            popWinResizeHeight = function (evt) {
4645                iframe.contentWindow.focus();
4646                iframe.contentWindow.init.call(self, iframe, popupAttr.argv || null);
4647
4648                if (self.cheditor.popupElem.style.visibility !== 'visible') {
4649                    self.cheditor.popupElem.style.top = Math.ceil(parseInt(self.cheditor.popupElem.style.top, 10) -
4650                            Math.ceil(self.cheditor.popupElem.clientHeight / 2)) + 'px';
4651                    self.cheditor.popupElem.style.visibility = 'visible';
4652                }
4653
4654                self.stopEvent(evt);
4655            },
4656            modalResize = function () {
4657                self.cheditor.modalBackground.style.height = (windowSize.scrollHeight > windowSize.height) ?
4658                    windowSize.scrollHeight : windowSize.height + 'px';
4659
4660                if (window.scrollWidth > window.width) {
4661                    self.cheditor.modalBackground.style.width = windowSize.width +
4662                        (windowSize.scrollWidth - windowSize.width) + 'px';
4663                } else {
4664                    self.cheditor.modalBackground.style.width = windowSize.width + 'px';
4665                }
4666                self.cheditor.modalBackground.style.left = windowSize.scrollX + 'px';
4667            },
4668            onReadyStateChangeEventHandler = function (evt) {
4669                if (!done && (!this.readyState || this.readyState === 'complete' || this.readyState === 'loaded')) {
4670                    popWinResizeHeight(evt);
4671                    done = true;
4672                }
4673            };
4674
4675        if (self.cheditor.popupTitle.hasChildNodes()) {
4676            self.cheditor.popupTitle.removeChild(self.cheditor.popupTitle.firstChild);
4677        }
4678
4679        if (self.cheditor.popupFrameWrapper.hasChildNodes()) {
4680            self.cheditor.popupFrameWrapper.removeChild(self.cheditor.popupFrameWrapper.firstChild);
4681        }
4682
4683        self.cheditor.popupTitle.appendChild(document.createTextNode(popupAttr.title));
4684        self.cheditor.popupElem.style.zIndex = self.modalElementZIndex + 1;
4685        self.setWinPosition(self.cheditor.popupElem, popupAttr, windowSize);
4686
4687        iframe.setAttribute('frameBorder', '0');
4688        iframe.setAttribute('height', '0');
4689        iframe.setAttribute('width', String(popupAttr.width - 22));
4690        iframe.setAttribute('name', popupAttr.tmpl);
4691        iframe.setAttribute('src', self.config.popupPath + popupAttr.tmpl);
4692        iframe.id = popupAttr.tmpl;
4693
4694        self.cheditor.modalBackground.style.zIndex = self.modalElementZIndex;
4695        body.insertBefore(self.cheditor.modalBackground, body.firstChild);
4696        body.insertBefore(self.cheditor.popupElem, body.firstChild);
4697
4698        self.cheditor.popupFrameWrapper.appendChild(iframe);
4699        self.cheditor.popupElem.style.visibility = 'hidden';
4700        self.cheditor.popupElem.style.display = 'block';
4701        self.cheditor.modalBackground.style.display = 'block';
4702        GB.dragWindow.init(self.cheditor.dragHandle, self.cheditor.popupElem);
4703
4704        (function () {
4705            if (GB.browser.msie && !(self.undefined(iframe.onreadystatechange))) {
4706                iframe.onreadystatechange = onReadyStateChangeEventHandler;
4707            } else {
4708                iframe.onload = popWinResizeHeight;
4709            }
4710
4711            if (GB.browser.msie && GB.browser.version < 9) {
4712                window.onresize = function () {
4713                    windowSize = self.getWindowSize();
4714                    modalResize();
4715                };
4716                modalResize();
4717                self.cheditor.modalBackground.style.filter = 'alpha(opacity=50)';
4718                self.cheditor.modalBackground.style.opacity = 0.5;
4719            } else {
4720                self.cheditor.modalBackground.style.opacity = 0.5;
4721            }
4722            self.cheditor.modalBackground.focus();
4723        })();
4724    },
4725
4726    popupWinCancel : function () {
4727        this.restoreRange();
4728        this.popupWinClose();
4729    },
4730
4731    popupWinClose : function () {
4732        if (!this.cheditor.popupElem) {
4733            return;
4734        }
4735        this.cheditor.popupElem.style.display = 'none';
4736        this.cheditor.popupElem.style.zIndex = -1;
4737        this.cheditor.popupFrameWrapper.src = '';
4738
4739        if (this.cheditor.popupFrameWrapper.hasChildNodes()) {
4740            this.cheditor.popupFrameWrapper.removeChild(this.cheditor.popupFrameWrapper.firstChild);
4741        }
4742
4743        this.cheditor.modalBackground.style.display = 'none';
4744        this.cheditor.modalBackground.style.zIndex = -1;
4745
4746        if (this.modalReSize !== null) {
4747            if (GB.browser.opera) {
4748                window.removeEventListener('resize', this.modaReSize, false);
4749            }
4750            this.modalReSize = null;
4751        }
4752        this.editAreaFocus();
4753    },
4754
4755    clearStoredSelections : function () {
4756        this.storedSelections.splice(0, this.storedSelections.length);
4757    },
4758
4759    restoreRange : function () {
4760        var range = null, selection = null;
4761        if (this.storedSelections[0]) {
4762            if (this.W3CRange) {
4763                selection = this.getSelection();
4764                if (selection.rangeCount > 0) {
4765                    selection.removeAllRanges();
4766                }
4767                selection.addRange(this.storedSelections[0]);
4768                range = selection.getRangeAt(0);
4769            } else {
4770                range = this.createRange();
4771                if (this.storedSelections[0]) {
4772                    if (typeof this.storedSelections[0] === 'string') {
4773                        range.moveToBookmark(this.storedSelections[0]);
4774                    } else {
4775                        range = this.storedSelections[0];
4776                    }
4777                }
4778                range.select();
4779            }
4780        }
4781        return range;
4782    },
4783
4784    keyPressBackupRange : function (range) {
4785        var selection = null, i;
4786        if (this.W3CRange) {
4787            selection = this.getSelection();
4788            if (selection) {
4789                for (i = 0; i < selection.rangeCount; i++) {
4790                    this.keyPressStoredSelections.push(selection.getRangeAt(i));
4791                }
4792            }
4793        } else {
4794            range = range || this.getRange();
4795            switch (this.getSelectionType()) {
4796                case GB.selection.none:
4797                case GB.selection.text:
4798                    this.storedSelections[0] = range.getBookmark();
4799                    break;
4800                case GB.selection.element:
4801                    this.storedSelections[0] = range;
4802                    break;
4803                default:
4804                    this.storedSelections[0] = null;
4805            }
4806        }
4807    },
4808
4809    backupRange : function (range) {
4810        var selection = null;
4811        if (this.W3CRange) {
4812            selection = this.getSelection();
4813            if (selection && selection.rangeCount > 0) {
4814                this.storedSelections[0] = selection.getRangeAt(0);
4815            }
4816        } else {
4817            range = range || this.getRange();
4818            switch (this.getSelectionType()) {
4819                case GB.selection.none:
4820                case GB.selection.text:
4821                    this.storedSelections[0] = range.getBookmark();
4822                    break;
4823                case GB.selection.element:
4824                    this.storedSelections[0] = range;
4825                    break;
4826                default:
4827                    this.storedSelections[0] = null;
4828            }
4829        }
4830    },
4831
4832    getSelection : function () {
4833        return this.W3CRange ? this.editArea.getSelection() : this.doc.selection;
4834    },
4835
4836    clearSelection : function () {
4837        var sel = this.getSelection();
4838        if (!sel) {
4839            return;
4840        }
4841        if (this.W3CRange) {
4842            sel.removeAllRanges();
4843        } else {
4844            sel.empty();
4845        }
4846        return sel;
4847    },
4848
4849    getRange : function () {
4850        var selection = this.getSelection(), range = null;
4851        if (this.W3CRange) {
4852            if (selection.getRangeAt) {
4853                range = selection.rangeCount ? selection.getRangeAt(0) : this.doc.createRange();
4854            } else {
4855                range = this.doc.createRange();
4856                range.setStart(selection.anchorNode, selection.anchorOffset);
4857                range.setEnd(selection.focusNode, selection.focusOffset);
4858                if (range.collapsed !== selection.isCollapsed) {
4859                    range.setStart(selection.focusNode, selection.focusOffset);
4860                    range.setEnd(selection.anchorNode, selection.anchorOffset);
4861                }
4862            }
4863        } else {
4864            range = selection.createRange ? selection.createRange() : this.doc.createRange();
4865            if (!range) {
4866                range = this.doc.body.createTextRange();
4867            }
4868        }
4869        this.range = range;
4870        return range;
4871    },
4872
4873    createRange : function () {
4874        return this.W3CRange ? this.doc.createRange() : this.doc.body.createTextRange();
4875    },
4876
4877    rangeCollapsed : function (range) {
4878        return this.W3CRange ?
4879            range.collapsed :
4880                (!this.undefined(range.text) && range.text.length === 0 && range.boundingWidth === 0);
4881    },
4882
4883    getRangeElement : function (range) {
4884        return this.W3CRange ? this.getW3CRangeElement(range) : this.getIeRangeElement(range);
4885    },
4886
4887    getIeRangeElement : function (range) {
4888        var sType = this.getSelectionType(),
4889            node;
4890
4891        if (!range) {
4892            range = this.createRange();
4893        }
4894
4895        switch (sType) {
4896            case GB.selection.text :
4897                node = range.parentElement();
4898                break;
4899            case GB.selection.element :
4900                node = range.item(0);
4901                break;
4902            case GB.selection.none :
4903                if (!this.undefined(range.parentElement)) {
4904                    node = range.parentElement();
4905                } else {
4906                    node = range.item(0);
4907                }
4908        }
4909        return node;
4910    },
4911
4912    getW3CRangeElement : function (range) {
4913        var ancestorContainer = range.commonAncestorContainer,
4914            startContainer = range.startContainer,
4915            startOffset = range.startOffset,
4916            endContainer = range.endContainer,
4917            endOffset = range.endOffset,
4918            docFragment = null, node = startContainer;
4919
4920        if (GB.browser.msie || GB.browser.edge) {
4921            if (!range.collapsed && ancestorContainer.nodeType === GB.node.element) {
4922                if (ancestorContainer === endContainer) {
4923                    node = ancestorContainer.childNodes[endOffset - 1];
4924                } else if (ancestorContainer === startContainer) {
4925                    node = ancestorContainer.childNodes[startOffset];
4926                } else {
4927                    docFragment = range.cloneContents();
4928                    node = (docFragment.childNodes.length === 1) ? startContainer.nextSibling : ancestorContainer;
4929                }
4930            }
4931        } else {
4932            if (!range.collapsed
4933                && startContainer.nodeType === GB.node.element
4934                && startContainer === endContainer
4935                && endOffset - startOffset === 1
4936                && startContainer.hasChildNodes())
4937            {
4938                node = startContainer.childNodes[startOffset];
4939            }
4940        }
4941
4942        if (node.nodeType === GB.node.text) {
4943            node = node.parentNode;
4944        }
4945        return node;
4946    },
4947
4948    getSelectionType : function () {
4949        var selection = this.getSelection(), type;
4950
4951        if (this.W3CRange) {
4952            if (!selection) {
4953                type = GB.selection.none;
4954            } else if (selection.rangeCount && !selection.isCollapsed && !selection.toString()) {
4955                type = GB.selection.element;
4956            } else {
4957                type = GB.selection.text;
4958            }
4959        } else {
4960            switch (selection.type) {
4961                case 'Text' : type = GB.selection.text; break;
4962                case 'Control' : type = GB.selection.element; break;
4963                default : type = GB.selection.none;
4964            }
4965            if (selection.createRange().parentElement) {
4966                type = GB.selection.text;
4967            }
4968        }
4969        return type;
4970    },
4971
4972    windowOpen : function (popupName) {
4973        this.editAreaFocus();
4974        this.boxHideAll();
4975        this.backupRange();
4976        if (!(this.undefined(GB.popupWindow[popupName]))) {
4977            var popup = GB.popupWindow[popupName];
4978            if (popupName === 'ImageUpload' && window.File && window.FileReader && window.FileList && window.Blob) {
4979                popup.tmpl = 'image.html5.html';
4980            }
4981            this.popupWinLoad(popup);
4982        } else {
4983            alert('사용할 수 없는 명령입니다.');
4984        }
4985    },
4986
4987    doCmd : function (cmd, opt) {
4988        var self = this, range = this.range,
4989            i, keyboard = '', command = '', pNode, node, tmpframe, tmpdoc, html, content,
4990            hr, newHr, para, next = null, nNode, tagName, style, id, hRule, nodeType, css, found = false,
4991            isEmpty = false, selectionType, selection, nodeRange,
4992            cleanPaste = function () {
4993                self.editAreaFocus();
4994                var tmpDoc = self.cheditor.tmpdoc;
4995                tmpDoc.execCommand('SelectAll');
4996                tmpDoc.execCommand('Paste');
4997                return self.cleanFromWord(tmpDoc);
4998            },
4999            isTextVisible = function (elem) {
5000                return (!(elem.firstChild.nodeType === GB.node.text && elem.firstChild === elem.lastChild &&
5001                    elem.firstChild.nodeValue === ''));
5002            };
5003
5004        this.editAreaFocus();
5005        this.boxHideAll();
5006
5007        if (!range) {
5008            return;
5009        }
5010
5011        if (cmd === 'NewDocument') {
5012            if (confirm('글 내용이 모두 사라집니다. 계속하시겠습니까?')) {
5013                this.doc.body.innerHTML = '';
5014            }
5015            this.images = [];
5016            this.editImages = {};
5017            this.editAreaFocus();
5018            this.toolbarUpdate();
5019            this.initDefaultParagraphSeparator();
5020            return;
5021        }
5022
5023        if (cmd === 'ClearTag') {
5024            if (confirm('모든 HTML 태그를 삭제합니다. 계속하시겠습니까?\n(P, DIV, BR 태그와 텍스트는 삭제하지 않습니다.)')) {
5025                content = this.doc.body.innerHTML;
5026                this.doc.body.innerHTML = content.replace(/<(\/?)([^>]*)>/g,
5027                        function (a, b, c) {
5028                            var el = c.toLowerCase().split(/ /)[0];
5029                            if (el !== 'p' && el !== 'div' && el !== 'br') {
5030                                return '';
5031                            }
5032                            return '<' + b + el + '>';
5033                        });
5034            }
5035            this.editAreaFocus();
5036            this.toolbarUpdate();
5037            return;
5038        }
5039
5040        if (cmd === 'Print') {
5041            this.editArea.print();
5042            return;
5043        }
5044
5045        if (cmd === 'PageBreak') {
5046            this.printPageBreak();
5047            this.editAreaFocus();
5048            return;
5049        }
5050
5051        selectionType = this.getSelectionType();
5052        if (this.W3CRange || selectionType === GB.selection.none) {
5053            range = this.doc;
5054        }
5055
5056        if (!GB.browser.msie && (cmd === 'Cut' || cmd === 'Copy' || cmd === 'Paste')) {
5057            if ((range.execCommand(cmd, false, opt)) !== true) {
5058                switch (cmd) {
5059                    case 'Cut'  : keyboard = 'x'; command = '자르기'; break;
5060                    case 'Copy' : keyboard = 'c'; command = '복사'; break;
5061                    case 'Paste': keyboard = 'v'; command = '붙이기'; break;
5062                }
5063                alert('사용하고 계신 브라우저는 보안 상의 이유로 \'' + command + '\' 명령을 사용하실 수 없습니다. \n\n' +
5064                '키보드 단축키를 이용하여 주십시오.\n단축키: Windows: Ctrl+' + keyboard + ', Mac OS X: Command+' + keyboard);
5065                this.editAreaFocus();
5066
5067            }
5068            return;
5069        }
5070
5071        try {
5072            if (cmd === 'PasteFromWord') {
5073                if (this.undefined(this.cheditor.tmpdoc)) {
5074                    tmpframe = this.doc.createElement('iframe');
5075                    tmpframe.setAttribute('contentEditable', 'true');
5076                    tmpframe.style.visibility = 'hidden';
5077                    tmpframe.style.height = tmpframe.style.width = '0px';
5078                    tmpframe.setAttribute('frameBorder', '0');
5079                    this.cheditor.editWrapper.appendChild(tmpframe);
5080
5081                    tmpdoc = tmpframe.contentWindow.document;
5082                    tmpdoc.designMode = 'On';
5083                    tmpdoc.open();
5084                    tmpdoc.close();
5085                    this.cheditor.tmpdoc = tmpdoc;
5086                }
5087
5088                if (this.W3CRange) {
5089                    html = cleanPaste();
5090                    // range = this.restoreRange();
5091                    this.insertNodeAtSelection(html);
5092                } else {
5093                    range = this.getRange();
5094                    range.pasteHTML(cleanPaste());
5095                    range.select();
5096                }
5097            } else if (cmd === 'Paste') {
5098                this.cheditor.paste = 'text';
5099                this.handlePaste(null);
5100                this.cheditor.paste = 'html';
5101            } else if (cmd === 'InsertHorizontalRule') {
5102                hr = this.doc.createElement('hr');
5103                hr.style.height = '1px';
5104                hr.style.backgroundColor = '#999';
5105                hr.style.border = 'none';
5106
5107                this.unselectionElement(hr);
5108                range = this.getRange();
5109
5110                if (this.W3CRange) {
5111                    range.insertNode(hr);
5112                } else {
5113                    nodeType = this.getSelectionType();
5114                    id = this.makeRandomString();
5115                    range.execCommand('InsertHorizontalRule', false, id);
5116                    switch (nodeType) {
5117                    case GB.selection.none :
5118                    case GB.selection.text :
5119                        node = range.parentElement();
5120                        break;
5121                    case GB.selection.element :
5122                        node = range.item(0);
5123                        break;
5124                    default :
5125                        return;
5126                }
5127                    newHr = this.$(id);
5128                    newHr.parentNode.replaceChild(hr, newHr);
5129                }
5130
5131                hRule = hr;
5132                pNode = hRule.parentNode;
5133                para = this.makeSpacerElement();
5134
5135                while (pNode && GB.textFormatTags[pNode.nodeName.toLowerCase()]) {
5136                    pNode = pNode.parentNode;
5137                }
5138
5139                tagName = pNode.tagName.toLowerCase();
5140                if (GB.textFormatBlockTags[tagName]) {
5141                    if (hr.nextSibling) {
5142                        next = this.doc.createElement(tagName);
5143                        pNode.parentNode.insertBefore(next, pNode.nextSibling);
5144                        while (hr.nextSibling) {
5145                            if (hr.nextSibling.nodeType === GB.node.text && hr.nextSibling.nodeValue === '') {
5146                                hr = hr.nextSibling;
5147                                continue;
5148                            }
5149                            if (hr.nextSibling.parentNode !== pNode) {
5150                                node =  hr.nextSibling.parentNode;
5151                                while (node !== pNode && GB.textFormatTags[node.nodeName.toLowerCase()]) {
5152                                    nNode = this.doc.createElement(node.nodeName);
5153                                    style = this.getCssValue(node);
5154                                    if (style) {
5155                                        for (i = 0; i < style.length; i++) {
5156                                            nNode.style[style[i].name] = style[i].value;
5157                                        }
5158                                    }
5159                                    if (next.hasChildNodes() === false) {
5160                                        next.appendChild(nNode);
5161                                        while (hr.nextSibling) {
5162                                            nNode.appendChild(hr.nextSibling);
5163                                        }
5164                                    } else {
5165                                        next.appendChild(nNode);
5166                                        nNode.appendChild(next.firstChild);
5167                                    }
5168                                    node = node.parentNode;
5169                                }
5170                            } else {
5171                                next.appendChild(hr.nextSibling);
5172                            }
5173                        }
5174                    }
5175                    node = hr.parentNode;
5176                    pNode.parentNode.insertBefore(hRule, pNode.nextSibling);
5177
5178                    while (node && node !== pNode) {
5179                        if (node.hasChildNodes() === false || (isTextVisible(node)) === false) {
5180                            nNode = node.parentNode;
5181                            node.parentNode.removeChild(node);
5182                            node = nNode;
5183                            continue;
5184                        }
5185                        node = node.parentNode;
5186                    }
5187
5188                    if (pNode.hasChildNodes() === false || (isTextVisible(pNode)) === false) {
5189                        pNode.parentNode.replaceChild(para.cloneNode(true), pNode);
5190                    }
5191                    if (next === null || next.hasChildNodes() === false) {
5192                        hRule.parentNode.insertBefore(para.cloneNode(true), hRule.nextSibling);
5193                    }
5194
5195                    node = hRule.nextSibling;
5196                    while (node.firstChild) {
5197                        node = node.firstChild;
5198                    }
5199                    if (node && node.nodeType !== GB.node.text) {
5200                        node = node.parentNode;
5201                    }
5202                    this.placeCaretAt(this.W3CRange ? node : hRule.nextSibling, true);
5203                } else {
5204                    if (!hRule.previousSibling) {
5205                        hRule.parentNode.insertBefore(para.cloneNode(true), hRule);
5206                    }
5207                    if (!hRule.nextSibling) {
5208                        hRule.parentNode.insertBefore(para.cloneNode(true), hRule.nextSibling);
5209                    }
5210                    this.placeCaretAt(hRule.nextSibling, hRule.nextSibling.nodeType === GB.node.text);
5211                }
5212            } else {
5213                switch (cmd) {
5214                    case 'JustifyLeft' :
5215                    case 'JustifyCenter' :
5216                    case 'JustifyRight' :
5217                    case 'JustifyFull' :
5218                        pNode = this.getRangeElement(this.range);
5219                        node = null;
5220
5221                        if (GB.offElementTags[pNode.nodeName.toLowerCase()]) {
5222                            nodeRange = this.createRange();
5223                            selection = this.clearSelection();
5224                            if (this.W3CRange) {
5225                                nodeRange.selectNode(pNode);
5226                                selection.addRange(nodeRange);
5227                            } else {
5228                                nodeRange.moveToElementText(pNode);
5229                                nodeRange.select();
5230                                range = nodeRange;
5231                            }
5232                        }
5233                        // Caption
5234                        if (pNode.nodeName.toLowerCase() === 'img') {
5235                            if (pNode.parentNode.nodeName.toLowerCase() === 'figure') {
5236                                node = pNode.parentNode;
5237                                if (node.parentNode.nodeName.toLowerCase() === 'div') {
5238                                    node = node.parentNode;
5239                                    node.style.textAlign = GB.textAlign[cmd];
5240                                    break;
5241                                }
5242                            }
5243                        } else if (pNode.nodeName.toLowerCase() === 'figure') {
5244                            node = pNode.parentNode;
5245                            if (node.nodeName.toLowerCase() === 'div') {
5246                                node.style.textAlign = GB.textAlign[cmd];
5247                                break;
5248                            }
5249                        }
5250
5251                        do {
5252                            if (pNode.nodeName.toLowerCase() === 'li') {
5253                                node = pNode;
5254                                break;
5255                            }
5256                            pNode = pNode.parentNode;
5257                        } while (pNode && pNode.nodeName.toLowerCase() !== 'body');
5258
5259
5260                        if (node) {
5261                            node.style.textAlign = GB.textAlign[cmd];
5262                            break;
5263                        }
5264
5265                        range.execCommand(cmd, false, opt);
5266                        pNode = this.getRangeElement(this.W3CRange ? this.getRange() : range);
5267
5268                        while (pNode && pNode.nodeName.toLowerCase() !== 'body') {
5269                            if (typeof pNode.getAttribute !== 'undefined' && pNode.getAttribute('align')) {
5270                                node = pNode;
5271                                break;
5272                            } else {
5273                                css = this.getCssValue(pNode);
5274                                if (css) {
5275                                    for (i = 0; i < css.length; i++) {
5276                                        if (css[i].name === 'text-align') {
5277                                            node = pNode;
5278                                            break;
5279                                        }
5280                                    }
5281                                }
5282                            }
5283                            pNode = pNode.parentNode;
5284                        }
5285
5286                        if (node) {
5287                            pNode.style.textAlign = GB.textAlign[cmd];
5288                            pNode.removeAttribute('align');
5289                            break;
5290                        }
5291                        break;
5292                    case 'InsertOrderedList' :
5293                    case 'InsertUnOrderedList' :
5294                        range.execCommand(cmd, false, opt);
5295                        if (this.W3CRange) {
5296                            range = this.getRange();
5297                            node = range.commonAncestorContainer;
5298                            if (node.nodeType === GB.node.element && node.lastChild &&
5299                                    node.lastChild.nodeName.toLowerCase() === 'br') {
5300                                node.lastChild.className = this.cheditor.bogusSpacerName;
5301                                isEmpty = true;
5302                            }
5303                            found = false;
5304                            while (node) {
5305                                if (node.nodeName.toLowerCase() === 'ul' || node.nodeName.toLowerCase() === 'ol') {
5306                                    found = true;
5307                                    break;
5308                                }
5309                                node = node.parentNode;
5310                            }
5311                            if (found) {
5312                                node.style.listStyleType = '';
5313                                if (!GB.browser.msie) {
5314                                    if (node.parentNode.nodeName.toLowerCase() === 'p' ||
5315                                            node.parentNode.nodeName.toLowerCase() === 'div') {
5316                                        pNode = node.parentNode;
5317                                        if (pNode.lastChild && pNode.lastChild.nodeName.toLowerCase() === 'br') {
5318                                            pNode.removeChild(pNode.lastChild);
5319                                        }
5320                                        if (pNode.firstChild === node && pNode.lastChild === node) {
5321                                            pNode.parentNode.insertBefore(node, pNode);
5322                                            pNode.parentNode.removeChild(pNode);
5323                                            this.placeCaretAt(node.lastChild, isEmpty);
5324                                        }
5325                                    }
5326                                }
5327                            }
5328                        }
5329                        break;
5330                    default :
5331                        if (range.queryCommandSupported(cmd)) {
5332                            range.execCommand(cmd, false, opt);
5333                        }
5334                }
5335            }
5336        } catch (e) {
5337            alert(cmd + ': 지원되지 않는 명령입니다. ' + e.toString());
5338        }
5339
5340        this.toolbarUpdate();
5341    },
5342
5343    cleanFromWord : function (tmpDoc) {
5344        var doc = tmpDoc.body.innerHTML;
5345        doc = doc.replace(/MsoNormal/g, '');        doc = doc.replace(/<\\?\?xml[^>]*>/g, '');  doc = doc.replace(/<\/?o:p[^>]*>/g, '');
5346        doc = doc.replace(/<\/?v:[^>]*>/g, '');     doc = doc.replace(/<\/?o:[^>]*>/g, '');     doc = doc.replace(/<\/?st1:[^>]*>/g, '');
5347        doc = doc.replace(/<!--(.*)-->/g, '');      doc = doc.replace(/<!--(.*)>/g, '');        doc = doc.replace(/<!(.*)-->/g, '');
5348        doc = doc.replace(/<\\?\?xml[^>]*>/g, '');  doc = doc.replace(/<\/?o:p[^>]*>/g, '');    doc = doc.replace(/<\/?v:[^>]*>/g, '');
5349        doc = doc.replace(/<\/?o:[^>]*>/g, '');     doc = doc.replace(/<\/?st1:[^>]*>/g, '');   //doc = doc.replace(/lang=.?[^' >]*/ig, '');
5350        doc = doc.replace(/type=.?[^' >]*/g, '');   doc = doc.replace(/href='#[^']*'/g, '');    doc = doc.replace(/href='#[^']*'/g, '');
5351        doc = doc.replace(/name=.?[^' >]*/g, '');   doc = doc.replace(/ clear='all'/g, '');     doc = doc.replace(/id='[^']*'/g, '');
5352        doc = doc.replace(/title='[^']*'/g, '');    doc = doc.replace(/\n/g, '');               doc = doc.replace(/\r/g, '');
5353        doc = doc.replace(/mso\-[^'>;]*/g, '');     doc = doc.replace(/<p[^>]*/ig, '<p');       doc = doc.replace(/windowtext/ig, '#000000');
5354        doc = doc.replace(/class=table/ig, '');     doc = doc.replace(/<span[^>]*<\/span>/ig, '');
5355        return doc;
5356    },
5357
5358    printPageBreak : function () {
5359        var hr = document.createElement('hr'),
5360            div = this.doc.createElement('div');
5361        hr.style.pageBreakAfter = 'always';
5362        hr.style.border = '1px #999 dotted';
5363        this.insertHTML(hr);
5364        div.appendChild(this.doc.createTextNode('\u00a0'));
5365        this.insertHTML(div);
5366    },
5367
5368    doCmdPaste : function (html) {
5369        var range = null;
5370        this.editAreaFocus();
5371        if (!this.W3CRange) {
5372            if (this.range.item) {
5373                range = this.doc.body.createTextRange();
5374                if (range) {
5375                    range.moveToElementText(this.range.item(0));
5376                    range.select();
5377                    this.range.item(0).outerHTML = html;
5378                }
5379                this.toolbarUpdate();
5380            } else {
5381                this.range.pasteHTML(html);
5382                this.range.select();
5383            }
5384        } else {
5385            this.insertNodeAtSelection(html);
5386        }
5387    },
5388
5389    getPreviousLeaf : function (node) {
5390        var leaf;
5391        while (!node.previousSibling) {
5392            node = node.parentNode;
5393            if (!node) {
5394                return node;
5395            }
5396        }
5397        leaf = node.previousSibling;
5398        while (leaf.lastChild) {
5399            leaf = leaf.lastChild;
5400        }
5401        return leaf;
5402    },
5403
5404    getNextLeaf : function (node, breakNode) {
5405        var leaf;
5406        while (!node.nextSibling) {
5407            node = node.parentNode;
5408            if ((breakNode && breakNode === node) || !node) {
5409                return node;
5410            }
5411        }
5412        leaf = node.nextSibling;
5413        if (breakNode && leaf === breakNode) {
5414            return node;
5415        }
5416        while (leaf.firstChild) {
5417            leaf = leaf.firstChild;
5418        }
5419        return leaf;
5420    },
5421
5422    isTextVisible : function (text) {
5423        var i, found = false, len = text.length;
5424        for (i = 0; i < len; i++) {
5425            if (text.charAt(i) !== ' ' && text.charAt(i) !== '\t' && text.charAt(i) !== '\r' && text.charAt(i) !== '\n') {
5426                found = true;
5427                break;
5428            }
5429        }
5430        return found;
5431    },
5432
5433    checkCssValue : function (elem, prop) {
5434        var css = this.getCssValue(elem), i;
5435        if (!css) {
5436            return null;
5437        }
5438        for (i = 0; i < css.length; i++) {
5439            if (css[i].name === prop) {
5440                return css[i];
5441            }
5442        }
5443        return null;
5444    },
5445
5446    getCssValue : function (elem) {
5447        var i, q, style = [], len, css;
5448
5449        css = elem.getAttribute('style');
5450        if (!css) {
5451            return null;
5452        }
5453        if (typeof css === 'object') {
5454            css = css.cssText;
5455        }
5456        if (this.trimSpace(css) === '') {
5457            return null;
5458        }
5459
5460        css = css.replace(/;$/, '').split(';');
5461        len = css.length;
5462
5463        for (i = 0; i < len; i++) {
5464            q = css[i].split(':');
5465            style.push({'name': this.trimSpace(q[0]).toLowerCase(), 'value': this.trimSpace(q[1]).toLowerCase()});
5466        }
5467        return style;
5468    },
5469
5470    makeFontCss : function (cmd, opt, elem) {
5471        switch (cmd) {
5472            case 'font-size' : elem.style.fontSize = opt; break;
5473            case 'font-family' : elem.style.fontFamily = opt; break;
5474            case 'color': elem.style.color = opt; break;
5475            case 'background-color': elem.style.backgroundColor = opt; break;
5476        }
5477    },
5478
5479    insertStartEndNode : function (range) {
5480        var startNode = this.doc.createElement('span'),
5481            startRange, endRange, endNode, collapsed, node = null;
5482
5483        startNode.id = 'startNode';
5484
5485        if (!this.W3CRange) {
5486            startNode.appendChild(this.doc.createTextNode('\u200b'));
5487            try {
5488                endRange = range.duplicate();
5489                startRange = range.duplicate();
5490                endRange.collapse(false);
5491                startRange.collapse(true);
5492            } catch (e) {
5493                node = this.getRangeElement(range);
5494                if (node.nodeType === GB.node.element) {
5495
5496                } else {
5497                    return null;
5498                }
5499            }
5500
5501            endNode = startNode.cloneNode(true);
5502            endNode.id = 'endNode';
5503
5504            if (node) {
5505                node.parentNode.insertBefore(startNode, node);
5506                node.parentNode.insertBefore(endNode, node.nextSibling);
5507                collapsed = false;
5508            } else {
5509                collapsed = startRange.isEqual(endRange);
5510                endRange.pasteHTML(endNode.outerHTML);
5511                endRange.moveStart('character', -1);
5512                endNode = endRange.parentElement();
5513
5514                if (collapsed || range.text.length === 0) {
5515                    endNode.parentNode.insertBefore(startNode, endNode);
5516                } else {
5517                    startNode = endNode.cloneNode(true);
5518                    startNode.id = 'startNode';
5519                    startRange.pasteHTML(startNode.outerHTML);
5520                    startRange.moveStart('character', -1);
5521                    startNode = startRange.parentElement();
5522                }
5523            }
5524            endRange = null;
5525            startRange = null;
5526        } else {
5527            endRange = range.cloneRange();
5528            startRange = range.cloneRange();
5529            startRange.collapse(true);
5530
5531            endRange.collapse(false);
5532            endNode = startNode.cloneNode(false);
5533            endNode.id = 'endNode';
5534
5535            collapsed = range.collapsed;
5536            if (collapsed) {
5537                endRange.insertNode(endNode);
5538                endNode.parentNode.insertBefore(startNode, endNode);
5539            } else {
5540                endRange.insertNode(endNode);
5541                startRange.insertNode(startNode);
5542            }
5543
5544            if (startNode.previousSibling && startNode.previousSibling.nodeType === GB.node.text &&
5545                startNode.previousSibling.nodeValue === '') {
5546                startNode.previousSibling.parentNode.removeChild(startNode.previousSibling);
5547            }
5548            if (endNode.nextSibling && endNode.nextSibling.nodeType === GB.node.text &&
5549                endNode.nextSibling.nodeValue === '') {
5550                endNode.nextSibling.parentNode.removeChild(endNode.nextSibling);
5551            }
5552            startRange.detach(); endRange.detach();
5553            endRange = null; startRange = null;
5554        }
5555        return {startNode: startNode, endNode: endNode, collapsed: collapsed};
5556    },
5557
5558    removeStartEndNode : function (nodes) {
5559        if (nodes.startNode) {
5560            nodes.startNode.parentNode.removeChild(nodes.startNode);
5561        }
5562        if (nodes.endNode) {
5563            nodes.endNode.parentNode.removeChild(nodes.endNode);
5564        }
5565    },
5566
5567    clearCss : function (node, name) {
5568        var i, css, styles = [];
5569
5570        if (!node || node.nodeType !== GB.node.element) {
5571            return null;
5572        }
5573
5574        css = this.getCssValue(node);
5575        if (!css) {
5576            return null;
5577        }
5578
5579        node.removeAttribute('style');
5580        for (i = 0; i < css.length; i++) {
5581            if (css[i].name !== name) {
5582                node.style[css[i].name] = css[i].value;
5583                styles.push(css[i]);
5584            }
5585        }
5586
5587        return styles.length ? styles : null;
5588    },
5589
5590    doCmdPopup : function (cmd, opt, checked) {
5591        var self = this,
5592            range, cursor, selectionType, pNode, node, found, isEmpty, span, endNode, startNode, i, endNodeAncestorRange,
5593            startNodeRange, endNodeRange, compare, tNode, len, selection, child, css, tempNodes, endNodeAncestor,
5594            backupRange, removeNodes = [], spanNodes = [], applyTextNodes = [], tailNodes = [], headNodes = [], rootNode = null,
5595            zeroWidth = this.doc.createTextNode('\u200b'), inRange,
5596
5597            makeSpanText = function (elem, ancestor) {
5598                if (self.undefined(ancestor)) {
5599                    ancestor = elem.parentNode;
5600                }
5601                span = self.doc.createElement('span');
5602                self.makeFontCss(cmd, opt, span);
5603                ancestor.insertBefore(span, elem);
5604                span.appendChild(elem);
5605                spanNodes.push(span);
5606                return span;
5607            },
5608            searchTextNode = function (node, match) {
5609                var i = 0, len = node.childNodes.length;
5610                for (; i < len; i++) {
5611                    child = node.childNodes[i];
5612                    match = searchTextNode(child, match);
5613                    if (child === startNode) {
5614                        break;
5615                    }
5616                    if (child.nodeType === GB.node.text) {
5617                        match = true;
5618                        break;
5619                    }
5620                    if (child.nodeType === GB.node.element && child.hasChildNodes() === false &&
5621                        GB.textFormatTags[child.nodeName.toLowerCase()]) {
5622                        removeNodes.push(child);
5623                    }
5624                }
5625                return match;
5626            },
5627            compareBoundaryPoints = function (range, type, source) {
5628                var values = {
5629                    'StartToStart': 0,  //Range.START_TO_START,
5630                    'StartToEnd': 1,    //Range.START_TO_END,
5631                    'EndToEnd': 2,      //Range.END_TO_END,
5632                    'EndToStart': 3     //Range.END_TO_START
5633                };
5634
5635                if (self.W3CRange) {
5636                    return range.compareBoundaryPoints(values[type], source);
5637                }
5638
5639                type = type === 'StartToEnd' ? 'EndToStart' : (type === 'EndToStart' ? 'StartToEnd' : type);
5640                return range.compareEndPoints(type, source);
5641            },
5642            rangeSelectNode = function (range, node) {
5643                if (self.W3CRange) {
5644                    range.selectNode(node);
5645                } else {
5646                    if (node.nodeType === GB.node.text) {
5647                        node = node.parentNode;
5648                    }
5649                    range.moveToElementText(node);
5650                }
5651            },
5652            clearPreviousLeaf = function (node) {
5653                var leaf, css = [];
5654                while (!node.previousSibling) {
5655                    node = node.parentNode;
5656                    if (!node || node.nodeName.toLowerCase() === 'body') {
5657                        return null;
5658                    }
5659                }
5660
5661                leaf = node.previousSibling;
5662
5663                while (leaf.lastChild && leaf.nodeType === GB.node.element && leaf !== startNode) {
5664                    rangeSelectNode(cursor, leaf);
5665                    compare = compareBoundaryPoints(cursor, 'StartToStart', startNodeRange);
5666                    if (compare === 1) {
5667                        css = self.clearCss(leaf, cmd);
5668                        if (!css && (leaf.nodeName.toLowerCase() === 'span' || leaf.nodeName.toLowerCase() === 'font')) {
5669                            while (leaf.firstChild) {
5670                                leaf.parentNode.insertBefore(leaf.firstChild, leaf);
5671                            }
5672                            removeNodes.push(leaf);
5673                            break;
5674                        }
5675                    } else if (compare === 0) {
5676                        self.clearCss(leaf, cmd);
5677                        if (!rootNode && leaf.nodeName.toLowerCase() === 'span') {
5678                            rootNode = leaf;
5679                        }
5680                    } else { // -1
5681                        node = startNode;
5682                        found = false;
5683                        while (node) {
5684                            if (node.nodeType === GB.node.text) {
5685                                found = true;
5686                                break;
5687                            }
5688                            node = checkPreviousLeaf(node, leaf);
5689                        }
5690                        if (!found) {
5691                            self.clearCss(leaf, cmd);
5692                            if (!rootNode && leaf.nodeName.toLowerCase() === 'span') {
5693                                rootNode = leaf;
5694                            }
5695                        }
5696                    }
5697
5698                    leaf = leaf.lastChild;
5699                }
5700
5701                if (leaf.nodeType === GB.node.text && self.isTextVisible(leaf.nodeValue)) {
5702                    applyTextNodes.push(leaf);
5703                }
5704
5705                return leaf;
5706            },
5707            checkPreviousLeaf = function (node, breakNode) {
5708                var leaf;
5709                while (!node.previousSibling) {
5710                    node = node.parentNode;
5711                    if (node === breakNode || node.nodeName.toLowerCase() === 'body') {
5712                        return null;
5713                    }
5714                }
5715                leaf = node.previousSibling;
5716                while (leaf.lastChild) {
5717                    leaf = leaf.lastChild;
5718                }
5719                return leaf;
5720            },
5721            checkInRange = function (range, source) {
5722                return (typeof range.inRange !== 'undefined') ? range.inRange(source) :
5723                    (compareBoundaryPoints(range, 'StartToStart', source) < 1
5724                        && compareBoundaryPoints(range, 'EndToEnd', source) > -1);
5725            },
5726            checkNextLeaf = function (node) {
5727                var leaf, inRange;
5728                while (!node.nextSibling) {
5729                    node = node.parentNode;
5730
5731                    if (!node || node.nodeName.toLowerCase() === 'body') {
5732                        return null;
5733                    }
5734
5735                    rangeSelectNode(cursor, node);
5736                    inRange = checkInRange(cursor, endNodeRange);
5737                    if (inRange) {
5738                        inRange = checkInRange(cursor, startNodeRange);
5739                        if (!inRange) {
5740                            tailNodes.push(node);
5741                        } else {
5742                            headNodes.push(node);
5743                        }
5744                    }
5745
5746                    if (node === endNodeAncestor) {
5747                        return null;
5748                    }
5749                }
5750
5751                leaf = node.nextSibling;
5752                if (leaf.nodeType === GB.node.text || !endNodeAncestor) {
5753                    return null;
5754                }
5755
5756                rangeSelectNode(cursor, leaf);
5757                inRange = checkInRange(endNodeAncestorRange, cursor);
5758                if (!inRange) {
5759                    return null;
5760                }
5761
5762                while (leaf.firstChild) {
5763                    leaf = leaf.firstChild;
5764                }
5765
5766                if (leaf.nodeType === GB.node.text) {
5767                    tailNodes = [];
5768                    return null;
5769                }
5770                return leaf;
5771            },
5772            checkParentSpan = function (node) {
5773                var len = spanNodes.length, i = 0;
5774                for (; i < len; i++) {
5775                    if (spanNodes[i] === node) {
5776                        return true;
5777                    }
5778                }
5779                return false;
5780            };
5781
5782        this.editAreaFocus();
5783
5784        backupRange = this.restoreRange();
5785        selectionType = this.getSelectionType();
5786
5787        if (this.W3CRange) {
5788            range = this.doc;
5789        } else {
5790            range = (selectionType === GB.selection.none) ? this.doc : backupRange;
5791        }
5792
5793        try {
5794            if (cmd === 'LineHeight') {
5795                this.applyLineHeight(opt);
5796            } else {
5797                if (cmd === 'InsertOrderedList' || cmd === 'InsertUnOrderedList') {
5798                    if (checked !== true) {
5799                        range.execCommand(cmd, false, opt);
5800                        if (!GB.browser.msie) {
5801                            range = this.getRange();
5802                            node = range.commonAncestorContainer;
5803                            found = isEmpty = false;
5804
5805                            if (node.nodeType === GB.node.element && node.lastChild &&
5806                                    node.lastChild.nodeName.toLowerCase() === 'br') {
5807                                node.lastChild.className = this.cheditor.bogusSpacerName;
5808                                isEmpty = true;
5809                            }
5810                            while (node) {
5811                                if (node.nodeName.toLowerCase() === 'ul' || node.nodeName.toLowerCase() === 'ol') {
5812                                    found = true;
5813                                    break;
5814                                }
5815                                node = node.parentNode;
5816                            }
5817
5818                            if (found) {
5819                                if (node.parentNode.nodeName.toLowerCase() === 'p' ||
5820                                        node.parentNode.nodeName.toLowerCase() === 'div') {
5821                                    pNode = node.parentNode;
5822                                    if (pNode.lastChild && pNode.lastChild.nodeName.toLowerCase() === 'br') {
5823                                        pNode.removeChild(pNode.lastChild);
5824                                    }
5825                                    if (pNode.firstChild === node && pNode.lastChild === node) {
5826                                        pNode.parentNode.insertBefore(node, pNode);
5827                                        pNode.parentNode.removeChild(pNode);
5828                                        this.placeCaretAt(node.lastChild, isEmpty);
5829                                    }
5830                                }
5831                            }
5832                        }
5833                    }
5834                    cursor = this.getRange();
5835                    pNode = this.W3CRange ? cursor.commonAncestorContainer : cursor.parentElement();
5836                    if (pNode.nodeType === GB.node.text) {
5837                        pNode = pNode.parentNode;
5838                    }
5839                    while (pNode) {
5840                        if (pNode.nodeName.toLowerCase() === 'ol' || pNode.nodeName.toLowerCase() === 'ul') {
5841                            if (opt === 'desc' || opt === 'decimal') {
5842                                opt = '';
5843                            }
5844                            pNode.style.listStyleType = opt;
5845                            break;
5846                        }
5847                        pNode = pNode.parentNode;
5848                    }
5849                } else if (cmd === 'FontSize' || cmd === 'FontName' || cmd === 'ForeColor' || cmd === 'BackColor') {
5850                    if (cmd === 'ForeColor' || cmd === 'BackColor') {
5851                        opt = this.colorConvert(opt, 'hex');
5852                    } else if (cmd === 'FontName' && opt === '맑은 고딕') {
5853                        opt += ', "Malgun Gothic"';
5854                    }
5855
5856                    cmd = GB.fontStyle[cmd];
5857
5858                    range = this.getRange();
5859                    tempNodes = this.insertStartEndNode(range);
5860                    startNode = tempNodes.startNode;
5861                    endNode = tempNodes.endNode;
5862
5863                    cursor = this.createRange();
5864                    startNodeRange = this.createRange();
5865                    rangeSelectNode(startNodeRange, startNode);
5866
5867                    endNodeRange = this.createRange();
5868                    endNodeAncestorRange = this.createRange();
5869
5870                    if (!tempNodes.collapsed) {
5871                        tailNodes = [];
5872                        endNodeAncestor = null;
5873                        rangeSelectNode(endNodeRange, endNode);
5874                        node = endNode.parentNode;
5875
5876                        while (node && node.nodeName.toLowerCase() !== 'body') {
5877                            endNodeAncestor = node;
5878                            node = node.parentNode;
5879                        }
5880
5881                        if (endNodeAncestor) {
5882                            rangeSelectNode(endNodeAncestorRange, endNodeAncestor);
5883                        }
5884
5885                        node = endNode;
5886                        while (node) {
5887                            node = checkNextLeaf(node);
5888                        }
5889
5890                        for (i = 0; i < tailNodes.length; i++) {
5891                            this.clearCss(tailNodes[i], cmd);
5892                        }
5893
5894                        node = endNode;
5895                        while (node && node !== startNode) {
5896                            node = clearPreviousLeaf(node);
5897                        }
5898
5899                        if (headNodes.length) {
5900                            found = false;
5901                            node = startNode;
5902                            while (node) {
5903                                if (node.nodeType === GB.node.text) {
5904                                    found = true;
5905                                    break;
5906                                }
5907                                node = checkPreviousLeaf(node, endNodeAncestor);
5908                            }
5909                            if (!found) {
5910                                for (i = 0; i < headNodes.length; i++) {
5911                                    self.clearCss(headNodes[i], cmd);
5912                                    css = self.getCssValue(headNodes[i]);
5913                                    if (!css && headNodes[i].nodeName.toLowerCase() === 'span') {
5914                                        child = headNodes[i];
5915                                        while (child.firstChild) {
5916                                            child.parentNode.insertBefore(child.firstChild, child);
5917                                        }
5918                                        child.parentNode.removeChild(child);
5919                                        headNodes.splice(i);
5920                                    }
5921                                }
5922                            }
5923                        }
5924
5925                        for (i = 0; i < removeNodes.length; i++) {
5926                            removeNodes[i].parentNode.removeChild(removeNodes[i]);
5927                        }
5928                        removeNodes = [];
5929
5930                        len = applyTextNodes.length;
5931                        if (rootNode) {
5932                            rangeSelectNode(startNodeRange, rootNode);
5933                        }
5934
5935                        for (i = 0; i < len; i++) {
5936                            tNode = applyTextNodes[i];
5937
5938                            if (tNode.previousSibling && tNode.previousSibling.nodeType === GB.node.text) {
5939                                if (applyTextNodes[i + 1] && tNode.previousSibling === applyTextNodes[i + 1]) {
5940                                    applyTextNodes[i + 1].nodeValue += tNode.nodeValue;
5941                                    tNode.parentNode.removeChild(tNode);
5942                                } else {
5943                                    tNode.nodeValue = tNode.previousSibling.nodeValue + tNode.nodeValue;
5944                                    tNode.previousSibling.parentNode.removeChild(tNode.previousSibling);
5945                                    i--;
5946                                }
5947                                continue;
5948                            }
5949
5950                            pNode = tNode.parentNode;
5951
5952                            if (rootNode) {
5953                                rangeSelectNode(cursor, pNode);
5954                                inRange = checkInRange(startNodeRange, cursor);
5955                                if (inRange) {
5956                                    self.makeFontCss(cmd, '', pNode);
5957                                    self.makeFontCss(cmd, opt, rootNode);
5958                                    continue;
5959                                }
5960                            }
5961                            if (pNode.nodeName.toLowerCase() === 'span'
5962                                && (pNode.firstChild === tNode  || pNode.firstChild === startNode)
5963                                && (pNode.lastChild === tNode || pNode.lastChild === endNode)) {
5964                                self.makeFontCss(cmd, opt, pNode);
5965                                spanNodes.push(pNode);
5966                                continue;
5967                            }
5968                            makeSpanText(tNode);
5969                        }
5970
5971                        len = spanNodes.length;
5972                        for (i = 0; i < len; i++) {
5973                            child = spanNodes[i];
5974                            pNode = child.parentNode;
5975                            if (pNode.nodeName.toLowerCase() === 'span') {
5976                                if (checkParentSpan(pNode)) {
5977                                    self.makeFontCss(cmd, '', child);
5978                                    css = self.getCssValue(child);
5979                                    if (!css) {
5980                                        while (child.firstChild) {
5981                                            pNode.insertBefore(child.firstChild, child);
5982                                        }
5983                                        pNode.removeChild(child);
5984                                        continue;
5985                                    }
5986                                }
5987                                while (pNode && pNode.nodeName.toLowerCase() === 'span') {
5988                                    if (pNode.firstChild === child && pNode.lastChild === child) {
5989                                        css = self.getCssValue(pNode);
5990                                        if (css) {
5991                                            self.makeFontCss(cmd, '', pNode);
5992                                            css = self.getCssValue(pNode);
5993                                            if (!css) {
5994                                                pNode.parentNode.insertBefore(child, pNode);
5995                                                pNode.parentNode.removeChild(pNode);
5996                                                pNode = child;
5997                                                continue;
5998                                            }
5999                                        }
6000                                    }
6001                                    pNode = pNode.parentNode;
6002                                }
6003                            }
6004                        }
6005
6006                        if (this.W3CRange) {
6007                            selection = this.getSelection();
6008                            if (selection.rangeCount > 0) {
6009                                selection.removeAllRanges();
6010                            }
6011                            range = this.createRange();
6012                            range.setStartAfter(startNode);
6013                            range.setEndBefore(endNode);
6014                            selection.addRange(range);
6015                        } else {
6016                            startNodeRange = this.createRange();
6017                            endNodeRange = startNodeRange.duplicate();
6018                            startNodeRange.moveToElementText(startNode);
6019                            endNodeRange.moveToElementText(endNode);
6020                            startNodeRange.setEndPoint('StartToEnd', startNodeRange);
6021                            startNodeRange.setEndPoint('EndToStart', endNodeRange);
6022                            startNodeRange.select();
6023                        }
6024                    } else {
6025                        pNode = startNode.parentNode;
6026                        found = false;
6027                        while (pNode && pNode.nodeName.toLowerCase() === 'span' && !found) {
6028                            css = self.getCssValue(pNode);
6029                            if (css) {
6030                                len = css.length;
6031                                for (i = 0; i < len; i++) {
6032                                    if (css[i].name === cmd && css[i].value === opt) {
6033                                        found = true;
6034                                        break;
6035                                    }
6036                                }
6037                            }
6038                            pNode = pNode.parentNode;
6039                        }
6040
6041                        if (!found) {
6042                            span = this.doc.createElement('span');
6043                            this.makeFontCss(cmd, opt, span);
6044                            span.appendChild(zeroWidth);
6045                            endNode.parentNode.insertBefore(span, endNode);
6046
6047                            if (this.W3CRange) {
6048                                selection = this.getSelection();
6049                                selection.collapse(zeroWidth, 1);
6050                            } else {
6051                                range = this.getRange();
6052                                range.moveToElementText(span);
6053                                range.collapse(false);
6054                                range.select();
6055                            }
6056                        }
6057                    }
6058                    this.removeStartEndNode(tempNodes);
6059                } else {
6060                    range.execCommand(cmd, false, opt);
6061                }
6062            }
6063        } catch (e) {
6064            alert(e.toString());
6065        }
6066
6067        this.toolbarUpdate();
6068        this.boxHideAll();
6069    },
6070
6071    modifyImage : function (img) {
6072        var self = this,
6073            idx, div, ico, inputCaption, wrapTextSpan, wrapTextCheckBox, wrapTextIcon, wrapTextChecked,
6074            width = 0, height = 0, wrapElem, currentCaption = '', caption = null, inputAlt, inputTitle, cssFloat,
6075            wrapperClassName = 'cheditor-caption-wrapper',
6076            figureClassName = 'cheditor-caption',
6077            figCaptionClassName = 'cheditor-caption-text',
6078            imageWidthOpt = {
6079                orig    : { size: 'normal', desc: '원본 크기' },
6080                fitpage : { size: '100%',   desc: '페이지 크기에 맞춤' },
6081                px160   : { size: 160,      desc: '썸네일, 160 픽셀' },
6082                px320   : { size: 320,      desc: '작은 크기, 320 픽셀' },
6083                px640   : { size: 640,      desc: '중간 크기, 640 픽셀' },
6084                px1024  : { size: 1024,     desc: '크게, 1024 픽셀' },
6085                px1600  : { size: 1600,     desc: '아주 크게, 1600 픽셀' }
6086            },
6087            captionAlignOpt = { left: '왼쪽', center: '가운데', right: '오른쪽' },
6088            imageFloatOpt = {
6089                left : {
6090                    value : '왼쪽',
6091                    input : null
6092                },
6093                right : {
6094                    value : '오른쪽',
6095                    input : null
6096                }
6097            },
6098            fmSelectWidth = document.createElement('select'),
6099            fmSelectCaptionAlign = document.createElement('select'),
6100
6101            onChangeEventHandler = function () {
6102                if (self.editImages[img.src] && self.editImages[img.src].width) {
6103                    width = self.editImages[img.src].width;
6104                    if (self.editImages[img.src] && self.editImages[img.src].height) {
6105                        height = self.editImages[img.src].height;
6106                    } else {
6107                        height = img.height;
6108                    }
6109                } else if (img.width) {
6110                    width = img.width;
6111                } else {
6112                    return;
6113                }
6114
6115                switch (this.value) {
6116                    case 'orig' :
6117                        width = width + 'px';
6118                        height = (height || img.height) + 'px';
6119                        break;
6120                    case 'fitpage' :
6121                        width = '100%';
6122                        height = 'auto';
6123                        break;
6124                    default :
6125                        width = imageWidthOpt[this.value].size;
6126                        if (img.height) {
6127                            height = Math.round((img.height * width) / img.width) + 'px';
6128                        }
6129                        width += 'px';
6130                }
6131
6132                if (width) {
6133                    img.style.width = width;
6134                    if (caption && caption.figure) {
6135                        caption.figure.style.width = width;
6136                    }
6137                }
6138                if (height) {
6139                    img.style.height = height;
6140                }
6141            },
6142            setCssFloat = function (elem, css) {
6143                if (typeof elem.style.styleFloat === 'undefined') {
6144                    elem.style.cssFloat = css;
6145                } else {
6146                    elem.style.styleFloat = css;
6147                }
6148            },
6149            getCssFloat = function (elem) {
6150                return (typeof elem.style.styleFloat === 'undefined') ? elem.style.cssFloat : elem.style.styleFloat;
6151            },
6152            clearCssFloat = function (elem) {
6153                setCssFloat(elem, '');
6154                elem.style.marginLeft = '';
6155                elem.style.marginRight = '';
6156            },
6157            createInputForm = function (type, name, value, classname) {
6158                var input = document.createElement('input');
6159                input.setAttribute('type', type);
6160                input.setAttribute('name', name);
6161                input.setAttribute('value', value);
6162                input.className = classname;
6163                return input;
6164            },
6165            applyWrapText = function (elem) {
6166                if (!elem) {
6167                    return;
6168                }
6169                wrapElem = (caption && caption.wrapper) ? caption.wrapper : img;
6170                if (elem.checked) {
6171                    imageFloatOpt[(elem.name === 'left' ? 'right' : 'left')].input.checked = false;
6172                    setCssFloat(wrapElem, elem.name);
6173                    if (elem.name === 'left') {
6174                        wrapElem.style.marginRight = '1em';
6175                        wrapElem.style.marginLeft = '';
6176                    } else {
6177                        wrapElem.style.marginLeft = '1em';
6178                        wrapElem.style.marginRight = '';
6179                    }
6180                    if (caption && caption.wrapper) {
6181                        clearCssFloat(img);
6182                    }
6183                } else {
6184                    clearCssFloat(wrapElem);
6185                }
6186            },
6187            getCaptionNodes = function (img) {
6188                var nodes = { figure: null, figCaption: [], captionText: '', img: null, wrapper: null},
6189                    pNode, node;
6190                pNode = img.parentNode;
6191                if (!pNode || pNode.nodeName.toLowerCase() !== 'figure') {
6192                    return null;
6193                }
6194                nodes.figure = pNode;
6195                nodes.figCaption = pNode.getElementsByTagName('figcaption');
6196                for (idx = 0; idx < nodes.figCaption.length; idx++) {
6197                    node = nodes.figCaption[idx].firstChild;
6198                    while (node) {
6199                        if (node.nodeType === GB.node.text) {
6200                            nodes.captionText += self.trimSpace(node.nodeValue);
6201                        }
6202                        node = node.nextSibling;
6203                    }
6204                }
6205                if (pNode.parentNode.nodeName.toLowerCase() === 'div' && pNode.parentNode.className === wrapperClassName) {
6206                    nodes.wrapper = pNode.parentNode;
6207                }
6208                nodes.img = img;
6209                return nodes;
6210            },
6211            applyAlt = function () {
6212                var alt = self.trimSpace(inputAlt.value);
6213                if (alt !== '') {
6214                    img.setAttribute('alt', alt);
6215                }
6216                self.removeEvent(inputAlt, 'blur', applyAlt);
6217                self.cheditor.modifyState = false;
6218            },
6219            applyTitle = function () {
6220                var title = self.trimSpace(inputTitle.value);
6221                if (title !== '') {
6222                    img.setAttribute('title', title);
6223                }
6224                self.removeEvent(inputTitle, 'blur', applyTitle);
6225                self.cheditor.modifyState = false;
6226            },
6227            applyCaption = function () {
6228                var figure = self.doc.createElement('figure'),
6229                    figCaption = self.doc.createElement('figcaption'),
6230                    wrapper = self.doc.createElement('div'),
6231                    pNode = img.parentNode, i, para = self.doc.createElement('p');
6232
6233                self.removeEvent(inputCaption, 'blur', applyCaption);
6234
6235                wrapper.className = wrapperClassName;
6236                figure.className = figureClassName;
6237                figCaption.className = figCaptionClassName;
6238
6239                this.value = self.trimSpace(inputCaption.value);
6240                if (!self.isTextVisible(this.value) && caption) {
6241                    caption.wrapper.parentNode.insertBefore(para, caption.wrapper);
6242                    para.appendChild(caption.img);
6243                    cssFloat = getCssFloat(caption.wrapper);
6244                    caption.wrapper.parentNode.removeChild(caption.wrapper);
6245                    caption = getCaptionNodes(img);
6246                    if (cssFloat && (cssFloat === 'left' || cssFloat === 'right')) {
6247                        applyWrapText(imageFloatOpt[cssFloat].input);
6248                    }
6249                    self.cheditor.modifyState = false;
6250                    return;
6251                }
6252                if (currentCaption === this.value) {
6253                    self.cheditor.modifyState = false;
6254                    return;
6255                }
6256
6257                if (caption && caption.figure) {
6258                    for (i = 0; i < caption.figCaption.length; i++) {
6259                        caption.figure.removeChild(caption.figCaption[i]);
6260                    }
6261                    figure = caption.figure;
6262                } else {
6263                    if (pNode.nodeName.toLowerCase() !== 'body') {
6264                        pNode.parentNode.insertBefore(wrapper, pNode.nextSibling);
6265                    } else {
6266                        pNode.insertBefore(wrapper, img);
6267                    }
6268
6269                    if (self.config.imgCaptionWrapper !== '') {
6270                        wrapper.setAttribute('style', self.config.imgCaptionWrapper);
6271                    }
6272
6273                    wrapper.appendChild(figure);
6274                    figure.setAttribute('style', self.config.imgCaptionFigure);
6275                    figure.style.display = 'inline-block';
6276                    figure.style.width = img.width;
6277                    figure.appendChild(img);
6278                    para.appendChild(self.createNbspTextNode());
6279                    wrapper.parentNode.insertBefore(para, wrapper.nextSibling);
6280                }
6281
6282                figure.appendChild(figCaption);
6283                figCaption.setAttribute('style', self.config.imgCaptionText);
6284                figCaption.appendChild(self.doc.createTextNode(this.value));
6285
6286                if (!pNode.hasChildNodes()) {
6287                    pNode.parentNode.removeChild(pNode);
6288                }
6289
6290                caption = getCaptionNodes(img);
6291                cssFloat = getCssFloat(img);
6292                if (cssFloat && (cssFloat === 'left' || cssFloat === 'right')) {
6293                    applyWrapText(imageFloatOpt[cssFloat].input);
6294                }
6295                self.cheditor.modifyState = false;
6296            };
6297
6298        for (idx in imageWidthOpt) {
6299            if (imageWidthOpt.hasOwnProperty(idx)) {
6300                fmSelectWidth.options[fmSelectWidth.options.length] = new Option(imageWidthOpt[idx].desc, idx);
6301            }
6302        }
6303
6304        fmSelectWidth.onchange = onChangeEventHandler;
6305        caption = getCaptionNodes(img);
6306
6307        div = document.createElement('div');
6308        div.style.textAlign = 'left';
6309        ico = new Image();
6310        ico.src = this.config.iconPath + 'image_resize.png';
6311        ico.className = 'cheditor-ico';
6312        div.appendChild(ico);
6313        div.appendChild(fmSelectWidth);
6314
6315        wrapTextChecked = getCssFloat((caption && caption.wrapper) ? caption.wrapper : img);
6316
6317        for (idx in imageFloatOpt) {
6318            if (imageFloatOpt.hasOwnProperty(idx)) {
6319                wrapTextCheckBox = createInputForm('checkbox', idx, '1', 'wrap-checked');
6320                wrapTextCheckBox.setAttribute('id', 'idWrapText-' + idx);
6321                wrapTextCheckBox.onclick = function () {
6322                    applyWrapText(this);
6323                };
6324                imageFloatOpt[idx].input = wrapTextCheckBox;
6325                wrapTextSpan = document.createElement('span');
6326                wrapTextIcon = new Image();
6327                wrapTextSpan.className = 'wrap-text-desc';
6328
6329                if (idx === 'left') {
6330                    wrapTextSpan.style.marginLeft = '20px';
6331                }
6332                if (wrapTextChecked === idx) {
6333                    wrapTextCheckBox.checked = 'checked';
6334                }
6335                wrapTextSpan.appendChild(wrapTextCheckBox);
6336                wrapTextIcon.className = 'cheditor-ico';
6337                wrapTextIcon.src = this.config.iconPath + 'image_align_' + idx + '_wt.png';
6338                wrapTextSpan.appendChild(wrapTextIcon);
6339                div.appendChild(wrapTextSpan);
6340            }
6341        }
6342
6343        if (self.undefined(self.editImages[img.src])) {
6344            self.editImages[img.src] = { width: img.width, height: img.he
6344ight };
6345        }
6346
6347        div.appendChild(document.createTextNode('\u00a0\u00a0Alt:'));
6348        inputAlt = createInputForm('text', 'inputAlt', '', 'user-input-alt');
6349        inputAlt.onfocus = function () {
6350            self.cheditor.modifyState = true;
6351            self.addEvent(inputAlt, 'blur', applyAlt);
6352        };
6353        div.appendChild(inputAlt);
6354        if (img.getAttribute('alt')) {
6355            inputAlt.value = img.getAttribute('alt');
6356        }
6357
6358        div.appendChild(document.createTextNode('타이틀:'));
6359        inputTitle = createInputForm('text', 'inputTitle', '', 'user-input-alt');
6360        inputTitle.onfocus = function () {
6361            self.cheditor.modifyState = true;
6362            self.addEvent(inputTitle, 'blur', applyTitle);
6363        };
6364        div.appendChild(inputTitle);
6365        if (img.getAttribute('title')) {
6366            inputTitle.value = img.getAttribute('title');
6367        }
6368
6369        div.appendChild(document.createElement('br'));
6370        div.appendChild(document.createTextNode('사진 캡션:'));
6371
6372        inputCaption = createInputForm('text', 'inputCaption', '', 'user-input-caption');
6373        inputCaption.onfocus = function () {
6374            caption = getCaptionNodes(img);
6375            self.cheditor.modifyState = true;
6376            self.addEvent(inputCaption, 'blur', applyCaption);
6377
6378        };
6379        div.appendChild(inputCaption);
6380
6381        div.appendChild(document.createTextNode('캡션 텍스트 정렬:'));
6382        for (idx in captionAlignOpt) {
6383            if (captionAlignOpt.hasOwnProperty(idx)) {
6384                fmSelectCaptionAlign.options[fmSelectCaptionAlign.options.length] = new Option(captionAlignOpt[idx], idx);
6385                if (caption && caption.figCaption[0] && caption.figCaption[0].style.textAlign) {
6386                    if (idx === caption.figCaption[0].style.textAlign) {
6387                        fmSelectCaptionAlign.options[fmSelectCaptionAlign.options.length - 1].selected = true;
6388                    }
6389                }
6390            }
6391        }
6392
6393        fmSelectCaptionAlign.className = 'caption-align';
6394        fmSelectCaptionAlign.onchange = function () {
6395            caption = getCaptionNodes(img);
6396            if (!caption) {
6397                return;
6398            }
6399            for (idx = 0; idx < caption.figCaption.length; idx++) {
6400                caption.figCaption[idx].style.textAlign = this.value;
6401            }
6402        };
6403        div.appendChild(fmSelectCaptionAlign);
6404
6405        if (caption && caption.captionText) {
6406            currentCaption = self.trimSpace(caption.captionText);
6407            inputCaption.value = currentCaption;
6408        }
6409
6410        while (self.cheditor.editBlock.firstChild) {
6411            self.cheditor.editBlock.removeChild(self.cheditor.editBlock.firstChild);
6412        }
6413        self.cheditor.editBlock.appendChild(div);
6414    },
6415
6416    modifyCell : function (ctd) {
6417        var self = this,
6418            ctb = ctd,
6419            ctr = ctb,
6420            tm = [], i, jr, j, jh, jv, rowIndex = 0, realIndex = 0, newc, newr, nc, tempr, rows, span, icon,
6421            div = document.createElement('div'),
6422
6423            getCellMatrix = function () {
6424                rows = (ctb.rows && ctb.rows.length > 0) ? ctb.rows : ctb.getElementsByTagName('tr');
6425                for (i = 0; i < rows.length; i++) {
6426                    tm[i] = [];
6427                }
6428                for (i = 0; i < rows.length; i++) {
6429                    jr = 0;
6430                    for (j = 0; j < rows[i].cells.length; j++) {
6431                        while (!(self.undefined(tm[i][jr]))) {
6432                            jr++;
6433                        }
6434                        for (jh = jr; jh < jr + (rows[i].cells[j].colSpan || 1); jh++) {
6435                            for (jv = i; jv < i + (rows[i].cells[j].rowSpan || 1); jv++) {
6436                                tm[jv][jh] = (jv === i) ? rows[i].cells[j].cellIndex : -1;
6437                            }
6438                        }
6439                    }
6440                }
6441                return tm;
6442            },
6443            insertColumn = function () {
6444                tm = getCellMatrix();
6445                rows = (ctb.rows && ctb.rows.length > 0) ? ctb.rows : ctb.getElementsByTagName('tr');
6446
6447                if (ctr.rowIndex >= 0) {
6448                    rowIndex = ctr.rowIndex;
6449                } else {
6450                    for (i = 0; i < rows.length; i++) {
6451                        if (rows[i] === ctr) {
6452                            rowIndex = i;
6453                            break;
6454                        }
6455                    }
6456                }
6457
6458                for (j = 0; j < tm[rowIndex].length; j++) {
6459                    if (tm[rowIndex][j] === ctd.cellIndex) {
6460                        realIndex = j;
6461                        break;
6462                    }
6463                }
6464
6465                for (i = 0; i < rows.length; i++) {
6466                    if (tm[i][realIndex] !== -1) {
6467                        if (rows[i].cells[tm[i][realIndex]].colSpan > 1) {
6468                            rows[i].cells[tm[i][realIndex]].colSpan++;
6469                        } else {
6470                            newc = rows[i].insertCell(tm[i][realIndex] + 1);
6471                            nc = rows[i].cells[tm[i][realIndex]].cloneNode(false);
6472                            nc.innerHTML = '&nbsp;';
6473                            rows[i].replaceChild(nc, newc);
6474                        }
6475                    }
6476                }
6477            },
6478            insertRow = function (idx) {
6479                newr = ctb.insertRow(ctr.rowIndex + 1);
6480                for (i = 0; i < ctr.cells.length; i++) {
6481                    if (ctr.cells[i].rowSpan > 1) {
6482                        ctr.cells[i].rowSpan++;
6483                    } else {
6484                        newc = ctr.cells[i].cloneNode(false);
6485                        newc.innerHTML = '&nbsp;';
6486                        newr.appendChild(newc);
6487                    }
6488                }
6489
6490                for (i = 0; i < ctr.rowIndex; i++) {
6491                    if (ctb.rows && ctb.rows.length > 0) {
6492                        tempr = ctb.rows[i];
6493                    } else {
6494                        tempr = ctb.getElementsByTagName('tr')[i];
6495                    }
6496                    for (j = 0; j < tempr.cells.length; j++) {
6497                        if (tempr.cells[j].rowSpan > (ctr.rowIndex - i)) {
6498                            tempr.cells[j].rowSpan++;
6499                        }
6500                    }
6501                }
6502            },
6503            deleteColumn = function () {
6504                tm = getCellMatrix(ctb);
6505                rows = (ctb.rows && ctb.rows.length > 0) ? ctb.rows : ctb.getElementsByTagName('tr');
6506                rowIndex = 0; realIndex = 0;
6507
6508                if (ctr.rowIndex >= 0) {
6509                    rowIndex = ctr.rowIndex;
6510                } else {
6511                    for (i = 0; i < rows.length; i++) {
6512                        if (rows[i] === ctr) {
6513                            rowIndex = i;
6514                            break;
6515                        }
6516                    }
6517                }
6518
6519                if (tm[0].length <= 1) {
6520                    ctb.parentNode.removeChild(ctb);
6521                } else {
6522                    for (j = 0; j < tm[rowIndex].length; j++) {
6523                        if (tm[rowIndex][j] === ctd.cellIndex) {
6524                            realIndex = j;
6525                            break;
6526                        }
6527                    }
6528
6529                    for (i = 0; i < rows.length; i++) {
6530                        if (tm[i][realIndex] !== -1) {
6531                            if (rows[i].cells[tm[i][realIndex]].colSpan > 1) {
6532                                rows[i].cells[tm[i][realIndex]].colSpan--;
6533                            } else {
6534                                rows[i].deleteCell(tm[i][realIndex]);
6535                            }
6536                        }
6537                    }
6538                }
6539            },
6540            deleteRow = function () {
6541                var curCI = -1, prevCI, ni, nrCI, cs, nj;
6542
6543                tm = getCellMatrix(ctb);
6544                rows = (ctb.rows && ctb.rows.length > 0) ? ctb.rows : ctb.getElementsByTagName('TR');
6545                rowIndex = 0;
6546
6547                if (ctr.rowIndex >= 0) {
6548                    rowIndex = ctr.rowIndex;
6549                } else {
6550                    for (i = 0; i < rows.length; i++) {
6551                        if (rows[i] === ctr) {
6552                            rowIndex = i;
6553                            break;
6554                        }
6555                    }
6556                }
6557
6558                if (rows.length <= 1) {
6559                    ctb.parentNode.removeChild(ctb);
6560                } else {
6561                    for (i = 0; i < rowIndex; i++) {
6562                        tempr = rows[i];
6563                        for (j = 0; j < tempr.cells.length; j++) {
6564                            if (tempr.cells[j].rowSpan > (rowIndex - i)) {
6565                                tempr.cells[j].rowSpan--;
6566                            }
6567                        }
6568                    }
6569
6570                    for (i = 0; i < tm[rowIndex].length; i++) {
6571                        prevCI = curCI;
6572                        curCI = tm[rowIndex][i];
6573
6574                        if (curCI !== -1 && curCI !== prevCI && ctr.cells[curCI].rowSpan > 1 && (rowIndex + 1) < rows.length) {
6575                            ni = i;
6576                            nrCI = tm[rowIndex + 1][ni];
6577                            while (nrCI === -1) {
6578                                ni++;
6579                                nrCI = (ni < rows[rowIndex + 1].cells.length) ? tm[rowIndex + 1][ni] : rows[rowIndex + 1].cells.length;
6580                            }
6581
6582                            newc = rows[rowIndex + 1].insertCell(nrCI);
6583                            rows[rowIndex].cells[curCI].rowSpan--;
6584                            nc = rows[rowIndex].cells[curCI].cloneNode(false);
6585                            rows[rowIndex + 1].replaceChild(nc, newc);
6586
6587                            cs = (ctr.cells[curCI].colSpan > 1) ? ctr.cells[curCI].colSpan : 1;
6588                            nj = 0;
6589
6590                            for (j = i; j < (i + cs); j++) {
6591                                tm[rowIndex + 1][j] = nrCI;
6592                                nj = j;
6593                            }
6594                            for (j = nj; j < tm[rowIndex + 1].length; j++) {
6595                                if (tm[rowIndex + 1][j] !== -1) {
6596                                    tm[rowIndex + 1][j]++;
6597                                }
6598                            }
6599                        }
6600                    }
6601
6602                    if (ctb.rows && ctb.rows.length > 0) {
6603                        ctb.deleteRow(rowIndex);
6604                    } else {
6605                        ctb.removeChild(rows[rowIndex]);
6606                    }
6607                }
6608            },
6609            mergeCellRight = function () {
6610                tm = getCellMatrix(ctb);
6611                rows = (ctb.rows && ctb.rows.length > 0) ? ctb.rows : ctb.getElementsByTagName('tr');
6612                rowIndex = 0; realIndex = 0;
6613
6614                if (ctr.rowIndex >= 0) {
6615                    rowIndex = ctr.rowIndex;
6616                } else {
6617                    for (i = 0; i < rows.length; i++) {
6618                        if (rows[i] === ctr) {
6619                            rowIndex = i;
6620                            break;
6621                        }
6622                    }
6623                }
6624
6625                for (j = 0; j < tm[rowIndex].length; j++) {
6626                    if (tm[rowIndex][j] === ctd.cellIndex) {
6627                        realIndex = j;
6628                        break;
6629                    }
6630                }
6631
6632                if (ctd.cellIndex + 1 < ctr.cells.length) {
6633                    var ccrs = ctd.rowSpan || 1,
6634                        cccs = ctd.colSpan || 1,
6635                        ncrs = ctr.cells[ctd.cellIndex + 1].rowSpan || 1,
6636                        nccs = ctr.cells[ctd.cellIndex + 1].colSpan || 1,
6637                        html;
6638
6639                    j = realIndex;
6640
6641                    while (tm[rowIndex][j] === ctd.cellIndex) {
6642                        j++;
6643                    }
6644
6645                    if (tm[rowIndex][j] === ctd.cellIndex + 1) {
6646                        if (ccrs === ncrs) {
6647                            if (rows.length > 1) {
6648                                ctd.colSpan = cccs + nccs;
6649                            }
6650                            html = self.trimSpace(ctr.cells[ctd.cellIndex + 1].innerHTML);
6651                            html = html.replace(/^&nbsp;/, '');
6652                            ctd.innerHTML += html;
6653                            ctr.deleteCell(ctd.cellIndex + 1);
6654                        }
6655                    }
6656                }
6657            },
6658            mergeCellDown = function () {
6659                var crealIndex = 0,
6660                    ccrs = ctd.rowSpan || 1,
6661                    cccs = ctd.colSpan || 1,
6662                    ncellIndex, html, ncrs, nccs;
6663
6664                tm = getCellMatrix(ctb);
6665                rows = (ctb.rows && ctb.rows.length > 0) ? ctb.rows : ctb.getElementsByTagName('tr');
6666                rowIndex = 0;
6667
6668                if (ctr.rowIndex >= 0) {
6669                    rowIndex = ctr.rowIndex;
6670                } else {
6671                    for (i = 0; i < rows.length; i++) {
6672                        if (rows[i] === ctr) {
6673                            rowIndex = i;
6674                            break;
6675                        }
6676                    }
6677                }
6678
6679                for (i = 0; i < tm[rowIndex].length; i++) {
6680                    if (tm[rowIndex][i] === ctd.cellIndex) {
6681                        crealIndex = i;
6682                        break;
6683                    }
6684                }
6685
6686                if (rowIndex + ccrs < rows.length) {
6687                    ncellIndex = tm[rowIndex + ccrs][crealIndex];
6688                    if (ncellIndex !== -1 &&
6689                        (crealIndex === 0 || (crealIndex > 0 &&
6690                        (tm[rowIndex + ccrs][crealIndex - 1] !== tm[rowIndex + ccrs][crealIndex]))))
6691                    {
6692                        ncrs = rows[rowIndex + ccrs].cells[ncellIndex].rowSpan || 1;
6693                        nccs = rows[rowIndex + ccrs].cells[ncellIndex].colSpan || 1;
6694                        if (cccs === nccs) {
6695                            html = self.trimSpace(rows[rowIndex + ccrs].cells[ncellIndex].innerHTML);
6696                            html = html.replace(/^&nbsp;/, '');
6697                            ctd.innerHTML += html;
6698                            rows[rowIndex + ccrs].deleteCell(ncellIndex);
6699                            ctd.rowSpan = ccrs + ncrs;
6700                        }
6701                    }
6702                }
6703            },
6704            splitCellVertical = function () {
6705                var ri, cs;
6706                tm = getCellMatrix();
6707                rowIndex = 0; realIndex = 0;
6708
6709                rows = (ctb.rows && ctb.rows.length > 0) ? ctb.rows : ctb.getElementsByTagName('TR');
6710
6711                if (ctr.rowIndex >= 0) {
6712                    rowIndex = ctr.rowIndex;
6713                } else {
6714                    for (ri = 0; ri < rows.length; ri++) {
6715                        if (rows[ri] === ctr) {
6716                            rowIndex = ri;
6717                            break;
6718                        }
6719                    }
6720                }
6721
6722                for (j = 0; j < tm[rowIndex].length; j++) {
6723                    if (tm[rowIndex][j] === ctd.cellIndex) {
6724                        realIndex = j;
6725                        break;
6726                    }
6727                }
6728
6729                if (ctd.colSpan > 1) {
6730                    newc = rows[rowIndex].insertCell(ctd.cellIndex + 1);
6731                    ctd.colSpan--;
6732                    nc = ctd.cloneNode(false);
6733                    nc.innerHTML = '&nbsp;';
6734                    rows[rowIndex].replaceChild(nc, newc);
6735                    ctd.colSpan = 1;
6736                    ctd.removeAttribute('colSpan');
6737                } else {
6738                    newc = rows[rowIndex].insertCell(ctd.cellIndex + 1);
6739                    nc = ctd.cloneNode(false);
6740                    nc.innerHTML = '&nbsp;';
6741                    rows[rowIndex].replaceChild(nc, newc);
6742                    for (i = 0; i < tm.length; i++) {
6743                        if (i !== rowIndex && tm[i][realIndex] !== -1) {
6744                            cs = (rows[i].cells[
6744tm[i][realIndex]].colSpan > 1) ? rows[i].cells[tm[i][realIndex]].colSpan : 1;
6745                            rows[i].cells[tm[i][realIndex]].colSpan = cs + 1;
6746                        }
6747                    }
6748                }
6749            },
6750            splitCellHorizontal = function () {
6751                var ni, rs;
6752                tm = getCellMatrix();
6753                rowIndex = 0; realIndex = 0;
6754                rows = (ctb.rows && ctb.rows.length > 0) ? ctb.rows : ctb.getElementsByTagName('TR');
6755
6756                if (ctr.rowIndex >= 0) {
6757                    rowIndex = ctr.rowIndex;
6758                } else {
6759                    for (i = 0; i < rows.length; i++) {
6760                        if (rows[i] === ctr) {
6761                            rowIndex = i;
6762                            break;
6763                        }
6764                    }
6765                }
6766
6767                for (j = 0; j < tm[rowIndex].length; j++) {
6768                    if (tm[rowIndex][j] === ctd.cellIndex) {
6769                        realIndex = j;
6770                        break;
6771                    }
6772                }
6773
6774                if (ctd.rowSpan > 1) {
6775                    i = realIndex;
6776                    while (tm[rowIndex + 1][i] === -1) {
6777                        i++;
6778                    }
6779
6780                    ni = (i === tm[rowIndex + 1].length) ? rows[rowIndex + 1].cells.length : tm[rowIndex + 1][i];
6781
6782                    newc = rows[rowIndex + 1].insertCell(ni);
6783                    ctd.rowSpan--;
6784
6785                    nc = ctd.cloneNode(false);
6786                    nc.innerHTML = '&nbsp;';
6787                    rows[rowIndex + 1].replaceChild(nc, newc);
6788                    ctd.rowSpan = 1;
6789                } else {
6790                    if (ctb.rows && ctb.rows.length > 0) {
6791                        ctb.insertRow(rowIndex + 1);
6792                    } else {
6793                        if (rowIndex < (rows.length - 1)) {
6794                            ctb.insertBefore(document.createElement('TR'), rows[rowIndex + 1]);
6795                        } else {
6796                            ctb.appendChild(document.createElement('TR'));
6797                        }
6798                    }
6799                    for (i = 0; i < ctr.cells.length; i++) {
6800                        if (i !== ctd.cellIndex) {
6801                            rs = ctr.cells[i].rowSpan > 1 ? ctr.cells[i].rowSpan : 1;
6802                            ctr.cells[i].rowSpan = rs + 1;
6803                        }
6804                    }
6805
6806                    for (i = 0; i < rowIndex; i++) {
6807                        tempr = rows[i];
6808                        for (j = 0; j < tempr.cells.length; j++) {
6809                            if (tempr.cells[j].rowSpan > (rowIndex - i)) {
6810                                tempr.cells[j].rowSpan++;
6811                            }
6812                        }
6813                    }
6814
6815                    newc = rows[rowIndex + 1].insertCell(0);
6816                    nc = ctd.cloneNode(false);
6817                    nc.innerHTML = '&nbsp;';
6818                    rows[rowIndex + 1].replaceChild(nc, newc);
6819                }
6820            },
6821            tblReflash = function () {
6822                self.editAreaFocus(); self.doEditorEvent();
6823            },
6824            colorPickerEventHandler = function () {
6825                GB.popupWindow.ColorPicker.argv = {
6826                    func: function (color) {
6827                        ctd.setAttribute('bgColor', color);
6828                        document.getElementById('fm_cell_bgcolor').value = color;
6829                    },
6830                    selectedCell : ctd
6831                };
6832                self.windowOpen('ColorPicker');
6833            },
6834            editSubmitEventHandler = function () {
6835                var width = self.trimSpace(document.getElementById('fm_cell_width').value),
6836                    height = self.trimSpace(document.getElementById('fm_cell_height').value),
6837                    bgcolor = self.trimSpace(document.getElementById('fm_cell_bgcolor').value);
6838                if (width) {
6839                    ctd.setAttribute('width', width);
6840                }
6841                if (height) {
6842                    ctd.setAttribute('height', height);
6843                }
6844                if (bgcolor) {
6845                    ctd.setAttribute('bgcolor', bgcolor);
6846                }
6847            },
6848            deleteSubmitEventHandler = function () {
6849                ctb.parentNode.removeChild(ctb);
6850                self.doEditorEvent();
6851            },
6852            funcs = {
6853                add_cols_after: { icon: 'table_insert_column.png', title: '열 삽입',
6854                    func: function () {
6855                        insertColumn(ctd.cellIndex); tblReflash();
6856                    }},
6857                add_rows_after: { icon: 'table_insert_row.png', title: '행 삽입',
6858                    func: function () {
6859                        insertRow(ctr.rowIndex); tblReflash();
6860                    }},
6861                remove_cols: { icon: 'table_delete_column.png', title: '열 삭제',
6862                    func: function () {
6863                        deleteColumn(ctd.cellIndex); tblReflash();
6864                    }},
6865                remove_rows: { icon: 'table_delete_row.png', title: '행 삭제',
6866                    func: function () {
6867                        deleteRow(); tblReflash();
6868                    }},
6869                sp1: { icon: 'dot.gif' },
6870                merge_cell_right: { icon: 'table_join_row.png', title: '오른쪽 셀ê
6870³¼ 병합',
6871                    func: function () {
6872                        mergeCellRight(); tblReflash();
6873                    }},
6874                merge_cell_down: { icon: 'table_join_column.png', title: '아래 셀과 병합',
6875                    func: function () {
6876                        mergeCellDown(); tblReflash();
6877                    }},
6878                split_cell_v: { icon: 'table_split_row.png', title: '셀 열로 나누기',
6879                    func: function () {
6880                        splitCellVertical(); tblReflash();
6881                    }},
6882                split_cell_h: { icon: 'table_split_column.png', title: '셀 행으로 나누기',
6883                    func: function () {
6884                        splitCellHorizontal(); tblReflash();
6885                    }}
6886            },
6887            attrFuncs = {
6888                setWidth: {
6889                    txt: '가로폭',
6890                    id: 'fm_cell_width',
6891                    marginRight: '10px',
6892                    value: ctd.getAttribute('width')
6893                },
6894                setHeight: {
6895                    txt: '세로폭',
6896                    id: 'fm_cell_height',
6897                    marginRight: '10px',
6898                    value: ctd.getAttribute('height')
6899                },
6900                setBgcolor: {
6901                    txt: '배경색',
6902                    id: 'fm_cell_bgcolor',
6903                    marginRight: '2px',
6904                    value: ctd.getAttribute('bgcolor')
6905                }
6906            },
6907            deleteSubmit = new Image(),
6908            spliter = document.createElement('div'), txt, input,
6909            colorPicker = new Image(),
6910            editSubmit = new Image();
6911
6912
6913        while (ctb && ctb.tagName.toLowerCase() !== 'table') {
6914            ctb = ctb.parentNode;
6915        }
6916        while (ctr && ctr.tagName.toLowerCase() !== 'tr') {
6917            ctr = ctr.parentNode;
6918        }
6919
6920        self.cheditor.editBlock.innerHTML = '';
6921        div.style.padding = '6px';
6922
6923        for (i in funcs) {
6924            if (!funcs.hasOwnProperty(i)) {
6925                continue;
6926            }
6927            span = document.createElement('span');
6928            icon = document.createElement('img');
6929            icon.src = self.config.iconPath + funcs[i].icon;
6930
6931            if (i === 'sp1' || i === 'sp2') {
6932                icon.className = 'edit-table-ico';
6933            } else {
6934                icon.setAttribute('title', funcs[i].title);
6935                icon.className = 'edit-table-ico';
6936                icon.setAttribute('alt', '');
6937                icon.onclick = funcs[i].func;
6938            }
6939            div.appendChild(span.appendChild(icon));
6940        }
6941
6942        deleteSubmit.src = this.config.iconPath + 'delete_table.png';
6943        deleteSubmit.style.marginLeft = '22px';
6944        deleteSubmit.className = 'edit-table-ico';
6945        deleteSubmit.setAttribute('title', '테이블 삭제');
6946        deleteSubmit.onclick = deleteSubmitEventHandler;
6947        div.appendChild(deleteSubmit);
6948
6949        spliter.style.padding = '10px 0px 0px 0px';
6950        spliter.style.marginTop = '5px';
6951        spliter.style.borderTop = '1px solid #ccc';
6952        spliter.style.textAlign = 'center';
6953
6954        for (i in attrFuncs) {
6955            if (!attrFuncs.hasOwnProperty(i)) {
6956                continue;
6957            }
6958            txt = document.createTextNode(attrFuncs[i].txt + ' ');
6959            spliter.appendChild(txt);
6960            input = document.createElement('input');
6961            input.style.marginRight = attrFuncs[i].marginRight;
6962            input.setAttribute('type', 'text');
6963            input.setAttribute('name', i);
6964            input.setAttribute('id', attrFuncs[i].id);
6965            input.setAttribute('size', 7);
6966            input.setAttribute('value', attrFuncs[i].value || '');
6967            spliter.appendChild(input);
6968        }
6969
6970        colorPicker.src = this.config.iconPath + 'button/color_picker.gif';
6971        colorPicker.className = 'color-picker';
6972        colorPicker.onclick = colorPickerEventHandler;
6973        spliter.appendChild(colorPicker);
6974
6975        editSubmit.src = this.config.iconPath + 'button/edit_cell.gif';
6976        editSubmit.className = 'input-submit';
6977        editSubmit.style.verticalAlign = 'top';
6978        editSubmit.onclick = editSubmitEventHandler;
6979
6980        spliter.appendChild(editSubmit);
6981        div.appendChild(spliter);
6982        self.cheditor.editBlock.appendChild(div);
6983    },
6984
6985    doEditorEvent : function (evt) {
6986        var self = this,
6987            cmd = null, ancestors = [], node, el, pNode, range, sType, links, span, tag, remove, bText,
6988            srcElement = evt.target || evt.srcElement,
6989            block = self.cheditor.editBlock,
6990            status = self.cheditor.tagPath,
6991            linkOnClickEventHandler = function () {
6992                if (bText) {
6993                    document.getElementById('removeSelected').style.display = 'inline';
6994                    self.tagSelector(this.el);
6995                }
6996            },
6997            removeOnClickEventHandler = function () {
6998                self.doc.execCommand('RemoveFormat', false, null);
6999                remove.style.display = 'none';
7000                self.editAreaFocus();
7001                self.doEditorEvent();
7002            };
7003
7004        if (!this.undefined(srcElement) && srcElement.nodeType === GB.node.element) {
7005            pNode = srcElement;
7006        } else {
7007            range = self.getRange();
7008            sType = self.getSelectionType();
7009            bText = sType === GB.selection.text;
7010
7011            if (!self.W3CRange) {
7012                switch (sType) {
7013                    case GB.selection.none :
7014                    case GB.selection.text :
7015                        pNode = range.parentElement();
7016                        break;
7017                    case GB.selection.element :
7018                        pNode = range.item(0);
7019                        break;
7020                    default :
7021                        pNode = self.editArea.document.body;
7022                }
7023            } else {
7024                pNode = range.commonAncestorContainer;
7025                if (!range.collapsed &&
7026                    range.startContainer === range.endContainer &&
7027                    range.startOffset - range.endOffset < 2 &&
7028                    range.startContainer.hasChildNodes())
7029                {
7030                    pNode = range.startContainer.childNodes[range.startOffset];
7031                }
7032                while (pNode.nodeType === GB.node.text) {
7033                    pNode = pNode.parentNode;
7034                }
7035            }
7036        }
7037
7038        node = pNode;
7039        while (pNode && pNode.nodeType === GB.node.element) {
7040            if (pNode.tagName.toLowerCase() === 'body') {
7041                break;
7042            }
7043            if (pNode.tagName.toLowerCase() === 'img') {
7044                cmd = 'img'; break;
7045            }
7046            if (pNode.tagName.toLowerCase() === 'td' || pNode.tagName.toLowerCase() === 'th') {
7047                cmd = 'cell'; break;
7048            }
7049            pNode = pNode.parentNode;
7050        }
7051
7052        if (!cmd) {
7053            block.style.display = 'none';
7054            block.innerHTML = '';
7055        } else {
7056            if (cmd === 'cell') {
7057                block.style.display = 'block';
7058                self.modifyCell(pNode);
7059            }
7060        }
7061
7062        if (self.config.showTagPath) {
7063            while (node && node.nodeType === GB.node.element) {
7064                ancestors.push(node);
7065                if (node.tagName.toLowerCase() === 'body') {
7066                    break;
7067                }
7068                node = node.parentNode;
7069            }
7070
7071            status.innerHTML = '';
7072            status.appendChild(document.createTextNode('<html> '));
7073            el = ancestors.pop();
7074
7075            while (el) {
7076                status.appendChild(document.createTextNode('<'));
7077                tag = el.nodeName.toLowerCase();
7078
7079                links = document.createElement('a');
7080                links.el = el;
7081                links.href = 'javascript:void%200';
7082                links.className = 'cheditor-tag-path-elem';
7083                links.title = el.style.cssText;
7084                (function () {
7085                    links.onclick = linkOnClickEventHandler;
7086                })();
7087                links.appendChild(document.createTextNode(tag));
7088                status.appendChild(links);
7089                status.appendChild(document.createTextNode('> '));
7090                el = ancestors.pop();
7091            }
7092
7093            if (bText) {
7094                remove = document.createElement('a');
7095                remove.href = 'javascript:void%200';
7096                remove.id = 'removeSelected';
7097                remove.style.display = 'none';
7098                remove.className = 'cheditor-tag-path-elem';
7099                remove.style.color = '#cc3300';
7100                remove.appendChild(document.createTextNode('<remove format>'));
7101                (function () {
7102                    remove.onclick = removeOnClickEventHandler;
7103                })();
7104                span = document.createElement('span');
7105                span.style.marginTop = '2px';
7106                span.appendChild(remove);
7107                self.cheditor.tagPath.appendChild(span);
7108            }
7109        }
7110
7111        self.toolbarUpdate(srcElement);
7112    },
7113
7114    tagSelector : function (node) {
7115        var rng, selection;
7116        this.editAreaFocus();
7117
7118        if (this.W3CRange) {
7119            selection = this.editArea.getSelection();
7120            if (this.undefined(selection)) {
7121                return;
7122            }
7123            try {
7124                rng = selection.getRangeAt(0);
7125            } catch (e) {
7126                return;
7127            }
7128            rng.selectNodeContents(node);
7129            selection.removeAllRanges();
7130            selection.addRange(rng);
7131        } else {
7132            rng = this.doc.body.createTextRange();
7133            if (rng) {
7134                rng.moveToElementText(node);
7135                rng.select();
7136            }
7137        }
7138    },
7139
7140    getBrowser : function () {
7141        return GB.browser;
7142    },
7143    $ : function (id) {
7144        return this.doc.getElementById(id);
7145    }
7146};
7147
7148(function () {
7149    var dragWindow = {
7150        obj: null,
7151        init: function (o, oRoot, minX, maxX, minY, maxY) {
7152            o.style.curser = 'default';
7153            o.onmousedown = dragWindow.start;
7154            o.onmouseover = function () {
7155                this.style.cursor = 'move';
7156            };
7157            o.hmode = true;
7158            o.vmode = true;
7159            o.root = (oRoot && oRoot !== null) ? oRoot : o;
7160            o.transId = oRoot.id + '_Trans';
7161
7162            if (o.hmode  && isNaN(parseInt(o.root.style.left, 10))) {
7163                o.root.style.left = '0px';
7164            }
7165            if (o.vmode  && isNaN(parseInt(o.root.style.top, 10))) {
7166                o.root.style.top = '0px';
7167            }
7168            if (!o.hmode && isNaN(parseInt(o.root.style.right, 10))) {
7169                o.root.style.right = '0px';
7170            }
7171            if (!o.vmode && isNaN(parseInt(o.root.style.bottom, 10))) {
7172                o.root.style.bottom = '0px';
7173            }
7174
7175            o.minX = minX !== undefined ? minX : null;
7176            o.minY = minY !== undefined ? minY : null;
7177            o.maxX = maxX !== undefined ? maxX : null;
7178            o.maxY = maxY !== undefined ? maxY : null;
7179            o.root.onDragStart = new Function();
7180            o.root.onDragEnd = new Function();
7181            o.root.onDrag = new Function();
7182        },
7183        start: function (e) {
7184            var o = dragWindow.obj = this,
7185                dragTransBg = document.createElement('div'),
7186                y = parseInt(o.vmode ? o.root.style.top  : o.root.style.bottom, 10),
7187                x = parseInt(o.hmode ? o.root.style.left : o.root.style.right, 10);
7188
7189            e = dragWindow.fixEv(e);
7190            o.root.onDragStart(x, y);
7191            o.lastMouseX = e.clientX;
7192            o.lastMouseY = e.clientY;
7193
7194            document.onmousemove = dragWindow.drag;
7195            document.onmouseup = dragWindow.end;
7196
7197            if (o.root.lastChild.id === o.transId) {
7198                return false;
7199            }
7200
7201            dragTransBg.className = 'cheditor-dragWindowTransparent';
7202            if (GB.browser.msie && GB.browser.version < 10) {
7203                dragTransBg.style.filter = 'alpha(opacity=0)';
7204            } else {
7205                dragTransBg.style.opacity = 0;
7206            }
7207            dragTransBg.id = o.transId;
7208            dragTransBg.style.width = o.root.lastChild.firstChild.style.width;
7209            dragTransBg.style.height = o.root.lastChild.firstChild.style.height;
7210            o.root.appendChild(dragTransBg);
7211            return false;
7212        },
7213        drag: function (e) {
7214            e = dragWindow.fixEv(e);
7215            var o = dragWindow.obj,
7216                ey = e.clientY,
7217                ex = e.clientX,
7218                y = parseInt(o.vmode ? o.root.style.top : o.root.style.bottom, 10),
7219                x = parseInt(o.hmode ? o.root.style.left : o.root.style.right, 10),
7220                nx, ny;
7221
7222            nx = x + ((ex - o.lastMouseX) * (o.hmode ? 1 : -1));
7223            ny = y + ((ey - o.lastMouseY) * (o.vmode ? 1 : -1));
7224
7225            dragWindow.obj.root.style.left = nx + 'px';
7226            dragWindow.obj.root.style.top = ny + 'px';
7227            dragWindow.obj.lastMouseX = ex;
7228            dragWindow.obj.lastMouseY = ey;
7229            dragWindow.obj.root.onDrag(nx, ny);
7230            return false;
7231        },
7232        end: function () {
7233            document.onmousemove = null;
7234            document.onmouseup = null;
7235            dragWindow.obj.root.onDragEnd(parseInt(dragWindow.obj.root.style[dragWindow.obj.hmode ? 'left' : 'right'], 10),
7236                    parseInt(dragWindow.obj.root.style[dragWindow.obj.vmode ? 'top' : 'bottom'], 10));
7237
7238            if (dragWindow.obj.root.lastChild.id === dragWindow.obj.transId) {
7239                dragWindow.obj.root.removeChild(dragWindow.obj.root.lastChild);
7240            }
7241            dragWindow.obj = null;
7242        },
7243        fixEv: function (e) {
7244            if (e === undefined) {
7245                e = window.event;
7246            }
7247            if (e.layerX === undefined) {
7248                e.layerX = e.offsetX;
7249            }
7250            if (e.layerY === undefined) {
7251                e.layerY = e.offsetY;
7252            }
7253            return e;
7254        }
7255    };
7256    GB.dragWindow = dragWindow;
7257})();
7258
7259// --------------------------------------------------------------------------
7260// W3C DOM Range
7261//
7262
7263// --------------------------------------------------------------------------
7264// Table
7265//
7266
7267// --------------------------------------------------------------------------
7268// Color Picker
7269//
7270(function () {
7271    var colorDropper = {
7272        images: {pad: [181, 101], sld: [16, 101], cross: [15, 15], arrow: [7, 11]},
7273        fetchElement: function (mixed) {
7274            return typeof mixed === 'string' ? document.getElementById(mixed) : mixed;
7275        },
7276
7277        addEvent: function (el, evnt, func) {
7278            if (el.addEventListener) {
7279                el.addEventListener(evnt, func, false);
7280            } else if (el.attachEvent) {
7281                el.attachEvent('on' + evnt, func);
7282            }
7283        },
7284
7285        fireEvent: function (el, evnt) {
7286            if (!el) {
7287                return;
7288            }
7289            var ev;
7290            if (document.createEvent) {
7291                ev = document.createEvent('HTMLEvents');
7292                ev.initEvent(evnt, true, true);
7293                el.dispatchEvent(ev);
7294            } else if (document.createEventObject) {
7295                ev = document.createEventObject();
7296                el.fireEvent('on' + evnt, ev);
7297            } else if (el['on' + evnt]) {
7298                el['on' + evnt]();
7299            }
7300        },
7301
7302        getElementPos: function (e) {
7303            var e1 = e, e2 = e, x = 0, y = 0;
7304            if (e1.offsetParent) {
7305                do {
7306                    x += e1.offsetLeft;
7307                    y += e1.offsetTop;
7308                    e1 = e1.offsetParent;
7309                } while (e1);
7310            }
7311
7312            while (e2 && e2.nodeName.toLowerCase() !== 'body') {
7313                x -= e2.scrollLeft;
7314                y -= e2.scrollTop;
7315                e2 = e2.parentNode;
7316            }
7317            return [x, y];
7318        },
7319
7320        getElementSize: function (e) {
7321            return [e.offsetWidth, e.offsetHeight];
7322        },
7323
7324        getRelMousePos: function (e) {
7325            var x = 0, y = 0;
7326            if (!e) {
7327                e = window.event;
7328            }
7329            if (typeof e.offsetX === 'number') {
7330                x = e.offsetX;
7331                y = e.offsetY;
7332            } else if (typeof e.layerX === 'number') {
7333                x = e.layerX;
7334                y = e.layerY;
7335            }
7336            return {x: x, y: y};
7337        },
7338
7339        color: function (target, prop) {
7340            this.required = true;
7341            this.adjust = true;
7342            this.hash = true;
7343            this.caps = false;
7344            this.valueElement = target;
7345            this.styleElement = target;
7346            this.onImmediateChange = null;
7347            this.hsv = [0, 0, 1];
7348            this.rgb = [1, 1, 1];
7349            this.minH = 0;
7350            this.maxH = 6;
7351            this.minS = 0;
7352            this.maxS = 1;
7353            this.minV = 0;
7354            this.maxV = 1;
7355
7356            this.pickerOnfocus = true;
7357            this.pickerMode = 'HSV';
7358            this.pickerFace = 3;
7359            this.pickerFaceColor = '#fff';
7360            this.pickerInset = 1;
7361            this.pickerInsetColor = '#999';
7362            this.pickerZIndex = 10003;
7363
7364            var p,
7365                self = this,
7366                modeID = this.pickerMode.toLowerCase() === 'hvs' ? 1 : 0,
7367                abortBlur = false,
7368                valueElement = colorDropper.fetchElement(this.valueElement), styleElement = colorDropper.fetchElement(this.styleElement),
7369                holdPad = false, holdSld = false, touchOffset = {},
7370                leaveValue = 1 << 0, leaveStyle = 1 << 1, leavePad = 1 << 2, leaveSld = 1 << 3,
7371                updateFieldEventHandler = function () {
7372                    self.fromString(valueElement.value, leaveValue);
7373                    dispatchImmediateChange();
7374                };
7375
7376            colorDropper.addEvent(target, 'blur', function () {
7377                if (!abortBlur) {
7378                    window.setTimeout(function () {
7379                        abortBlur || blurTarget();
7380                        abortBlur = false;
7381                    }, 0);
7382                } else {
7383                    abortBlur = false;
7384                }
7385            });
7386
7387            for (p in prop) {
7388                if (prop.hasOwnProperty(p)) {
7389                    this[p] = prop[p];
7390                }
7391            }
7392
7393            this.hidePicker = function () {
7394                if (isPickerOwner()) {
7395                    removePicker();
7396                }
7397            };
7398
7399            this.showPicker = function () {
7400                if (!isPickerOwner()) {
7401                    drawPicker();
7402                }
7403            };
7404
7405            this.importColor = function () {
7406                if (!valueElement) {
7407                    this.exportColor();
7408                } else {
7409                    if (!this.adjust) {
7410                        if (!this.fromString(valueElement.value, leaveValue)) {
7411                            styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage;
7412                            styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
7413                            styleElement.style.color = styleElement.jscStyle.color;
7414                            this.exportColor(leaveValue | leaveStyle);
7415                        }
7416                    } else if (!this.required && /^\s*$/.test(valueElement.value)) {
7417                        valueElement.value = '';
7418                        styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage;
7419                        styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
7420                        styleElement.style.color = styleElement.jscStyle.color;
7421                        this.exportColor(leaveValue | leaveStyle);
7422
7423                    } else if (this.fromString(valueElement.value)) {
7424                    } else {
7425                        this.exportColor();
7426                    }
7427                }
7428            };
7429
7430            this.exportColor = function (flags) {
7431                if (!(flags & leaveValue) && valueElement) {
7432                    var value = this.toString();
7433                    if (this.caps) {
7434                        value = value.toUpperCase();
7435                    }
7436                    if (this.hash) {
7437                        value = '#' + value;
7438                    }
7439                    valueElement.value = value;
7440                }
7441                if (!(flags & leaveStyle) && styleElement) {
7442                    styleElement.style.backgroundImage = 'none';
7443                    styleElement.style.backgroundColor = '#' + this.toString();
7444                    styleElement.style.color = 0.213 * this.rgb[0] + 0.715 * this.rgb[1] + 0.072 * this.rgb[2] < 0.5 ? '#FFF' : '#000';
7445                }
7446                if (!(flags & leavePad) && isPickerOwner()) {
7447                    redrawPad();
7448                }
7449                if (!(flags & leaveSld) && isPickerOwner()) {
7450                    redrawSld();
7451                }
7452            };
7453
7454            this.fromHSV = function (h, s, v, flags) {
7455                if (h) {
7456                    h = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, h));
7457                }
7458                if (s) {
7459                    s = Math.max(0.0, this.minS, Math.min(1.0, this.maxS, s));
7460                }
7461                if (v) {
7462                    v = Math.max(0.0, this.minV, Math.min(1.0, this.maxV, v));
7463                }
7464
7465                this.rgb = this.HSV_RGB(
7466                    h === null ? this.hsv[0] : (this.hsv[0] = h),
7467                    s === null ? this.hsv[1] : (this.hsv[1] = s),
7468                    v === null ? this.hsv[2] : (this.hsv[2] = v)
7469                );
7470                this.exportColor(flags);
7471            };
7472
7473            this.fromRGB = function (r, g, b, flags) {
7474                if (r) {
7475                    r = Math.max(0.0, Math.min(1.0, r));
7476                }
7477                if (g) {
7478                    g = Math.max(0.0, Math.min(1.0, g));
7479                }
7480                if (b) {
7481                    b = Math.max(0.0, Math.min(1.0, b));
7482                }
7483
7484                var hsv = this.RGB_HSV(
7485                    r === null ? this.rgb[0] : r,
7486                    g === null ? this.rgb[1] : g,
7487                    b === null ? this.rgb[2] : b
7488                );
7489                if (hsv[0] !== null) {
7490                    this.hsv[0] = Math.max(0.0, this.minH, Math.min(6.0, this.maxH, hsv[0]));
7491                }
7492                if (hsv[2] !== 0) {
7493                    this.hsv[1] = hsv[1] === null ? null : Math.max(0.0, this.minS, Math.min(1.0, this.maxS, hsv[1]));
7494                }
7495                this.hsv[2] = hsv[2] === null ? null : Math.max(0.0, this.minV, Math.min(1.0, this.maxV, hsv[2]));
7496
7497                var rgb = this.HSV_RGB(this.hsv[0], this.hsv[1], this.hsv[2]);
7498                this.rgb[0] = rgb[0];
7499                this.rgb[1] = rgb[1];
7500                this.rgb[2] = rgb[2];
7501
7502                this.exportColor(flags);
7503            };
7504
7505            this.fromString = function (hex, flags) {
7506                var m = hex.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i);
7507                if (!m) {
7508                    return false;
7509                }
7510                if (m[1].length === 6) {
7511                    this.fromRGB(
7512                        parseInt(m[1].substr(0, 2), 16) / 255,
7513                        parseInt(m[1].substr(2, 2), 16) / 255,
7514                        parseInt(m[1].substr(4, 2), 16) / 255,
7515                        flags
7516                    );
7517                } else {
7518                    this.fromRGB(
7519                        parseInt(m[1].charAt(0) + m[1].charAt(0), 16) / 255,
7520                        parseInt(m[1].charAt(1) + m[1].charAt(1), 16) / 255,
7521                        parseInt(m[1].charAt(2) + m[1].charAt(2), 16) / 255,
7522                        flags
7523                    );
7524                }
7525                return true;
7526            };
7527
7528            this.toString = function () {
7529                return (
7530                    (0x100 | Math.round(255 * this.rgb[0])).toString(16).substr(1) +
7531                    (0x100 | Math.round(255 * this.rgb[1])).toString(16).substr(1) +
7532                    (0x100 | Math.round(255 * this.rgb[2])).toString(16).substr(1)
7533                );
7534            };
7535
7536            this.RGB_HSV = function (r, g, b) {
7537                var n = Math.min(Math.min(r, g), b),
7538                    v = Math.max(Math.max(r, g), b),
7539                    m = v - n, h;
7540
7541                if (m === 0) {
7542                    return [null, 0, v];
7543                }
7544                h = r === n ? 3 + (b - g) / m : (g === n ? 5 + (r - b) / m : 1 + (g - r) / m);
7545                return [h === 6 ? 0 : h, m / v, v];
7546            };
7547
7548            this.HSV_RGB = function (h, s, v) {
7549                if (h === null) {
7550                    return [v, v, v];
7551                }
7552                var i = Math.floor(h),
7553                    f = i % 2 ? h - i : 1 - (h - i),
7554                    m = v * (1 - s),
7555                    n = v * (1 - s * f);
7556                switch (i) {
7557                    case 6:
7558                    case 0:
7559                        return [v, n, m];
7560                    case 1:
7561                        return [n, v, m];
7562                    case 2:
7563                        return [m, v, n];
7564                    case 3:
7565                        return [m, n, v];
7566                    case 4:
7567                        return [n, m, v];
7568                    case 5:
7569                        return [v, m, n];
7570                }
7571            };
7572
7573            function removePicker() {
7574                delete colorDropper.picker.owner;
7575                colorDropper.picker.boxB.parentNode.removeChild(colorDropper.picker.boxB);
7576            }
7577
7578            function drawPicker() {
7579                var touchMoveEventHandler = function (e) {
7580                        var event = {
7581                            'offsetX': e.touches[0].pageX - touchOffset.X,
7582                            'offsetY': e.touches[0].pageY - touchOffset.Y
7583                        };
7584                        if (holdPad || holdSld) {
7585                            holdPad && setPad(event);
7586                            holdSld && setSld(event);
7587                            dispatchImmediateChange();
7588                        }
7589                        e.stopPropagation();
7590                        e.preventDefault();
7591                    },
7592                    dims = getPickerDims(self),
7593                    padImg = modeID ? 'color_picker_hv.png' : 'color_picker_hs.png',
7594                    i, seg, segSize;
7595
7596                if (!colorDropper.picker) {
7597                    colorDropper.picker = {
7598                        box: document.createElement('div'),
7599                        boxB: document.createElement('div'),
7600                        pad: document.createElement('div'),
7601                        padB: document.createElement('div'),
7602                        padM: document.createElement('div'),
7603                        sld: document.createElement('div'),
7604                        sldB: document.createElement('div'),
7605                        sldM: document.createElement('div')
7606                    };
7607                    for (i = 0, segSize = 2; i < colorDropper.images.sld[1]; i += segSize) {
7608                        seg = document.createElement('div');
7609                        seg.style.height = segSize + 'px';
7610                        seg.style.fontSize = '1px';
7611                        seg.style.lineHeight = '0px';
7612                        colorDropper.picker.sld.appendChild(seg);
7613                    }
7614                    colorDropper.picker.sldB.appendChild(colorDropper.picker.sld);
7615                    colorDropper.picker.box.appendChild(colorDropper.picker.sldB);
7616                    colorDropper.picker.box.appendChild(colorDropper.picker.sldM);
7617                    colorDropper.picker.padB.appendChild(colorDropper.picker.pad);
7618                    colorDropper.picker.box.appendChild(colorDropper.picker.padB);
7619                    colorDropper.picker.box.appendChild(colorDropper.picker.padM);
7620                    colorDropper.picker.boxB.appendChild(colorDropper.picker.box);
7621                }
7622
7623                p = colorDropper.picker;
7624                p.box.onmouseup = p.box.onmouseout = function () {
7625                    target.focus();
7626                };
7627                p.box.onmousedown = function () {
7628                    abortBlur = true;
7629                };
7630                p.box.onmousemove = function (e) {
7631                    if (holdPad || holdSld) {
7632                        holdPad && setPad(e);
7633                        holdSld && setSld(e);
7634                        if (document.selection) {
7635                            document.selection.empty();
7636                        } else if (window.getSelection) {
7637                            window.getSelection().removeAllRanges();
7638                        }
7639                        dispatchImmediateChange();
7640                    }
7641                };
7642
7643                if ('ontouchstart' in window) {
7644                    p.box.removeEventListener('touchmove', touchMoveEventHandler, false);
7645                    p.box.addEventListener('touchmove', touchMoveEventHandler, false);
7646                }
7647                p.padM.onmouseup = p.padM.onmouseout = function () {
7648                    if (holdPad) {
7649                        holdPad = false;
7650                        colorDropper.fireEvent(valueElement, 'change');
7651                    }
7652                };
7653                p.padM.onmousedown = function (e) {
7654                    switch (modeID) {
7655                        case 0:
7656                            if (self.hsv[2] === 0) {
7657                                self.fromHSV(null, null, 1.0);
7658                            }
7659                            break;
7660                        case 1:
7661                            if (self.hsv[1] === 0) {
7662                                self.fromHSV(null, 1.0, null);
7663                            }
7664                            break;
7665                    }
7666                    holdSld = false;
7667                    holdPad = true;
7668                    setPad(e);
7669                    dispatchImmediateChange();
7670                };
7671
7672                if ('ontouchstart' in window) {
7673                    p.padM.addEventListener('touchstart', function (e) {
7674                        touchOffset = {'X': getOffsetParent(e.target).Left, 'Y': getOffsetParent(e.target).Top};
7675                        this.onmousedown({
7676                            'offsetX': e.touches[0].pageX - touchOffset.X,
7677                            'offsetY': e.touches[0].pageY - touchOffset.Y
7678                        });
7679                    });
7680                }
7681                p.sldM.onmouseup = p.sldM.onmouseout = function () {
7682                    if (holdSld) {
7683                        holdSld = false;
7684                        colorDropper.fireEvent(valueElement, 'change');
7685                    }
7686                };
7687                p.sldM.onmousedown = function (e) {
7688                    holdPad = false;
7689                    holdSld = true;
7690                    setSld(e);
7691                    dispatchImmediateChange();
7692                };
7693                if ('ontouchstart' in window) {
7694                    p.sldM.addEventListener('touchstart', function (e) {
7695                        touchOffset = {'X': getOffsetParent(e.target).Left, 'Y': getOffsetParent(e.target).Top};
7696                        this.onmousedown({
7697                            'offsetX': e.touches[0].pageX - touchOffset.X,
7698                            'offsetY': e.touches[0].pageY - touchOffset.Y
7699                        });
7700                    });
7701                }
7702
7703                p.box.style.width = dims[0] + 'px';
7704                p.box.style.height = dims[1] + 'px';
7705
7706                p.boxB.style.position = 'relative';
7707                p.boxB.style.clear = 'both';
7708                p.boxB.style.border = 'none';
7709                p.boxB.style.background = self.pickerFaceColor;
7710
7711                p.pad.style.width = colorDropper.images.pad[0] + 'px';
7712                p.pad.style.height = colorDropper.images.pad[1] + 'px';
7713
7714                p.padB.style.position = 'absolute';
7715                p.padB.style.left = self.pickerFace + 'px';
7716                p.padB.style.top = self.pickerFace + 'px';
7717                p.padB.style.border = self.pickerInset + 'px solid';
7718                p.padB.style.borderColor = self.pickerInsetColor;
7719
7720                p.padM.style.position = 'absolute';
7721                p.padM.style.left = '0';
7722                p.padM.style.top = '0';
7723                p.padM.style.width = self.pickerFace + 2 * self.pickerInset + colorDropper.images.pad[0] + colorDropper.images.arrow[0] + 'px';
7724                p.padM.style.height = p.box.style.height;
7725                p.padM.style.cursor = 'crosshair';
7726
7727                p.sld.style.overflow = 'hidden';
7728                p.sld.style.width = '13px';
7729                p.sld.style.height = colorDropper.images.sld[1] + 'px';
7730
7731                p.sldB.style.position = 'absolute';
7732                p.sldB.style.right = self.pickerFace + 'px';
7733                p.sldB.style.top = self.pickerFace + 'px';
7734                p.sldB.style.border = self.pickerInset + 'px solid';
7735                p.sldB.style.borderColor = self.pickerInsetColor;
7736
7737                p.sldM.style.position = 'absolute';
7738                p.sldM.style.right = '0';
7739                p.sldM.style.top = '0';
7740                p.sldM.style.width = 14 + colorDropper.images.arrow[0] + self.pickerFace + 2 * self.pickerInset + 'px';
7741                p.sldM.style.height = p.box.style.height;
7742
7743                try {
7744                    p.sldM.style.cursor = 'pointer';
7745                } catch (e) {
7746                    p.sldM.style.cursor = 'hand';
7747                }
7748
7749                p.padM.style.backgroundImage = 'url("' + self.iconDir + '/color_picker_cross.gif")';
7750                p.padM.style.backgroundRepeat = 'no-repeat';
7751                p.sldM.style.backgroundImage = 'url("' + self.iconDir + '/color_picker_arrow.gif")';
7752                p.sldM.style.backgroundRepeat = 'no-repeat';
7753                p.pad.style.backgroundImage = 'url("' + self.iconDir + '/' + padImg + '")';
7754                p.pad.style.backgroundRepeat = 'no-repeat';
7755                p.pad.style.backgroundPosition = '0 0';
7756                redrawPad();
7757                redrawSld();
7758                colorDropper.picker.owner = self;
7759                target.parentNode.parentNode.appendChild(p.boxB);
7760            }
7761
7762            function getPickerDims(o) {
7763                return [2 * o.pickerInset + 2 * o.pickerFace + colorDropper.images.pad[0] +
7764                2 * o.pickerInset + 2 * colorDropper.images.arrow[0] + colorDropper.images.sld[0],
7765                    2 * o.pickerInset + 2 * o.pickerFace + colorDropper.images.pad[1]];
7766            }
7767
7768            function redrawPad() {
7769                var yComponent, x, y, i = 0, rgb, s, c, f,
7770                    seg = colorDropper.picker.sld.childNodes;
7771
7772                switch (modeID) {
7773                    case 0:
7774                        yComponent = 1;
7775                        break;
7776                    case 1:
7777                        yComponent = 2;
7778                        break;
7779                }
7780                x = Math.round((self.hsv[0] / 6) * (colorDropper.images.pad[0] - 1));
7781                y = Math.round((1 - self.hsv[yComponent]) * (colorDropper.images.pad[1] - 1));
7782                colorDropper.picker.padM.style.backgroundPosition =
7783                    (self.pickerFace + self.pickerInset + x - Math.floor(colorDropper.images.cross[0] / 2)) + 'px ' +
7784                    (self.pickerFace + self.pickerInset + y - Math.floor(colorDropper.images.cross[1] / 2)) + 'px';
7785
7786                switch (modeID) {
7787                    case 0:
7788                        rgb = self.HSV_RGB(self.hsv[0], self.hsv[1], 1);
7789                        if (window.File && window.FileReader) {
7790                            colorDropper.picker.sld.style.background = 'linear-gradient(rgb(' +
7791                                (rgb[0] * (1 - i / seg.length) * 100) + '%,' +
7792                                (rgb[1] * (1 - i / seg.length) * 100) + '%,' +
7793                                (rgb[2] * (1 - i / seg.length) * 100) + '%), black)';
7794                        } else {
7795                            for (i = 0; i < seg.length; i += 1) {
7796                                seg[i].style.backgroundColor = 'rgb(' +
7797                                    (rgb[0] * (1 - i / seg.length) * 100) + '%,' +
7798                                    (rgb[1] * (1 - i / seg.length) * 100) + '%,' +
7799                                    (rgb[2] * (1 - i / seg.length) * 100) + '%)';
7800                            }
7801                        }
7802                        break;
7803                    case 1:
7804                        c = [self.hsv[2], 0, 0];
7805                        i = Math.floor(self.hsv[0]);
7806                        f = i % 2 ? self.hsv[0] - i : 1 - (self.hsv[0] - i);
7807                        switch (i) {
7808                            case 6:
7809                            case 0:
7810                                rgb = [0, 1, 2];
7811                                break;
7812                            case 1:
7813                                rgb = [1, 0, 2];
7814                                break;
7815                            case 2:
7816                                rgb = [2, 0, 1];
7817                                break;
7818                            case 3:
7819                                rgb = [2, 1, 0];
7820                                break;
7821                            case 4:
7822                                rgb = [1, 2, 0];
7823                                break;
7824                            case 5:
7825                                rgb = [0, 2, 1];
7826                                break;
7827                        }
7828
7829                        for (i = 0; i < seg.length; i += 1) {
7830                            s = 1 - 1 / (seg.length - 1) * i;
7831                            c[1] = c[0] * (1 - s * f);
7832                            c[2] = c[0] * (1 - s);
7833                            seg[i].style.backgroundColor = 'rgb(' +
7834                                (c[rgb[0]] * 100) + '%,' +
7835                                (c[rgb[1]] * 100) + '%,' +
7836                                (c[rgb[2]] * 100) + '%)';
7837                        }
7838                        break;
7839                }
7840            }
7841
7842            function getOffsetParent(el) {
7843                var parent = el.offsetParent, top = 0, left = 0;
7844                while (parent) {
7845                    top += parent.offsetTop;
7846                    left += parent.offsetLeft;
7847                    parent = parent.offsetParent;
7848                }
7849                return {Left: left, Top: top};
7850            }
7851
7852            function redrawSld() {
7853                var yComponent, y;
7854                switch (modeID) {
7855                    case 0:
7856                        yComponent = 2;
7857                        break;
7858                    case 1:
7859                        yComponent = 1;
7860                        break;
7861                }
7862                y = Math.round((1 - self.hsv[yComponent]) * (colorDropper.images.sld[1] - 1));
7863                colorDropper.picker.sldM.style.backgroundPosition =
7864                    '0 ' + (self.pickerFace + self.pickerInset + y - Math.floor(colorDropper.images.arrow[1] / 2)) + 'px';
7865            }
7866
7867            function isPickerOwner() {
7868                return colorDropper.picker && colorDropper.picker.owner === self;
7869            }
7870
7871            function blurTarget() {
7872                if (valueElement === target) {
7873                    self.importColor();
7874                }
7875            }
7876
7877            function blurValue() {
7878                if (valueElement !== target) {
7879                    self.importColor();
7880                }
7881            }
7882
7883            function setPad(e) {
7884                var mpos = colorDropper.getRelMousePos(e),
7885                    x = mpos.x - self.pickerFace - self.pickerInset,
7886                    y = mpos.y - self.pickerFace - self.pickerInset;
7887                switch (modeID) {
7888                    case 0:
7889                        self.fromHSV(x * (6 / (colorDropper.images.pad[0] - 1)), 1 - y / (colorDropper.images.pad[1] - 1), null, leaveSld);
7890                        break;
7891                    case 1:
7892                        self.fromHSV(x * (6 / (colorDropper.images.pad[0] - 1)), null, 1 - y / (colorDropper.images.pad[1] - 1), leaveSld);
7893                        break;
7894                }
7895            }
7896
7897            function setSld(e) {
7898                var mpos = colorDropper.getRelMousePos(e),
7899                    y = mpos.y - self.pickerFace - self.pickerInset;
7900                switch (modeID) {
7901                    case 0:
7902                        self.fromHSV(null, null, 1 - y / (colorDropper.images.sld[1] - 1), leavePad);
7903                        break;
7904                    case 1:
7905                        self.fromHSV(null, 1 - y / (colorDropper.images.sld[1] - 1), null, leavePad);
7906                        break;
7907                }
7908            }
7909
7910            function dispatchImmediateChange() {
7911                if (self.onImmediateChange) {
7912                    var callback;
7913                    if (typeof self.onImmediateChange === 'string') {
7914                        callback = new Function(self.onImmediateChange);
7915                    } else {
7916                        callback = self.onImmediateChange;
7917                    }
7918                    callback.call(self);
7919                }
7920            }
7921
7922            if (valueElement) {
7923                colorDropper.addEvent(valueElement, 'keyup', updateFieldEventHandler);
7924                colorDropper.addEvent(valueElement, 'input', updateFieldEventHandler);
7925                colorDropper.addEvent(valueElement, 'blur', blurValue);
7926                valueElement.setAttribute('autocomplete', 'off');
7927            }
7928
7929            this.importColor();
7930        }
7931    };
7932    GB.colorDropper = colorDropper.color;
7933})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.