PageSourceSearch

http://e-sens.co.kr/cheditor/cheditor.js

js e-sens.co.kr collected 2026-10-06 13:50:14 UTC 286,961 bytes, 7,953 lines download raw bytes

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

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.