PageSourceSearch

https://www.hanbit.co.kr/lib/cheditor/cheditor.js

js hanbit.co.kr collected 2026-10-02 03:53:40 UTC 287,644 bytes, 7,960 lines download raw bytes

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

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.