PageSourceSearch

https://c-on.co.kr/weven_service/asset/js/bm2/control/Dom.js

js c-on.co.kr collected 2026-10-05 22:22:04 UTC 34,419 bytes, 873 lines download raw bytes

1/**
2 * User: kjh
3 * Date: 13. 6. 27
4 * Time: 오후 8:09
5 * 아래의 소스는 WEVEN에 저작권이 있으므로 무단 사용 및 재 배포를 금합니다.
6 */
7
8bm.__foo = document.createElement('div');
9
10bm.html = function( str ) {
11    this.__foo.innerHTML = str;
12    var el = this.__foo.children[0].cloneNode(true);
13    this.__foo.removeChild( this.__foo.children[0] );
14    return el;
15}
16
17bm.addChild = function( element, parent ) { parent.insertBefore( element, parent.childNodes[0] ); }
18bm.addChildAt = function( element, parent, index ){ parent.insertBefore( element, parent.childNodes[index] ); }
19
20
21
22bm.dom = {
23    htmlParsingReplacer: function (value) {
24        return value ? String(value).replace(/<\/br>/gi, '') : "";
25    }
26
27    ,listInterpreter : function( data, template, parentContainer, type ){
28        var len = data.length;
29        for( var i=0; i<len; i++ ){
30            var el = $( this.convertVariables( data[i], template ) );
31            this.checkAutoForm( data[i], el );
32            if( el.length > 0 ) el.appendTo( parentContainer).show();
33        }
34    }
35
36    ,singleInterpreter : function( data, template, parentContainer, isEmptyView, templateAppenIndex ){
37        // templateAppenIndex : 렌더링된 template 이 append 될 index
38        if(!template) return null;
39
40        var el = $( this.convertVariables( data, template, templateAppenIndex ) ); // 변수변환
41
42        if( el.length && el.length > 0 ) {
43            this.checkAutoForm( data, el ); // binding
44            el.appendTo( parentContainer).show(); // add child
45            if(templateAppenIndex != undefined && templateAppenIndex > -1){
46                el.insertBefore(parentContainer.children().eq(templateAppenIndex));
47            }else{
48                el.appendTo( parentContainer).show(); // add child
49            }
50        }
51        else if( isEmptyView ){
52            el = $( this.convertVariables( {}, template, templateAppenIndex ) ); // 변수제거
53            if(templateAppenIndex != undefined && templateAppenIndex > -1){
54                el.insertBefore(parentContainer.children().eq(templateAppenIndex));
55            }else{
56                el.appendTo( parentContainer).show(); // add child
57            }
58        }
59
60        return el;
61    }
62
63    ,checkAutoForm : function( o, el ){
64        el.find('[binding]').each(function(){
65
66            var key = $(this).attr( "binding" );
67            var name;
68
69            if( o[key] === 0 || o[key] ){
70                if( this.type.indexOf( "text") > -1 ){
71                    $(this).val( o[key] );
72                }
73                else if( this.type.indexOf( "radio") > -1 ){
74                    name = $(this).attr( 'name' );
75                    $(el).find("input[name="+name+"]:radio[value='"+o[key]+"']").attr('checked', 'checked');
76                }
77                else if( this.type.indexOf( "checkbox") > -1 ){
78                    name = $(this).attr( 'name' );
79                    $(el).find("input[name='"+name+"']:checkbox").each(function(){
80                        if( o[key].indexOf( this.value ) > -1 ){
81                            $(this).attr('checked', 'checked');
82                        }else{
83                            // 체크박스 체크상태 리무브
84                            //                            $(this).attr('checked', false);
85                        }
86                    });
87                }
88                else if( this.type.indexOf( "select" ) > -1 ){
89                    this.value = o[key];
90                }
91            }
92        });
93    }
94
95    // remove
96    ,removeVariables : function( template ){
97        while( template.indexOf("{{") > -1 ){
98            var currIdx =  template.indexOf("{{");
99            var key = template.slice( currIdx + 2 , template.indexOf("}}", currIdx) );
100            template = template.replace( "{{"+key+"}}", "" );
101        }
102        return template;
103    }
104
105    // auto setting
106    , convertVariables: function ( o, template, index ) {
107
108
109        // 전부 소문자로 변환
110        var originObject = o;
111        o = bm.object.toKeyLowerCase( o );
112
113        // 입력된 파라미터가 Dom 이라면 string 으로 html 로 전환
114        template = (template instanceof Element) ? template.outerHTML : template;
115
116        // data-wv-print 제거
117        while( template.indexOf( "data-wv-print=") > -1 ){
118            var currIdx =  template.indexOf("data-wv-print=");
119            var lastIdx = template.indexOf("\"", currIdx + 15 )+1;
120            var currentPrint = template.slice( currIdx , lastIdx );
121
122            template = template.replace( currentPrint, template.slice( currIdx + 15, lastIdx - 1 ) );
123        }
124
125
126        if( o == null ) return;
127
128        // 순번 기록
129        o.index = index;
130
131        // key : replacePattern
132        // value : script
133        var scriptList = {};
134        var scriptStartIndex, scriptLastIndex;
135        var i = 0;
136        var maxCount;
137        maxCount = 1000;
138        while( template.indexOf("{{") > -1 ){
139            if(--maxCount == 0){
140                throw new Error("최대 반복 횟수를 초과하였습니다.");
141            }
142            var currIdx =  template.indexOf("{{");
143            var key = template.slice( currIdx + 2 , template.indexOf("}}", currIdx) );
144            var isRadio, compareValue, value;
145            var tempKey = key;
146
147            if( tempKey.indexOf( "::" ) > -1 ){
148                tempKey = bm.string.trim( tempKey.slice( 0, tempKey.indexOf("::") ) );
149            }
150
151            if( tempKey.indexOf( "textarea:" ) == 0 ){
152                // 텍스트 에어리어일 경우 <br/> 넣지 않음
153                var tempKey2 = tempKey.slice( 9 , tempKey.length );
154                value = this.getWvParseValue( tempKey2, o );
155                template = template.replace("{{"+key+"}}", () => this.htmlParsingReplacer(value));
156
157            } else if( tempKey.indexOf( "src:" ) == 0 ){
158
159                var tempKey2 = tempKey.slice( 4 , tempKey.length );
160                var prefixStr = "", postfixStr="";
161                if( tempKey2.indexOf( "+" ) > 0 ){
162                    prefixStr = bm.string.trim( tempKey2.slice( 0, tempKey2.indexOf( "+" ) ) );
163                    tempKey2 = bm.string.trim( tempKey2.slice( prefixStr.length+1, tempKey2.length ) );
164
165                    if( tempKey2.indexOf("+") > 0 ){
166                        postfixStr = bm.string.trim( tempKey2.slice( tempKey2.indexOf("+")+1, tempKey2.length ) );
167                        tempKey2 = bm.string.trim( tempKey2.slice( 0, tempKey2.indexOf("+") ) );
168                    }
169                }
170
171                value = this.getWvParseValue( tempKey2, o );
172                template = template.replace( "{{"+key+"}}" , () => {
173                    return value ? "src='"+prefixStr+this.htmlParsingReplacer(value)+postfixStr+"'" : "";
174                });
175
176            } else if ( tempKey.indexOf( "-&gt;" ) > -1 || tempKey.indexOf( "->" ) > -1 ){
177
178                // -> 는 속성의 키값 검색으로 처리.
179                template = template.replace( "{{"+key+"}}" , this.getWvParseValue( key, o ) );
180            } else if ( tempKey.indexOf( "comma:" ) == 0 ){
181
182                var tempKey2 = tempKey.slice( 6 , tempKey.length );
183                value = this.getWvParseValue( tempKey2, o );
184                value = value ? bm.string.comma( value ) : "";
185
186                template = template.replace( "{{"+key+"}}" , () => this.htmlParsingReplacer(value) );
187
188            } else if ( tempKey.indexOf( "date:" ) == 0 ){
189
190                var tempKey2 = tempKey.slice( 5 , tempKey.length );
191                var tempKeyArr = tempKey2.split("|");
192
193                value = this.getWvParseValue( tempKeyArr[0], o );
194                if( value ){
195                    function parseDate(strDate) {
196                        var _strDate = strDate;
197                        var _dateObj = new Date(_strDate);
198                        if (_dateObj.toString() == 'Invalid Date') {
199                            _strDate = _strDate.split('.').join('-');
200                            _dateObj = new Date(_strDate);
201                        }
202                        if (_dateObj.toString() == 'Invalid Date') {
203                            var _parts = _strDate.split(' ');
204
205                            var _dateParts = _parts[0];
206                            _dateObj = new Date(_dateParts);
207
208                            if (_parts.length > 1) {
209                                var _timeParts = _parts[1].split(':');
210                                _dateObj.setHours(_timeParts[0]);
211                                _dateObj.setMinutes(_timeParts[1]);
212                                if (_timeParts.length > 2) {
213                                    _dateObj.setSeconds(_timeParts[2]);
214                                }
215                            }
216                        }
217
218                        return _dateObj;
219                    }
220                    value = new Date( parseDate(value) );
221                    value = new Date( value );
222                    value = ( function date2str(x, y) {
223                        var z = {
224                            m: x.getMonth() + 1,
225                            d: x.getDate(),
226                            H: x.getHours(),
227                            M: x.getMinutes(),
228                            S: x.getSeconds()
229                        };
230
231                        y = y.replace(/(m+|d+|H+|M+|S+)/g, function(v) {
232                            return ((v.length > 1 ? "0" : "") + z[v.slice(-1)]).slice(-2)
233                        });
234
235                        return y.replace(/(y+)/g, function(v) {
236                            return x.getFullYear().toString().slice(-v.length)
237                        });
238                    })( value, tempKeyArr[1] );
239                }else{
240                    value = "";
241                }
242
243                template = template.replace( "{{"+key+"}}" , () => this.htmlParsingReplacer(value) );
244
245            } else if ( tempKey.indexOf( "formatter:" ) == 0 ){ // 함수 호출하기 ex) {{KEY|function}}
245 key | 함수명
246
247                var tempKey2 = tempKey.slice( 10 , tempKey.length );
248                var fnString = null;
249                if( tempKey.indexOf("|") > -1 ){ // 구분자가 있을경우와 없을경우로 나눔
250                    var tempKeyArr = tempKey2.split("|");
251                    if( tempKeyArr[1] ) fnString = tempKeyArr[1];
252                    tempKey2 = tempKeyArr[0];
253
254                    var value2;
255                    value = this.getWvParseValue( tempKey2, o );
256                    if( fnString && fnString !== "" ){
257                        if( fnString.indexOf(".") > 0 ){ // Object function 일경우
258                            if( $.isFunction( new Function('return '+fnString) ) ){
259                                var fn = new Function('a', 'b', 'c', 'd', 'e', 'return '+fnString+ '.call( window, a, b, c, d, e )' );
260                                value2 = fn( index, tempKey2, value, originObject, $(template)[0] );
261                            }
262                        }else{
263                            var fn = window[fnString];
264                            if( typeof fn === "function" ){ // Global Function 일 경우
265                                value2 = fn.call( window, index, tempKey2, value, originObject, $(template)[0] ); // data, KEY 에 대한 값, keyString
266                            }
267                        }
268                    }
269                    if( value2 !== null && value2 !== undefined ) value = value2;
270                    template = template.replace( "{{"+key+"}}" , () => this.htmlParsingReplacer(value) );
271                } else { // 구분자가 없을 경우 index, data, row 리턴
272                    fnString = tempKey.slice( 10 , tempKey.length );
273                    value = "";
274                    if( fnString && fnString !== "" ){
275                        if( fnString.indexOf(".") > 0 ){ // Object function 일경우
276                            if( $.isFunction( new Function('return '+fnString) ) ){
277                                var fn = new Function('a', 'b', 'c', 'return '+fnString+ '.call( window, a, b, c )' );
278                                value = fn( index, originObject, $(template)[0] );
279                            }
280                        }else{
281                            var fn = window[fnString];
282                            if( typeof fn === "function" ){ // Global Function 일 경우
283                                value = fn.call( window, index, originObject, $(template)[0] ); // data, KEY 에 대한 값, keyString
284                            }
285                        }
286                    }
287                    template = template.replace( "{{"+key+"}}" , () => this.htmlParsingReplacer(value) );
288                }
289
290            } else {
291                // 나머지..
292                if( o[tempKey] ) {
293                    if (Object.prototype.toString.call(o[tempKey]) === "[object String]" ){
294//                        o[tempKey] = o[tempKey].replace(/\n|\r/g, "<br/>");
295                        o[tempKey] = o[tempKey].replace(/(?:\r\n|\r|\n)/g, "<br/>"); //  개행 정규식 수정 150518
296                    }
297                }
298                var _v = this.getWvParseValue( key, o );
299
300                if( window.version != -1 && window.version <= 8 ){
301                    var preTxt = template.slice( currIdx-6, currIdx );
302                    if( preTxt == "value=" ){
303                        _v = '"'+_v+'"';
304                    }
305                }
306
307                // kjh 2017.09.15
308                _v = _v === undefined || _v === null ? "" : _v;
309                //template = template.replace( "{{"+key+"}}", o[tempKey] == undefined ? "" : _v );
310                template = template.replace("{{"+key+"}}", () => this.htmlParsingReplacer(_v));
311
312            }
313        }
314
315        // script 에도 interpreter 처리가 필요 함
316        //maxCount = 1000;
317        //while( template.indexOf("<script") > -1 ){
318        //	if(--maxCount == 0){
319        //		throw new Error("최대 반복 횟수를 초과하였습니다.");
320        //	}
321        //	scriptStartIndex = template.indexOf("<script");
322        //	scriptLastIndex = template.indexOf("</script>", scriptStartIndex )+"</script>".length;
323        //	var scriptPosition = parseInt(Math.random()*1000)+"_"+(i++);
324        //	var scriptPositionTempDom = "<div data-script-position='"+scriptPosition+"'></div>";
325        //	var scriptNode = template.slice(scriptStartIndex, scriptLastIndex );
326        //	scriptList[scriptPosition] = scriptNode;
327        //	template = template.substring( 0, scriptStartIndex ) + scriptPositionTempDom + template.substring( scriptLastIndex );
328        //}
329
330        // 스크립트가 있을 경우 치환때문에 실행
331        //if( template.indexOf( "script") > -1 ){
332        //    var $template = $(template);
333        //    if( $template.length > 0 ){
334        //        this.replaceScriptNode($template, scriptList);
335        //        return $template;
336        //    }
337        //}
338
339        return template;
340
341    }
342
343    ,getWvParseValue : function( key, o ){
344        var originKey = key;
345        key = key.toLowerCase();
346        var val, originTempKey = originKey, tempKey = key;
347
348        var isN2br = false;
349        if( key.indexOf( "n2br:") == 0 ){
350            tempKey = key = key.substring( 5 );
351            originTempKey = originKey = originTempKey.substring(5);
352            isN2br = true;
353        }
354
355
356
357        if( key.indexOf( "::" ) > -1 ){
358            // 다항 switch case 처리문
359            var compareList, realValList, splitVal;
360            key = bm.string.trim( tempKey.slice( 0, tempKey.indexOf("::") ) );
361            val = bm.string.trim( originTempKey.slice( originTempKey.indexOf("::")+2, originTempKey.length ) );
362            splitVal = val.split("?");
363
364            compareList = splitVal[0].split("|");
365            realValList = splitVal[1].split("|");
366
367            compareList = bm.string.trimList( compareList );
368            realValList = bm.string.trimList( realValList );
369
370            var len = compareList.length;
371            while( len-- ){
372                if( !isNaN(parseFloat( compareList[len] )) ){
373                    compareList[len] = parseFloat(compareList[len]);
374                }
375            }
376
377            var oVal;
378            if( key.indexOf( "-&gt;" ) > -1 || key.indexOf( "->" ) > -1 ){
379                // -> 로 키검색 처리.
380                var keyList = key.indexOf( "-&gt;" ) > -1 ? key.split("-&gt;") : key.split("->");
381                var originKeyList = originKey.indexOf( "-&gt;" ) > -1 ? originKey.split("-&gt;") : originKey.split("->");
382                var len = keyList.length;
383                oVal = o;
384                for( var i=0; i<len; i++ ){
385                    var prevOVal = oVal;
386                    oVal = oVal[ bm.string.trim( keyList[i] ) ];
387                    if( !oVal ){
388                        oVal = prevOVal[ bm.string.trim( originKeyList[i] ) ];
389                        if( !oVal ) break;
390                    }
391                }
392                if( isN2br && oVal ){
393                    if (Object.prototype.toString.call(oVal) === "[object String]" ){
394                        oVal = oVal.replace(/(?:\r\n|\r|\n)/g, "<br/>");
395                    }
396                }
397
398            }else{
399                oVal = o[key];
400            }
401
402            // 비교를 위해 문자열로 치환함.
403            if( Object.prototype.toString.call( oVal ) === "[object Boolean]" ){
404                if( oVal ) oVal = "true";
405                else oVal = "false";
406            }
406else if( oVal === null ){ // value값이 null 일때 문자열로 치환
407                oVal = "null";
408            }
409            var realValIndex = compareList.indexOf( oVal );
410            if( oVal && realValIndex < 0 ){
411                if( typeof oVal === "string" ){
412                    var lowerVal = oVal.toLowerCase();
413                    realValIndex = compareList.indexOf( lowerVal );
414                }
415            }
416            val = realValList[ realValIndex ];
417
418            if( val !== 0 && !val ){
419                if( val == undefined && !isNaN(parseFloat( oVal )) ){
420                    val = realValList[ compareList.indexOf( parseFloat( oVal ) ) ];
421                }
422                if( val == undefined && compareList.indexOf( "~" ) > -1 && oVal !== undefined ){ // 키가 없진 않은데, ~ 가 있다면..  ~ 의 index에 해당하는 값으로 매핑.
423                    val = realValList[ compareList.indexOf( "~" ) ];
424                }
425                if (val == undefined && splitVal[2] ){ // 여전히 val 은 undefined 이고, ? 가 하나 더있는,,, undefined 용 값이 있었다면.. ( 즉, 키가 없는 경우 대비를 했다면 )
426                    if( oVal ) val = oVal; // 그런데 object 에 값이 있었다면, 값으로 반환
427                    else val = splitVal[2]; // 값도 없는 완전 undefined 라면, 대응되는 값으로 반환.
428                }
429                if (val == undefined && compareList.indexOf( "~" ) > -1 ){ // 여전히 val 은 undefined 이고, ~ 아무거나 가 있으면
430                    val = realValList[ compareList.indexOf( "~" ) ];
431                }
432                if (val == undefined ){ // 만약 검색에 걸리는 값이 없으면
433                    val = oVal; // 원래 key 로 값을 찾아 반환
434                    if( val == undefined ) val = ""; // 그조차 없으면 빈값 반환
435                }
436            }
437
438        }else if( key.indexOf( "-&gt;" ) > -1 || key.indexOf( "->" ) > -1 ){
439            // -> 로 키검색 처리.
440            var keyList = key.indexOf( "-&gt;" ) > -1 ? key.split("-&gt;") : key.split("->");
441            var len = keyList.length;
442            val = o;
443            for( var i=0; i<len; i++ ){
444                val = val[ bm.string.trim( keyList[i] ) ];
445                if( !val ) break;
446            }
447
448            if( isN2br && val ){
449                if (Object.prototype.toString.call(val) === "[object String]" ){
450                    val = val.replace(/(?:\r\n|\r|\n)/g, "<br/>");
451                }
452            }
453
454        }else{
455            // 기타
456            val = o[$.trim(key)];
457        }
458
459
460        return ( val == undefined || val == null ) ? "" : val;
461    }
462
463
464
465    /**
466     * jquery 의 $(element).offset().left 가 margin 을 연산에서 제외하거나, width() 가 padding 을 연산에서 제외하므로, 이를 모두 더한 값을 반환.
467     * @param element
468     * @param prop
469     * @returns {*}
470     */
471    ,getOuterPosition : function ( element, prop ){
472
473        if( element.length && element.length > 0 ) element = element[0];
474
475        var styleProp;
476        switch (prop ){
477            case "left" : styleProp = "marginLeft"; prop = "left"; break;
478            case "right" : styleProp = "marginRight"; prop = "right"; break;
479            case "top" : styleProp = "marginTop"; prop = "top"; break;
480            case "bottom" : styleProp = "marginBottom"; prop = "bottom"; break;
481            case "innerLeft" : styleProp = "paddingLeft"; prop = "left"; break;
482            case "innerRight" : styleProp = "paddingRight"; prop = "right"; break;
483            case "innerTop" : styleProp = "paddingLeft"; prop = "top"; break;
484            case "innerBottom" : styleProp = "paddingRight"; prop = "bottom"; break;
485        }
486
487        var currentValue;
488
489        // jquery 에 의한 offset().left 는 padding 과 margin 사이의 포인트를 반환한다. 그러므로 real left 는 marginLeft 만 추가 연산해주면 되지만, real right 는 오른쪽 paddingRight 와 marginRight 를 함께 연산해줘야 한다.
490        if( prop == "left" ){
491            var currentMarginLeft = bm.getStyleInt( element, "marginLeft");
492            currentValue = $(element).offset()["left"] - currentMarginLeft;
493        }else if( prop == "right" ){
494            var currentPaddingRight = bm.getStyleInt( element, "paddingRight") || 0;
495            var currentMarginRight = bm.getStyleInt( element, "marginRight") || 0;
496            currentValue = $(element).offset()["left"] + $(element).width() + currentPaddingRight + currentMarginRight;
497        }else if( prop == "top" ){
498            var currentMarginTop = bm.getStyleInt( element, "marginTop");
499            currentValue = $(element).offset()["top"] - currentMarginTop;
500        }else if( prop == "bottom" ){
501            var currentPaddingBottom = bm.getStyleInt( element, "paddingBottom") || 0;
502            var currentMarginBottom= bm.getStyleInt( element, "marginBottom") || 0;
503            currentValue = $(element).offset()["top"] + $(element).height() + currentPaddingBottom + currentMarginBottom;
504        }
505
506        return currentValue;
507    }
508
509
510
511
512    ,getValueByFormElement : function( el, searchContainer ){
513        var value, name;
514        //el = el.length && el.context ? el[0] : el;
515        //el.context 가 undefined 가 나와서 아래처럼 수정 [chojw]
516        el = el instanceof jQuery && el.length > 0 ? el[0] : el;
517        if( el.type.indexOf( "text") > -1
518            || el.type.indexOf("number") > -1
519            || el.type.indexOf("hidden") > -1 ){
520            value = $(el).val();
521        }else if( el.type.indexOf( "radio") > -1 ){
522            name = $(el).attr('name');
523            value = $( searchContainer ).find( "input[name='"+name+"']:checked").val();
524        }else if( el.type.indexOf( "select") > -1 ){
525            value = $(el).val();
526        }else if( el.type.indexOf( "checkbox" ) > -1 ) {
527            name = $(el).attr('name');
528            if( $("[name='"+name+"']:checked").length > 0 ){
529                value = "";
530                $("[name='"+name+"']:checked").each( function(){
531                    if( value != "" ) value += ",";
532                    value += $(this).val();
533                })
534            }else{
535                // 기본값이 설정되어 있을 경우
536                if( $(el).attr( "data-wv-nocheck-value" ) !== undefined ){
537                    value = $(el).attr( "data-wv-nocheck-value" );
538                }
539            }
540        }
541        return value;
542    }
543
544
545
546    ,__blockSchema : null
547
548    ,getBlockSchema : function(){
549
550        if( this.__blockSchema == null ){
551            this.__blockSchema = ( "center dir isindex noframes " +
552            "address blockquote div dl fieldset form h1 h2 h3 h4 h5 h6 hr menu ol p pre table ul li dt dd body " +
553            "table td " +
554            "article aside details dialog figure header footer hgroup section nav" ).split(" ");
555        }
556
557        return this.__blockSchema;
558    }
559
560    ,__inlineSchema : null
561
562    ,getInlineSchema : function(){
563        if( this.__inlineSchema == null ){
564            this.__inlineSchema = ( "a abbr b bdo br button cite code del dfn em embed i iframe img input ins kbd " +
565            "label map noscript object q s samp script select small span strong sub sup textarea u var #text #comment " +
566            "audio canvas command datalist mark meter output picture progress time wbr video ruby bdi keygen font" ).split(" ");
567        }
568
569        return this.__inlineSchema;
570    }
571
572    ,isBlock : function( tagOrElement ){
573        var tag;
574        if( bm.type.isString( tagOrElement ) ) tag = tagOrElement;
575        else tag = tagOrElement.nodeName;
576
577        tag = tag.toLocaleLowerCase();
578        var schema = this.getBlockSchema();
579        if( schema.indexOf( tag ) == -1  ){
580            return false;
581        }else{
582            return true;
583        }
584    }
585
586    ,isInline : function( tagOrElement ){
587        var tag;
588        if( bm.type.isString( tagOrElement ) ) tag = tagOrElement;
589        else tag = tagOrElement.nodeName;
590
591        tag = tag.toLocaleLowerCase();
592        var schema = this.getInlineSchema();
593        if( schema.indexOf( tag ) == -1  ){
594            return false;
595        }else{
596            return true;
597        }
598    }
599
600    ,isElement : function( element ){
601        if( element.nodeType !== 1 ){
602            return false;
603        }else{
604            return true;
605        }
606    }
607
608    ,isEmptyNode : function( node ){
609        var t = node.nodeType;
610        return (node.nodeType == 3 && $.trim( node.data ) == "") || t == 4 || t == 8 ; // Text, CDataSection or Comment
611    }
612
613    ,checkEmptyThenRemove : function( nodeOrElement ){
614        var node = nodeOrElement.nodeType == 3 ? nodeOrElement : nodeOrElement.firstChild;
615        if( this.isEmptyNode( node ) ) $(nodeOrElement).remove();
616    }
617
618
619    ,deleteData : function( node, startIndex, endIndex ){
620        var childNode = node.nodeType == 3 ? this : node.firstChild;
621        if( !childNode || !childNode.nodeValue ) return;
622
623        var str = childNode.nodeValue;
624        str = str.substr( 0, startIndex ) + str.substr( endIndex , str.length );
625        childNode.nodeValue = str;
626    }
627
628    ,splitNodeAt : function (node, index) {
629        var newNode = $(node).clone()[0];
630        this.deleteData( newNode, 0, index );
631
632        var childNode = node.nodeType == 3 ? this : node.firstChild;
633        if( childNode && childNode.nodeValue ){
634            this.deleteData( node, index, childNode.nodeValue.length );
635        }
636
637        $(node).after( newNode );
638
639        return [node,newNode];
640    }
641
642
643    ,getParent : function( node ){
644        if( node.parentNode ) return node.parentNode;
645        else{
646            return node.ownerDocument.activeElement;
647        }
648    }
649
650    ,findParentUntilElement : function(node){
651        return this.findParentUntil( "element", node );
652    }
653
654    ,findParentUntilInline: function(node){
655        return this.findParentUntil( "inline", node );
656    }
657
658    ,findParentUntilBlock : function(node){
659        return this.findParentUntil( "block", node );
660    }
661
662
663    /**
664     * 최초의 type 요소가 나올때까지 parent 탐색
665     * @param node
666     * @returns {*}
667     */
668    ,findParentUntil : function( type, node ){
669
670        var body = document.body;
671        var currentNode = node;
672
673        var compareFn;
674        switch( type ){
675            case "block" : compareFn = this.isBlock; break;
676            case "inline" : compareFn = this.isInline; break;
677            case "element" : compareFn = this.isElement; break;
678        }
679
680        while( compareFn.call( this, currentNode) == false ){
681            if(!currentNode.parentNode) {
682                return null;
683            }
684            currentNode = currentNode.parentNode;
685
686            if( currentNode === body ) {
687                currentNode = body;
688                break;
689            }
690        }
691
692        return currentNode;
693    }
694
695    /**
696     * 태그 변경.
697     * @param element
698     * @param tagName
699     * @param attributeCopy 속성 변경 , 기본값 true
700     */
701    ,replaceTag : function( element, tagName, attributeCopy ){
702
703        if( attributeCopy === undefined ) attributeCopy = true;
704
705        var to = bm.html( "<"+tagName+"></"+tagName+">" );
706        $(element).contents().each( function(){
707            to.append( this );
708        });
709
710        if( attributeCopy === undefined || attributeCopy ){
711            this.copyAttribute( element, to );
712        }
713
714        $(element).before( to );
715        $(element).remove();
716
717        return to;
718    }
719
720    /**
721     * 싸고있는 엘리먼트를 벗겨내는 함수
722     * @param element
723     * @param selector - 없을 경우 엘리먼트의 가장 최상단 엘리먼트를 unWrap한다.
724     */
725    ,unWrap : function (element, selector) {
726
727        var targetElement;
728        if( selector ){
729            targetElement = $(element).find( selector );
730        }else{
731            targetElement = $( element );
732        }
733
734        targetElement.children().each( function(){
735            targetElement.after( this );
736        });
737        targetElement.remove();
738
739        return element;
740    }
741
742
743    ,wrapOuter : function( element, tag ){
744        var wrapper = $(tag).insertBefore( element );
745        wrapper.prepend( element );
746        return wrapper[0];
747    }
748
749    ,removeTagOnChild : function( element, tag ){
750        var list = $(element).find(tag);
751
752        list.each( function(){
753            var children = this.children;
754            var len = children.length;
755            for( var i=0; i<len; i++ ){
756                $(this).before( children[0] );
757            }
758
759            $(this).remove();
760        })
761    }
762
763    ,removeTagOnParent : function( element, tag ){
764        var el = $(element).closest(tag)[0];
765        var children, len;
766        if( el ){
767            children = el.children;
768            len = children.length;
769            for( var i=0; i<len; i++ ){
770                $(el).before( children[0] );
771            }
772        }
773
774        $(el).remove();
775    }
776
777    ,copyAttribute : function( from, to ){
778
779        $.each(from.attributes, function() {
780            $(to).attr(this.name, this.value);
781        } );
782    }
783
784    ,replaceScriptNode : function($template, scriptList){
785        // script 노드는 jquery 로 append 시 제외되므로 임시로 생성된 div 위치에 치환시킨다.
786        for(var scriptPosition in scriptList){
787            var div = $template.find("[data-script-position='"+scriptPosition+"']")[0];
788            if(div == null) continue;
789
790            var scriptSource = scriptList[scriptPosition];
791            scriptSource = scriptSource.substring(scriptSource.indexOf(">")+1, scriptSource.lastIndexOf("</script"));
792
793            // append
794            var scriptElement = document.createElement('script');
795            scriptElement.setAttribute('type', 'text/javascript');
796            scriptElement.text = scriptSource;
797
798            // div 치환
799            var parentElement = div.parentElement;
800            parentElement.replaceChild(scriptElement, div);
801        }
802    }
803
804
805    ,getScriptContent : function (source) {
806
807
808        var codeList = [];
809        var srcList = [];
810
811        var startIndex, endIndex, src, preTag, postTag;
812        while( 1 ){
813            startIndex = source.indexOf( "<script" );
814
815            if( startIndex > -1 ){
816                preTag = source.slice( startIndex , source.indexOf( ">", startIndex ) );
817
818                if( preTag.indexOf("src") > -1 ){
819                    preTag = preTag.replace( / /g, "" );
820
821                    if( preTag.indexOf("src=\"") > -1 ){
822
823                    }else if( preTag.indexOf("src=\'") > -1 ){
824
825                    }
826
827                    src = preTag.slice()
828                }
829
830
831            }else{
832                break;
833            }
834        }
835
836    }
837
838    ,insertScript : function (code, src, targetWindow ) {
839
840        targetWindow = targetWindow || window;
841
842        var head = targetWindow.document.getElementsByTagName('head')[0];
843        var scriptElement = targetWindow.document.createElement('script');
844        scriptElement.setAttribute('type', 'text/javascript');
845        if( src ){
846            scriptElement.src = src;
847        }
848        if( code ){
849            scriptElement.text = code;
850        }
851
852        head.appendChild(scriptElement);
853        head.removeChild(scriptElement);
854
855    }
856
857    /**
858     * 해당 노드간의 상대좌표값을 구한다
859     * @param standardEl 기준노드
860     * @param targetEl   타겟노드
861     */
862    , getRelativeCoordinates : (standardEl, targetEl) => {
863        var rect1 = standardEl.getBoundingClientRect();
864        var rect2 = targetEl.getBoundingClientRect();
865        var scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
866        var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
867        
868        return {
869          top: rect2.top - rect1.top + scrollTop,
870          left: rect2.left - rect1.left + scrollLeft
871        };
872      }
873}

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.