/* * */ /* * @(#) du_base.js * build version : 0.9.0 $Revision: 13634 $ * * Copyright ⓒ LG CNS, Inc. All rights reserved. * * Do Not Erase This Comment!!! (이 주석문을 지우지 말것) * * DevOn Rich UI Framework를 실제 프로젝트에 사용하는 경우 DevOn Rich UI 개발담당자에게 * 프로젝트 정식명칭, 담당자 연락처(Email)등을 mail로 알려야 한다. * * 소스를 변경하여 사용하는 경우 DevOn Rich UI 개발담당자에게 * 변경된 소스 전체와 변경된 사항을 알려야 한다. * 저작자는 제공된 소스가 유용하다고 판단되는 경우 해당 사항을 반영할 수 있다. * 중요한 Idea를 제공하였다고 판단되는 경우 협의하에 저자 List에 반영할 수 있다. * * (주의!) 원저자의 허락없이 재배포 할 수 없으며 * LG CNS 외부로의 유출을 하여서는 안 된다. */ /** * DU 객체는 네임스페이스, 상속, 로깅을 포함하는 utility이다. * @module core * @namespace * @title DU Global */ if (typeof DU == "undefined" || !DU) { /** * DU는 global namespace object 이다.. * 만약 DU가 이미 정의되어 있으면, 기존의 DU object는 정의된 namespace들이 보존되도록 * overwrite 않을 것이다. * @class DU * @static */ var DU = {}; } (function(){ var userAgent = navigator.userAgent.toLowerCase(); // API 작성기때문에 주석을 가장 아래로 옮겼음. DU.browser = { version: (userAgent.match( /.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/ ) || [])[1], opera: /opera/.test( userAgent ), chrome:/chrome/.test( userAgent ), webkit:/webkit/.test(userAgent), safari: !/chrome/.test( userAgent ) && /safari/.test( userAgent ), safari2 : /safari/.test( userAgent ) && /applewebkit\/4/.test( userAgent ), safari3 : /safari/.test( userAgent ) && /version\/3/.test( userAgent ), safari4 : /safari/.test( userAgent ) && /version\/4/.test( userAgent ), safari5 : /safari/.test( userAgent ) && /version\/5/.test( userAgent ), msie: /msie/.test( userAgent ) && !/opera/.test( userAgent ), msie6: /msie/.test( userAgent ) && /msie 6/.test( userAgent ), msie7: /msie/.test( userAgent ) && /msie 7/.test( userAgent ), msie8: /msie/.test( userAgent ) && /msie 8/.test( userAgent ), mozilla: /mozilla/.test( userAgent ) && !/(compatible|webkit)/.test( userAgent ), gecko : !/webkit/.test(userAgent) && /gecko/.test(userAgent), gecko2 : !/webkit/.test(userAgent) && /gecko/.test(userAgent) && /rv:1\.8/.test(userAgent), gecko3 : !/webkit/.test(userAgent) && /gecko/.test(userAgent) && /rv:1\.9/.test(userAgent), iPhone: false // 소스 추가해야함. }; DU.platform = { window: /window/.test( userAgent ) || /win32/.test( userAgent ), mac : /macintosh/.test( userAgent ), air : /adobeair/.test( userAgent ), linux : /linux/.test( userAgent ) }; // remove css image flicker if(DU.browser.msie6){ try{ document.execCommand("BackgroundImageCache", false, true); }catch(e){} } /** * @description https가 적용되었는지 확인하는 속성 * @property isSecure * @public * @static * @type {Boolean} */ DU.isSecure = (window.location.href.toLowerCase().indexOf("https") === 0) ? true : false; /** * @description css의 compatMode가 CSS1Compat인지 확인하는 속성 * @property isStrict * @public * @static * @type {Boolean} */ DU.isStrict = document.compatMode == "CSS1Compat"; /** * @description Border가 box 모델이 적용되는지 확인하는 속성 * @property isBorderBox * @public * @static * @type {Boolean} */ DU.isBorderBox = DU.browser.msie && !DU.isStrict; /** * namespace를 지정하고 만약 존재하지 않는 경우 생성하고 반환한다. *
* DU.namespace("property.package"); * DU.namespace("DU.property.package"); ** DU.property나 DU.property.package 중에 하나를 생성한다. * * 패키지 네이밍은 조심하여야 한다. 예약어는 어떤 브라우저에서는 작동하고 * 또 다른데서는 작동하지 않을 수 있다. 예를 들어, 다음은 Safari에서 실패할 것이다: *
* DU.namespace("really.long.nested.namespace"); ** 이 fail은 "long"이 ECMAScript에서 앞으로 예약어가 될 것이기 때문이다. * * @method namespace * @static * @param {String} 생성할 1-n namespace들의 argument들 * @return {Object} 생성된 마지막 namespace object의 reference */ DU.namespace = function() { var a=arguments, o=null, i, j, d; for (i=0; i
type <string>, args <array>, customobject <object>
*onReady events에 대해서 fire argument들은 없으며, signature는 다음과 같다:
*"onReady", [], obj
* * * @method onReady * * @param {function} p_fn element가 발견되었을때 실행할 함수. * @param {object} p_obj p_fn에 대한 parameter로 다시 전달하는 부가적인 object * @param {boolean|object} p_scope 만약 true로 설정하면, p_fn은 p_onj의 scope에서 * 실행을 하며, object로 설정할 경우 그 object의 scope에서 실행한다. * * @static */ DU.onReady = function(p_fn, p_obj, p_override){ DU.util.LEvent.onDOMReady(p_fn, p_obj, p_override); } /** * onAvaliable과 같은 방식으로 실행되지만, 추가적으로 * 사용가능한 element의 content를 수정하기 위한 안전 여부를 결정하기 위하여, * sibling element들의 상태를 체크한다. * *callback은 하나의 parameter로 실행된다: * custom object parameter를 제공하는 경우.
* * @method onContentReady * * @param {string} p_id 찾을 element의 id. * @param {function} p_fn element가 준비되었을때 실행할 함수. * @param {object} p_obj p_fn에 대한 parameter로 다시 전달하는 부가적인 object * @param {boolean|object} p_scope 만약 true로 설정하면, p_fn은 p_onj의 scope에서 * 실행을 하며, object로 설정할 경우 그 object의 scope에서 실행한다. * * @static */ DU.onContentReady = function(p_id, p_fn, p_obj, p_override) { DU.util.LEvent.onContentReady(p_id, p_fn, p_obj, p_override); } /** * Ajax를 호출한다. * * @method ajax * @static * @param {object} config config : url(String), method(String/optional), success(Function), failure(Function/optional), params(Object/optional) * @return {object} connection object를 반환. */ DU.ajax = function(config) { config = DU.applyIf(config, { method: 'GET', failure: DU.emptyFn }); return DU.LConnect.asyncRequest(config.method, config.url, { success: config.success, failure: config.failure }, config.params, config); } /** * 유일한 id들을 생성한다. 만약 element가 이미 id를 가지고 있으면, 그것은 변하지 않는다. * @method id * @param {Mixed} el (optional) id가 생성될 element * @param {String} prefix (optional) Id prefix (기본 "ext-gen") * @return {String} 생성된 Id. */ DU.id = function(el, prefix){ return DU.util.LDom.generateId(el, prefix); } /** * 주어진 CSS selector에 기반한 node들의 집합을 조회한다. * @method select * * @param {string} selector 테스트 할 CSS LDomSelector. * @param {HTMLElement | String} root optional query로 부터 시작할 id나 HTMLElement. 기본은 LDomSelector.document. * @param {Boolean} firstOnly optional 처음 일치하는 값만 반환할지에 대한 여부. * @return {DU.LElementList} 주어진 selector와 일치하는 node들의 array. * @static */ DU.select = function (selector, root, firstOnly) { var n = DU.util.LDomSelector.query(selector, root, firstOnly); var element = []; if(DU.isArray(n)) { DU.each(n, function(child) { element.push(DU.get(child)); }); } else { if(!DU.isEmpty(n)) element.push(DU.get(n)); } return new DU.LElementList(element); } /** * 주어진 CSS selector에 기반한 node들의 집합을 조회한다. * @method query * * @param {string} selector node를 상대로 테스트할 CSS LDomSelector. * @param {HTMLElement | String} root optional query로 부터 시작할 id나 HTMLElement. 기본은 LDomSelector.document. * @param {Boolean} firstOnly optional 처음 일치하는 값만 반환할지에 대한 여부. * @return {DU.LElementList} 주어진 selector와 일치하는 node들의 array. * @static */ DU.query = function (selector, root, firstOnly) { return DU.util.LDomSelector.query(selector, root, firstOnly); } /** * items 정보에 해당되는 객체를 Function으로 호출하는 메소드 * @method each * @static * @param {Array} items Array 배열 * @param {Function} func Array 배열 * @param {Object} scope Array 배열 * @return void */ DU.each = function(items, func, scope) { return DU.util.LArray.each(items, func, scope); } /** * object나 array를 표현하는 간단한 문자열을 반환한다. * object들의 다른 타입은 처리되지 않고 반환될 것이다. * Array들은 색인될 것으로 예상된다. * 연관 배열에 대한 object 표기법을 사용한다. * @method dump * @static * @since 2.3.0 * @param o {Object} dump 할 object * @param d {int} child object를 탐색할 깊이(deep), 기본적으로 3 * @return {String} dump 결과 */ DU.dump = function(o, d) { var i,len,s=[],OBJ="{...}",FUN="f(){...}", COMMA=', ', ARROW=' => '; // Cast non-objects to string // Skip dates because the std toString is what we want // Skip HTMLElement-like objects because trying to dump // an element will cause an unhandled exception in FF 2.x if (!DU.isObject(o)) { return o + ""; } else if (o instanceof Date || ("nodeType" in o && "tagName" in o)) { return o; } else if (DU.isFunction(o)) { return FUN; } // dig into child objects the depth specifed. Default 3 d = (DU.isNumber(d)) ? d : 3; // arrays [1, 2, 3] if (DU.isArray(o)) { s.push("["); for (i=0,len=o.length;i* var A = function() {}; * A.prototype.foo = 'foo'; * var a = new A(); * a.foo = 'foo'; * alert(a.hasOwnProperty('foo')); // true * alert(DU.hasOwnProperty(a, 'foo')); // false when using fallback ** @method hasOwnProperty * @static * @param {Object} o 테스트될 object * @param prop {string} 테스트할 property의 이름 * @return {boolean} 결과 */ DU.hasOwnProperty = (Object.prototype.hasOwnProperty) ? function(o, prop) { return o && o.hasOwnProperty(prop); } : function(o, prop) { return !DU.isUndefined(o[prop]) && o.constructor.prototype[prop] !== o[prop]; }; DU.augment = DU.applyPrototype; /** * DU.env는 DU 라이브러리나 브라우징 환경에 대해 알려진 항목들을 추적하는데 사용된다. * @class DU.env * @static */ DU.env = DU.env || { /** * 보고된 모든 DU 모듈들에 대한 버전 정보를 유지. * @property modules * @type Object[] */ modules: [], /** * DU 모듈이이 보고될 때마다 실행되어야 할 함수들의 목록. * @property listeners * @type Function[] */ listeners: [] }; /** * DU 모듈이 로딩될때마다 실행되어야 할 함수에 대한 reference. * parameter로서 이 함수들은 모듈에 대한 version 정보를 받는다. * version 데이터 구조에 대한 설명은 * DU.env.getVersion을 참고한다. * @property listener * @type Function * @static * @default undefined */ /** * 만약 라이브러리가 window.onload 이후에 동적으로 로딩될 경우에는 true를 설정한다. * 기본값은 false. * @property injecting * @type boolean * @static * @default undefined */ /** * yui 컴포넌트와 그것들의 dependancy들을 동적으로 로딩하기 위하여 * yuiloader 컴포넌트에 지시한다. * 동적인 로딩에 대한 더 자세한 정보는 yuiloader documentation을 참고한다. * @property load * @static * @default undefined * @see yuiloader */ /** * 라이브러리에서 제공된 locale의 사용에 적용하도록 강제한다. * @property locale * @type string * @static * @default undefined */ /** * 명시된 모듈들에 대한 version 데이터를 반환한다: *
* var dateStr = new Date().format("YYYYMMDD"); * * 참고 : Date 오브젝트 생성자들 - dateObj = new Date() * - dateObj = new Date(dateVal) * - dateObj = new Date(year, month, date[, hours[, minutes[, seconds[,ms]]]]) ** 위의 예에서 오늘날짜가 2002년 3월 5일이라면 dateStr의 값은 "20020305"가 된다. * default pattern은 "YYYYMMDD"이다. * @method format * @param {String|Object} oConfig pattern optional 변환하고자 하는 패턴 스트링이나 Config객체. (default : YYYYMMDD) * @return : Date를 표현하는 변환된 String. * @author : 임재현 */ Date.prototype.format = function(oConfig){ oConfig = typeof oConfig == 'string' ? { format: oConfig } : oConfig; return DU.util.LDate.format(this, oConfig); } /** * 해당 instance에 지정된 시간량을 추가한다. * Day "D", Week "W", Year "Y", Month "M", Hour "H", Minute "m", Second "S", Milisecond "s" * @method add * @param {Date} date 추가적으로 실행될 JavaScript Date object * @param {String} field 추가적인 실행에 사용되는 field constant * @param {Number} amount 날짜에 추가하기 위한 unit들의 number(field constant에서 측정된) * @return {Date} Date object의 결과 */ Date.prototype.add = function(field, amount) { return DU.util.LDate.add(this, field, amount); } /** * @description 현재 날짜를 대상날짜와 format 형식에 맞게 비교한다. config를 주지 않을경우 %x(yyyy-mm-dd)로 비교한다. * @method equals * @param {Date} date 비교 대상 date 객체 * @param {Object} config [optional] format등 옵션 * @return {boolean} */ Date.prototype.equals = function(d, config) { return DU.util.LDate.equals(this, d, config); } /** * 시간을 제외한 날짜를 비교하여 현재 날짜와의 차이를 일자로 리턴한다. * @method compareTo * @param {Date} date 비교 날짜 객체 * @return {int} */ Date.prototype.compareTo = function(compareDate){ var date1 = this.clone(); date1.setHours(0); date1.setMinutes(0); date1.setSeconds(0); compareDate.setHours(0); compareDate.setMinutes(0); compareDate.setSeconds(0); return parseInt((date1 - compareDate) / 1000 / 24 / 60 / 60, 10); } /** * @description 현재 날짜의 마지막 일자를 Date형으로 리턴한다. * @method getDayInMonth * @return {Date} */ Date.prototype.getDayInMonth = function() { return new Date(this.getFullYear(), this.getMonth(), DU.util.LDate.getDayInMonth(this.getMonth())); } /** * @description 현재 날짜를 복사하여 리턴한다. * @method clone * @return {Date} */ Date.prototype.clone = function() { return new Date(this.getFullYear(), this.getMonth(), this.getDate(), this.getHours(), this.getMinutes(), this.getSeconds()); } })(); (function(){ /** * @module util * @title DU Global */ var xPad = function(x, pad, r){ r = r || 10; for (; parseInt(x, 10) < r && r > 1; r /= 10) { x = pad.toString() + x; } return x.toString(); }; /** * Date type의 데이터를 다루는데 도움이 되는 function을 제공하는 static Date 클래스 * @requires DU * @class LDate * @static */ var Dt = { /***************************************LDateMath에서 가져온 function 시작***************************************/ /** * representing Day 상수 field * @property DAY * @static * @final * @type String */ DAY: "D", /** * representing Week 상수 field * @property WEEK * @static * @final * @type String */ WEEK: "W", /** * representing Year 상수 field * @property YEAR * @static * @final * @type String */ YEAR: "Y", /** * representing Month 상수 field * @property MONTH * @static * @final * @type String */ MONTH: "M", /** * representing Hour 상수 field * @property HOUR * @static * @final * @type String */ HOUR:"H", /** * representing Minute 상수 field * @property MINUTE * @static * @final * @type String */ MINUTE : "m", /** * representing Second 상수 field * @property SECOND * @static * @final * @type String */ SECOND : "S", /** * representing Milisecond 상수 field * @property MILISECOND * @static * @final * @type String */ MILLISECOND : "s", /** * representing one day, in milliseconds 상수 field * @property ONE_DAY_MS * @static * @final * @type Number */ ONE_DAY_MS: 1000 * 60 * 60 * 24, /** * Constant field representing the date in first week of January * which identifies the first week of the year. * 한해의 첫주를 식별하게 하는 1월의 첫째주에 대한 date를 표시하는 상수 field *
* 미국에서는 1월 1일이 보통 한주의 일요일 시작을 기반으로 사용된다. * 유럽에서 넓게 사용되는 ISO 8601 은 한주의 월요일 시작을 기반으로한 1월 4일을 사용한다. *
* @property WEEK_ONE_JAN_DATE * @static * @type Number */ WEEK_ONE_JAN_DATE: 1, /** * 해당 instance에 특정 시간량을 추가한다. * @method add * @param {Date} date 추가적으로 실행될 JavaScript Date object * @param {String} field 추가적인 실행에 사용되는 field constant * @param {Number} amount 날짜에 추가하기 위한 unit들의 number(field constant에서 측정된) * @return {Date} Date object의 결과 */ add: function(date, field, amount) { var d = new Date(date.getTime()); switch (field) { case this.MONTH: var newMonth = date.getMonth() + amount; var years = 0; if (newMonth < 0) { while (newMonth < 0) { newMonth += 12; years -= 1; } } else if (newMonth > 11) { while (newMonth > 11) { newMonth -= 12; years += 1; } } d.setMonth(newMonth); d.setFullYear(date.getFullYear() + years); break; case this.DAY: this._addDays(d, amount); break; case this.YEAR: d.setFullYear(date.getFullYear() + amount); break; case this.WEEK: this._addDays(d, (amount * 7)); break; case this.HOUR: date.setHours(date.getHours()+amount); d = date; break; case this.MINUTE: date.setMinutes(date.getMinutes()+ amount); d = date; break; case this.SECOND: date.setSeconds(date.getSeconds()+ amount); d = date; break; case this.MILLISECOND: date.setMilliseconds(date.getMilliseconds()+ amount); d = date; break; } return d; }, /** * Date.setDate(n)의 n값이 -128 미만이거나 127보다 클때, * Safari 2 (webkit < 420) 버그에 대해 담당 하는 private helper method. ** 해결 접근 및 문제 원인은 다음에서 찾을 수 있다.: * http://brianary.blogspot.com/2006/03/safari-date-bug.html *
* @method _addDays * @param {Date} d JavaScript date object * @param {Number} nDays date object에 추가할 날짜들의 number(음수 가능) * @private */ _addDays: function(d, nDays) { if (DU.browser.webkit && DU.browser.webkit < 420) { if (nDays < 0) { // Ensure we don't go below -128 (getDate() is always 1 to 31, so we won't go above 127) for (var min = -128; nDays < min; nDays -= min) { d.setDate(d.getDate() + min); } } else { // Ensure we don't go above 96 + 31 = 127 for (var max = 96; nDays > max; nDays -= max) { d.setDate(d.getDate() + max); } } // nDays should be remainder between -128 and 96 } d.setDate(d.getDate() + nDays); }, /***************************************LDateMath에서 가져온 function 끝***************************************/ formats: { a: function (d, l) { return l.a[d.getDay()]; }, A: function (d, l) { return l.A[d.getDay()]; }, b: function (d, l) { return l.b[d.getMonth()]; }, B: function (d, l) { return l.B[d.getMonth()]; }, C: function (d) { return xPad(parseInt(d.getFullYear()/100, 10), 0); }, d: ['getDate', '0'], e: ['getDate', ' '], g: function (d) { return xPad(parseInt(Dt.formats.G(d)%100, 10), 0); }, G: function (d) { var y = d.getFullYear(); var V = parseInt(Dt.formats.V(d), 10); var W = parseInt(Dt.formats.W(d), 10); if(W > V) { y++; } else if(W===0 && V>=52) { y--; } return y; }, H: ['getHours', '0'], I: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, 0); }, j: function (d) { var gmd_1 = new Date('' + d.getFullYear() + '/1/1 GMT'); var gmdate = new Date('' + d.getFullYear() + '/' + (d.getMonth()+1) + '/' + d.getDate() + ' GMT'); var ms = gmdate - gmd_1; var doy = parseInt(ms/60000/60/24, 10)+1; return xPad(doy, 0, 100); }, k: ['getHours', ' '], l: function (d) { var I=d.getHours()%12; return xPad(I===0?12:I, ' '); }, m: function (d) { return xPad(d.getMonth()+1, 0); }, M: ['getMinutes', '0'], p: function (d, l) { return l.p[d.getHours() >= 12 ? 1 : 0 ]; }, P: function (d, l) { return l.P[d.getHours() >= 12 ? 1 : 0 ]; }, s: function (d, l) { return parseInt(d.getTime()/1000, 10); }, S: ['getSeconds', '0'], u: function (d) { var dow = d.getDay(); return dow===0?7:dow; }, U: function (d) { var doy = parseInt(Dt.formats.j(d), 10); var rdow = 6-d.getDay(); var woy = parseInt((doy+rdow)/7, 10); return xPad(woy, 0); }, V: function (d) { var woy = parseInt(Dt.formats.W(d), 10); var dow1_1 = (new Date('' + d.getFullYear() + '/1/1')).getDay(); // First week is 01 and not 00 as in the case of %U and %W, // so we add 1 to the final result except if day 1 of the year // is a Monday (then %W returns 01). // We also need to subtract 1 if the day 1 of the year is // Friday-Sunday, so the resulting equation becomes: var idow = woy + (dow1_1 > 4 || dow1_1 <= 1 ? 0 : 1); if(idow === 53 && (new Date('' + d.getFullYear() + '/12/31')).getDay() < 4) { idow = 1; } else if(idow === 0) { idow = Dt.formats.V(new Date('' + (d.getFullYear()-1) + '/12/31')); } return xPad(idow, 0); }, w: 'getDay', W: function (d) { var doy = parseInt(Dt.formats.j(d), 10); var rdow = 7-Dt.formats.u(d); var woy = parseInt((doy+rdow)/7, 10); return xPad(woy, 0, 10); }, y: function (d) { return xPad(d.getFullYear()%100, 0); }, Y: 'getFullYear', z: function (d) { var o = d.getTimezoneOffset(); var H = xPad(parseInt(Math.abs(o/60), 10), 0); var M = xPad(Math.abs(o%60), 0); return (o>0?'-':'+') + H + M; }, Z: function (d) { var tz = d.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/, '$2').replace(/[a-z ]/g, ''); if(tz.length > 4) { tz = Dt.formats.z(d); } return tz; }, '%': function (d) { return '%'; } }, aggregates: { c: 'locale', D: '%m/%d/%y', F: '%Y-%m-%d', h: '%b', n: '\n', q: 'locale',//숫자형 날짜형식 short Q: 'locale',//숫자형 날짜형식 long r: 'locale', R: '%H:%M', t: '\t', T: '%H:%M:%S', x: 'locale', X: 'locale' //'+': '%a %b %e %T %Z %Y' }, /** * 내장된 JavaScript Date를 가져오고 사용자에게 표시할 문자열로 formating 처리. * * @method format * @param oDate {Date} Date. * @param {Object} oConfig (Optional) 부가적인 configuration 값: * @return {String} 표시할 Formatted date. */ format : function (oDate, oConfig) { oConfig = oConfig || {}; if(!(oDate instanceof Date) && DU.isString(oDate)) { // 바꾸고자 하는 값이 Date 객체가 아니라 문자열인 경우에 Date 객체로 변환한다. oDate = DU.util.LDate.parse(oDate,{locale:oConfig.locale}); } var sLocale = oConfig.locale; var format = oConfig.format; format = Dt.getFormat(format, sLocale); if(!(oDate instanceof Date)) { return DU.isValue(oDate) ? oDate : ""; } // Be backwards compatible, support strings that are // exactly equal to YYYY/MM/LDD, LDD/MM/YYYY and MM/LDD/YYYY if(format === 'YYYY/MM/LDD') { format = '%Y/%m/%d'; } else if(format === 'LDD/MM/YYYY') { format = '%d/%m/%Y'; } else if(format === 'MM/LDD/YYYY') { format = '%m/%d/%Y'; } // end backwards compatibility block var aLocale = Dt.getLocale(sLocale); var replace_aggs = function (m0, m1) { var f = Dt.aggregates[m1]; return (f === 'locale' ? aLocale[m1] : f); }; // First replace aggregates (run in a loop because an agg may be made up of other aggs) while(format.match(/%[cDFhnrRtTxX]/)) { format = format.replace(/%([cDFhnrRtTxX])/g, replace_aggs); } var replace_formats = function (m0, m1) { var f = Dt.formats[m1]; if(typeof f === 'string') { // string => built in date function return oDate[f](); } else if(typeof f === 'function') { // function => our own function return f.call(oDate, oDate, aLocale); } else if(typeof f === 'object' && typeof f[0] === 'string') { // built in function with padding return xPad(oDate[f[0]](), f[1]); } else { return m1; } }; // Now replace formats (do not run in a loop otherwise %%a will be replace with the value of %a) var str = format.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g, replace_formats); replace_aggs = replace_formats = undefined; return str; }, /** * @description 기본 local 정보 등을 가져온다. * @param {String} sLocale * @return DU.util.LDateLocale */ getLocale : function (sLocale){ sLocale = sLocale || ((DU.getConfig) ? DU.getConfig().getFirst("$.core.defaultLocale") : "ko"); // Make sure we have a definition for the requested locale, or default to ko. /* if(!(sLocale in DU.util.LDateLocale)) { if(sLocale.replace(/-[a-zA-Z]+$/, '') in DU.util.LDateLocale) { sLocale = sLocale.replace(/-[a-zA-Z]+$/, ''); } else { sLocale = "ko"; } } */ return DU.util.LDateLocale.getInstance(sLocale); }, /** * @description format 문자열 return, 입력값 없을 경우 default return * @param {String} format * @param {String} locale * @return string */ getFormat : function(format, locale){ format = format || "%x"; if(format == "%x" || format == "%q" || format == "%Q" || format == "%T" || format == "%R" || format == "%r") { var aLocale = Dt.getLocale(locale); for(var f in Dt.aggregates) { if(Dt.aggregates[f] != 'locale') { aLocale[f] = Dt.aggregates[f]; } } format = aLocale[format.replace('%','')]; } return format; }, /** * @description 두 날짜를 format 형식에 맞게 비교한다. config를 주지 않을경우 %x(yyyy-mm-dd)로 비교한다. * @method equals * @param {Date} date1 대상 date 객체 * @param {Date} date2 비교 대상 date 객체 * @param {Object} config [optional] format등 옵션 * @return {boolean} */ equals : function(d1, d2, config) { config = config || { format:'%x' }; return (d1.format(config.format) == d2.format(config.format)); }, /** * @description inx월에 해당되는 마지막 날짜 * @method getDayInMonth * @param {Int} inx * @return {Int} */ getDayInMonth: function(inx){ return DU.util.LDate.DAYS_IN_MONTH[inx]; } }; /** * format 문자열에 기반한 문자열로부터 세부 시간 정보를 parsing 하는 *strptime
에 대한 부분적인 implementation.
*
* This implementation largely takes its cue from the documentation for Python's
* time
module, as documented at
* http://docs.python.org/lib/module-Dt.html; with the exception of seconds
* formatting, which is restricted to the range [00,59] rather than [00,61].
*
* 지원되는 formatting directive들: *
Directive | *Meaning | *
---|---|
%b |
* Locale의 단축된 월 이름. | *
%B |
* Locale의 전체 월 이름. | *
%d |
* [01,31]의 십진수로된 월의 날짜. | *
%H |
* [00,23]의 십진수로된 시간(24시간제). | *
%I |
* [00,12]의 십진수로된 시간(12시간제). | *
%m |
* [01,12]의 십진수로된 월. | *
%M |
* [00,59]의 십진수로된 분. | *
%p |
*
* Locale의 AM이나 PM 표시(시간을 분류하기 위해 %I directive 가
* 사용되는 경우에 시간 출력 field에만 영향을 미친다.)
* |
*
%S |
* [00,59]의 십진수로된 초. | *
%y |
* [00,99]의 십진수로된 세기값이 없는 년도. | *
%Y |
* 십진수로된 세기값을 포함한 년도. | *
%% |
* "%" 문자 literal . | *
regexp
에 의해 일치될 예상 directives code의 list
*
* @type Array
*/
this.expected = expected;
};
/**
* directive에 해당하는 데이터, 혹은 locale에 의존하는 directive의 경우에나
* locale을 가지고 정규표현식 패턴 조각을 생성하는 함수를
* 캡쳐할 정규표현식 패턴 조각에 directive code들을 맵핑.
*
* @type Object
*/
Dt.Parser.DIRECTIVE_PATTERNS =
{
"a": function(l) { return "(" + l.a.join("|") + ")"; },
// Locale's abbreviated month name
"b": function(l) { return "(" + l.b.join("|") + ")"; },
// Locale's full month name
"B": function(l) { return "(" + l.B.join("|") + ")"; },
// Locale's equivalent of either AM or PM.
"p": function(l) { return "(" + l.AM + "|" + l.PM + ")"; },
"d": "(\\d\\d?)", // Day of the month as a decimal number [01,31]
"H": "(\\d\\d?)", // Hour (24-hour clock) as a decimal number [00,23]
"I": "(\\d\\d?)", // Hour (12-hour clock) as a decimal number [01,12]
"m": "(\\d\\d?)", // Month as a decimal number [01,12]
"M": "(\\d\\d?)", // Minute as a decimal number [00,59]
"S": "(\\d\\d?)", // Second as a decimal number [00,59]
"y": "(\\d\\d?)", // Year without century as a decimal number [00,99]
"Y": "(\\d\\d\\d\\d)", // Year with century as a decimal number
"%": "%" // A literal "%" character
};
/**
* 각 directive에 대해 예상되는 캡쳐된 directive code들을 directive code들에 맵핑.
* - 여러 데이터 항목들을 포함할 수 있는 어떤 directive들로 지정한 목록.
*
* @type Object
*/
Dt.Parser.EXPECTED_DATA_TYPES =
{
"b": ["b"],
"B": ["B"],
"d": ["d"],
"H": ["H"],
"I": ["I"],
"m": ["m"],
"M": ["M"],
"p": ["p"],
"S": ["S"],
"y": ["y"],
"Y": ["Y"],
"%": []
};
Dt.Parser.prototype =
{
/*
* Attempts to extract date and time details from the given input.
* * Time fields in this method's result are as follows: *
Index | *Represents | *Values | *
---|---|---|
0 |
* Year | *(for example, 1993) | *
1 |
* Month | *range [1,12] | *
2 |
* Day | *range [1,31] | *
3 |
* Hour | *range [0,23] | *
4 |
* Minute | *range [0,59] | *
5 |
* Second | *range [0,59] | *
6 |
* Day of week (not implemented - always 0 ) |
* range [0,6], Monday is 0 | *
7 |
* Day of year (not implemented - always 1 ) |
* range [1,366] | *
8 |
* Daylight savings flag (not implemented - always -1 ) |
* 0, 1 or -1 | *
* alert(config.get("$.core.defaultLocale")); *
XPath | JsonPath | Description |
/ | $ | 루트 object/element |
. | @ | 현재 object/element |
/ | . or [] | child 연산자 |
.. | n/a | parent 연산자 |
// | .. | recursive descent. JsonPath는 E4X로 부터 이런 문법을 빌려왔다. |
* | * | 와일드카드. 모든 object/element들은 그것들의 이름을 고려하지 않는다. |
@ | n/a | attribute 액세스. Json 구조는 attribute들을 가지지 않는다. |
[] | [] | subscript 연산자. XPath는 predicates와 element collection들의 반복을 위해 이것을 사용한다. Javascript와 Json에서 이것은 native array 연산자이다. |
| | [,] | 노드 집합들의 조합에 XPath 결과들의 Union 연산자. JsonPath는 집합으로 대체적인 이름이나 array 인덱스들이 가능하다. |
n/a | [start:end:step] | ES4에서 빌려온 array slice 연산자. |
[] | ?() | 스크립트 표현 필터를 적용. |
n/a | () | underlying 스크립트 엔진을 사용한 스크립트 표현. |
() | n/a | Xpath 에서의 그룹핑 |
callback은 하나의 parameter를 가지고 실행된다: * custom object parameter를 제공하는 경우.
* * @method onAvailable * * @param {string||string[]} p_id element의 id나, 찾아야 할 id들의 array * @param {function} p_fn element를 찾았을때, 실행할 함수. * @param {object} p_obj p_fn의 parameter로서 전달될 optional object. * @param {boolean|object} p_override true가 설정될 경우, p_fn은 p_obj의 scope로 * 실행할 것이며, object가 설정될 경우, 해당 object의 scope로 * 실행할 것이다. * @param checkContent {boolean} child 노드의 준비성을 체크한다.(onContentReady) * @static */ onAvailable: function(p_id, p_fn, p_obj, p_override, checkContent) { var a = (DU.isString(p_id)) ? [p_id] : p_id; for (var i=0; icallback은 LCustomEvent이며, signature는 다음과 같다:
*type <string>, args <array>, customobject <object>
*DOMReady event들에 대해, 발생 argument들은 없으며, signature는 다음과 같다:
*"DOMReady", [], obj
* * * @method onDOMReady * * @param {function} p_fn element를 찾았을 때 실행할 함수 * @param {object} p_obj p_fn의 parameter로서 전달될 optional object * @param {boolean|object} p_scope true가 설정될 경우, p_fn은 p_obj의 scope로 * 실행할 것이며, object가 설정될 경우, 해당 object의 scope로 * 실행할 것이다. * * @static */ onDOMReady: function(p_fn, p_obj, p_override) { if (this.DOMReady) { setTimeout(function() { var s = window; if (p_override) { if (p_override === true) { s = p_obj; } else { s = p_override; } } p_fn.call(s, "DOMReady", [], p_obj); }, 0); } else { this.DOMReadyEvent.on(p_fn, p_obj, p_override); } }, /** * event handlet를 추가한다. * * @method _addListener * * @param {String|HTMLElement|Array|NodeList} el listener에 할당할 id나 * element reference 혹은 id나 element들의 collection. * @param {String} sType 추가할 event의 타입 * @param {Function} fn event가 수행하는 method * @param {Object} obj handler에 parameter로서 전달될 임의의 object * @param {Boolean|object} override true일 결우, obj가 listener의 실행 scope가 된다. * object일 경우, object가 실행 scope가 된다. * @param {boolen} capture capture or bubble phase * @return {Boolean} action이 성공이거나 defred일 경우 true, * 하나 혹은 그 이상의 element들이 첨부된 listener를 가질 * 수 없었거나 operation에서 exception이 발생했을 경우 false. * @private * @static */ _addListener: function(el, sType, fn, obj, override, capture) { if (!fn || !fn.call) { return false; } // The el argument can be an array of elements or element ids. if ( this._isValidCollection(el)) { var ok = true; for (var i=0,len=el.length; iSee: Element.addListener
*Event fields:
* <String> type
available
* <HTMLElement>
* target
the HTMLElement bound to this Element instance
*
Usage:
* var handler = function(e) {var target = e.target};
* myTabs.addListener('available', handler);
See: Element.addListener
*Event fields:
* <String> type
contentReady
* <HTMLElement>
* target
the HTMLElement bound to this Element instance
*
Usage:
* var handler = function(e) {var target = e.target};
* myTabs.addListener('contentReady', handler);
See: Element.addListener
*Event fields:
* <String> type
beforeAppendTo
* <HTMLElement/Element>
* target
the HTMLElement/Element being appended to
*
Usage:
* var handler = function(e) {var target = e.target};
* myTabs.addListener('beforeAppendTo', handler);
See: Element.addListener
*Event fields:
* <String> type
appendTo
* <HTMLElement/Element>
* target
the HTMLElement/Element being appended to
*
Usage:
* var handler = function(e) {var target = e.target};
* myTabs.addListener('appendTo', handler);
이 method는 {@link DU.Component Component}들을 조회하지 않는다. * 이 method는 DOM element들을 캡슐화 하는 DU.Element object들을 조회한다. * 그것의 ID로 Component를 조회하기 위하여, {@link DU.ComponentMgr#get}를 사용한다.
*같은 object를 일관되게 반환하기 위하여 simple 캐싱을 사용한다. * 만약 object가 AJAX나 DOM을 통해 똑같은 id로 재생성되었으면, 자동적으로 수정한다.
* @param {Mixed} el DOM node나 존재하고 있는 Element의 id. * @return {Element} {@link DU.LElement Element} object나 맞는 element를 찾지 못했으면 null * @static */ var El = DU.LElement; var docEl; El.get = function(el){ var ex, elm, id; if(!el){ return null; } if(typeof el == "string"){ // element id if(!(elm = document.getElementById(el))){ return null; } if(ex = El.cache[el]){ ex.dom = elm; }else{ ex = El.cache[el] = new DU.LElement(elm); } return ex; }else if(el.tagName){ // dom element ex = new El(el); return ex; }else if(el instanceof El){ if(el != docEl){ el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid, // catch case where it hasn't been appended } return el; }else if(el.isComposite){ return el; }else if(DU.isArray(el)){ var obj = []; for(var i = 0 ; i < el.length ; i++) obj.push(new DU.LElement(el[i])); return obj; //El.select(el); }else if(el == document){ // create a bogus element object representing the document object if(!docEl){ var f = function(){}; f.prototype = El.prototype; docEl = new f(); docEl.dom = document; } return docEl; } return null; }; DU.get = El.get; El.cache = {}; El.PADDING = "padding"; El.MARGIN = "margin"; El.BORDER = "border"; El.LEFT = "-left"; El.RIGHT = "-right"; El.TOP = "-top"; El.BOTTOM = "-bottom"; El.WIDTH = "-width"; // special markup used throughout Ext when box wrapping elements El.borders = {l: El.BORDER + El.LEFT + El.WIDTH, r: El.BORDER + El.RIGHT + El.WIDTH, t: El.BORDER + El.TOP + El.WIDTH, b: El.BORDER + El.BOTTOM + El.WIDTH}; El.paddings = {l: El.PADDING + El.LEFT, r: El.PADDING + El.RIGHT, t: El.PADDING + El.TOP, b: El.PADDING + El.BOTTOM}; El.margins = {l: El.MARGIN + El.LEFT, r: El.MARGIN + El.RIGHT, t: El.MARGIN + El.TOP, b: El.MARGIN + El.BOTTOM}; El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i; ( function() { /** * Element 객체를 Chain 구조로 처리하는 객체 * @class LElementList * @constructor LElementList * @param o {HTMLElement} The html element that */ DU.LElementList = function(o) { /** * @description element의 배열 객체 * @property elements * @private * @type {Array} */ this.elements = []; /** * @description element의 배열 갯수 * @property length * @private * @type {Int} */ this.length = 0; this.add(o); }; DU.LElementList.prototype = { /** * @description Element객체 추가 * @method add * @param {DU.LElement} els 추가할 Element 객체 * @return {DU.LElementList} DU.LElementList 객체 리턴 */ add : function(els) { if (els) { if (!DU.isArray(els)) { this.elements = this.elements.concat(els); } else { var yels = this.elements; DU.each(els, function(e) { yels.push(e); }); } this.length = this.elements.length; } return this; }, /** * @description index에 대한 Element객체 리턴 * @method getAt * @param {Int} index 리턴할 위치 * @return {DU.LElement} DU.LElement 객체 리턴 */ getAt : function(index) { var me = this; if(!me.elements[index]){ return null; } return me.elements[index]; }, /** * @description each 메소드 * @method each * @private * @param {Function} fn 비교할 Function * @param {Object} scope this로 인식할 객체 정보 * @return {DU.LElementList} DU.LElementList 객체 리턴 */ each : function(fn, scope){ var me = this; DU.each(me.elements, function(e,i) { return fn.call(scope || e, e, me, i); }); return me; }, /** * @description 배열 초기화 메소드 * @method clear * @return {DU.LElementList} DU.LElementList 객체 리턴 */ clear : function(){ this.elements = []; this.length = 0; return this; }, /** * @description item들의 dom select 메소드 * @method select * @private * @param {String} selector selector 문장 * @param {Boolean} firstOnly 첫번째 Dom을 리턴할지 여부 * @return {DU.LElementList} DU.LElementList 객체 리턴 */ select : function(selector, firstOnly) { var newElement = []; this.each(function(item) { var me = item.select(selector, firstOnly); newElement = newElement.concat(me.elements || me); }, this.elements); return new DU.LElementList(newElement); }, /** * @description item들의 dom query 메소드 * @method query * @private * @param {String} selector selector 문장 * @param {Boolean} firstOnly 첫번째 Dom을 리턴할지 여부 * @return {DU.LElementList} DU.LElementList 객체 리턴 */ query : function(selector, firstOnly) { var newElement = []; this.each(function(item) { var me = item.query(selector, firstOnly); newElement = newElement.concat(me); }, this.elements); return new DU.LElementList(newElement); }, /** * @description item들의 dom filter 메소드 * @method filter * @private * @param {String} selector selector 문장 * @return {DU.LElementList} DU.LElementList 객체 리턴 */ filter : function(selector) { var newElement = []; this.each(function(item) { var me = item.filter(selector); newElement = newElement.concat(me.elements || me); }, this.elements); return new DU.LElementList(newElement); }, /** * @description LElement 배열을 리턴한다. * @method toArray * @return {Array} */ toArray: function() { return this.elements; }, /** * @description 현재 item들이 selector에 맞는 객체인지 확인하는 메소드 * @method selector * @private * @param {String} selector selector 문장 * @return {Boolean} */ test : function(selector) { var isTest = true; this.each(function(item) { var isV = item.test(selector); isTest = isV; return !isTest ? false:true; }, this.elements); return isTest; }, invoke : function(fn, args){ var els = this.elements, el = this.el; DU.each(els, function(e) { DU.LElement.prototype[fn].apply(e, args); }, this); return this; }, /** * @description 객체의 toString * @method toString * @public * @return {String} */ toString : function() { return 'DU.LElementList '; } }; })(); (function(){ var fnName, ElProto = DU.LElement.prototype, CelProto = DU.LElementList.prototype; for(var fnName in ElProto){ if(DU.isFunction(ElProto[fnName])){ (function(fnName){ CelProto[fnName] = CelProto[fnName] || function(){ return this.invoke(fnName, arguments); }; }).call(CelProto, fnName); } }; })(); /** * select 모듈은 CSS3 selector들이 DOM element들과 함께 사용될 수 있게 도움을 주는 method들을 제공한다. * @module util * @title Selector Utility * @namespace DU.util * @requires DU, dom */ (function() { /** * DOM element들의 collecting과 filtering에 도움을 주는 method들을 제공한다. * @namespace DU.util * @class LDomSelector * @static */ var LDomSelector = function() {}; var Y = DU.util; var reNth = /^(?:([-]?\d*)(n){1}|(odd|even)$)*([-+]?\d*)$/; var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g; LDomSelector.prototype = { /** * query들을 사용하기 위한 기본 document * @property document * @type object * @default window.document */ document: window.document, /** * 일반적으로 JS 예약어와 충돌하는 HTMLAttibute를 해결하기 위하여, * alias로 attribute를 매핑한다. * @property attrAliases * @type object */ attrAliases: { }, /** * attribute selector에 대응되는 shorthand 토큰의 매핑 * @property shorthand * @type object */ shorthand: { //'(?:(?:[^\\)\\]\\s*>+~,]+)(?:-?[_a-z]+[-\\w]))+#(-?[_a-z]+[-\\w]*)': '[id=$1]', '\\#(-?[_a-z]+[-\\w]*)': '[id=$1]', '\\.(-?[_a-z]+[-\\w]*)': '[class~=$1]' }, /** * 연산자의 목록과 대응되는 boolean 함수들. * 이 함수들은 attribute와 attribute의 현재 node값이 전달된다. * @property operators * @type object */ operators: { '=': function(attr, val) { return attr === val; }, // Equality '!=': function(attr, val) { return attr !== val; }, // Inequality '~=': function(attr, val) { // Match one of space seperated words var s = ' '; return (s + attr + s).indexOf((s + val + s)) > -1; }, '|=': function(attr, val) { return getRegExp('^' + val + '[-]?').test(attr); }, // Match start with value followed by optional hyphen '^=': function(attr, val) { return attr.indexOf(val) === 0; }, // Match starts with value '$=': function(attr, val) { return attr.lastIndexOf(val) === attr.length - val.length; }, // Match ends with value '*=': function(attr, val) { return attr.indexOf(val) > -1; }, // Match contains value as substring '': function(attr, val) { return attr; } // Just test for existence of attribute }, /** * pseudo 클래스들의 목록과 대응되는 boolean 함수들. * 이 함수들은 현재 node와 pseudo 정규식으로 parsing되는 어떤값들로 호출이 된다. * @property pseudos * @type object */ pseudos: { 'root': function(node) { return node === node.ownerDocument.documentElement; }, 'nth-child': function(node, val) { return getNth(node, val); }, 'nth-last-child': function(node, val) { return getNth(node, val, null, true); }, 'nth-of-type': function(node, val) { return getNth(node, val, node.tagName); }, 'nth-last-of-type': function(node, val) { return getNth(node, val, node.tagName, true); }, 'first-child': function(node) { return getChildren(node.parentNode)[0] === node; }, 'last-child': function(node) { var children = getChildren(node.parentNode); return children[children.length - 1] === node; }, 'first-of-type': function(node, val) { return getChildren(node.parentNode, node.tagName.toLowerCase())[0]; }, 'last-of-type': function(node, val) { var children = getChildren(node.parentNode, node.tagName.toLowerCase()); return children[children.length - 1]; }, 'only-child': function(node) { var children = getChildren(node.parentNode); return children.length === 1 && children[0] === node; }, 'only-of-type': function(node) { return getChildren(node.parentNode, node.tagName.toLowerCase()).length === 1; }, 'empty': function(node) { return node.childNodes.length === 0; }, 'not': function(node, simple) { return !LDomSelector.test(node, simple); }, 'contains': function(node, str) { var text = node.innerText || node.textContent || ''; return text.indexOf(str) > -1; }, 'checked': function(node) { return node.checked === true; } }, /** * 제공된 node가 제공된 selector와 일치하는지 테스트한다. * @method test * * @param {HTMLElement | String} node 테스트될 HTMLElement로의 id나 node reference * @param {string} selector node를 상대로 테스트할 CSS LDomSelector * @return{boolean} node가 selector와 일치하는지에 대한 여부 * @static */ test: function(node, selector) { node = LDomSelector.document.getElementById(node) || node; //node = typeof node == "string" ? LDomSelector.document.getElementById(node) : node; if (!node) { return false; } var groups = selector ? selector.split(',') : []; if (groups.length) { for (var i = 0, len = groups.length; i < len; ++i) { if ( rTestNode(node, groups[i]) ) { // passes if ANY group matches return true; } } return false; } return rTestNode(node, selector); }, /** * 주어진 CSS selector에 기반한 node들의 집합을 filtering. * @method filter * * @param {array} nodes filter할 node/id들의 집합 * @param {string} selector 각 node를 테스트 하기 위해 사용되는 selector * @return{array} 주어진 selector와 일치하는 제공된 array로 부터의 node들의 array * @static */ filter: function(nodes, selector) { nodes = nodes || []; var node, result = [], tokens = tokenize(selector); if (!nodes.item) { // if not HTMLCollection, handle arrays of ids and/or nodes for (var i = 0, len = nodes.length; i < len; ++i) { if (!nodes[i].tagName) { // tagName limits to HTMLElements node = LDomSelector.document.getElementById(nodes[i]); if (node) { // skip IDs that return null nodes[i] = node; } else { } } } } result = rFilter(nodes, tokenize(selector)[0]); clearParentCache(); return result; }, /** * 주어진 CSS selector에 기반한 node들의 집합을 받는다. * @method query * * @param {string} selector 노드를 상대로 테스트할 CSS LDomSelector * @param {HTMLElement | String} root (optional) 쿼리가 시작할 id나 HTMLElement. 기본은 LDomSelector.document. * @param {Boolean} firstOnly (optional) 첫번째 일치값만 반환할지에 대한 여부 * @return {Array} 주어진 selector와 일치하는 node들의 array * @static */ query: function(selector, root, firstOnly) { var result = query(selector, root, firstOnly); return result; } }; var query = function(selector, root, firstOnly, deDupe) { var result = (firstOnly) ? null : []; if (!selector) { return result; } var groups = selector.split(','); // TODO: handle comma in attribute/pseudo if (groups.length > 1) { var found; for (var i = 0, len = groups.length; i < len; ++i) { found = arguments.callee(groups[i], root, firstOnly, true); result = firstOnly ? found : result.concat(found); } clearFoundCache(); return result; } if (root && !root.nodeName) { // assume ID root = LDomSelector.document.getElementById(root); if (!root) { return result; } } root = root || LDomSelector.document; var tokens = tokenize(selector); var idToken = tokens[getIdTokenIndex(tokens)], nodes = [], node, id, token = tokens.pop() || {}; if (idToken) { id = getId(idToken.attributes); } // use id shortcut when possible if (id) { node = LDomSelector.document.getElementById(id); /* * ie에서 getElementById로 얻어와도 name객체는 찾는 문제 해결 */ if(node && node.id != id) { var findNodeList = []; findNodeList = DU.util.LDom.getAllChildrenBy(root || document, findNodeList, function(child){ if(child.id == id) return true; return false; }); node = findNodeList.length > 0 ? findNodeList[0] : node; } if (node && (root.nodeName == '#document' || contains(node, root))) { if ( rTestNode(node, null, idToken) ) { if (idToken === token) { nodes = [node]; // simple selector } else { root = node; // start from here } } } else { return result; } } if (root && !nodes.length) { nodes = root.getElementsByTagName(token.tag); } if (nodes.length) { result = rFilter(nodes, token, firstOnly, deDupe); } clearParentCache(); return result; }; var contains = function() { if (document.documentElement.contains && !DU.browser.webkit < 422) { // IE & Opera, Safari < 3 contains is broken return function(needle, haystack) { return haystack.contains(needle); }; } else if ( document.documentElement.compareDocumentPosition ) { // gecko return function(needle, haystack) { /* //compareDocumentPosition: DOM Level 3에 정의된 패런트와 차일드 관계를 나타내는 메소드 //this.compareDocumentPosition(other)를 기준으로 8진수 값 //1: 같은 document에 존재하지 않음 //2: node가 other보다 앞에 있음 //4: node가 other보다 뒤에 있음 //8: node는 other의 자손 //10: node는 other의 선조 //20: DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC */ return !!(haystack.compareDocumentPosition(needle) & 16); }; } else { // Safari < 3 return function(needle, haystack) { var parent = needle.parentNode; while (parent) { if (needle === parent) { return true; } parent = parent.parentNode; } return false; }; } }(); var rFilter = function(nodes, token, firstOnly, deDupe) { var result = firstOnly ? null : []; for (var i = 0, len = nodes.length; i < len; i++) { if (! rTestNode(nodes[i], '', token, deDupe)) { continue; } if (firstOnly) { return nodes[i]; } if (deDupe) { if (nodes[i]._found) { continue; } nodes[i]._found = true; foundCache[foundCache.length] = nodes[i]; } result[result.length] = nodes[i]; } return result; }; var rTestNode = function(node, selector, token, deDupe) { token = token || tokenize(selector).pop() || {}; if (!node.tagName || (token.tag !== '*' && node.tagName.toUpperCase() !== token.tag) || (deDupe && node._found) ) { return false; } if (token.attributes.length) { var attribute; for (var i = 0, len = token.attributes.length; i < len; ++i) { if (token.attributes[i][0] == "class" || token.attributes[i][0] == "className") { attribute = node.className; } else { attribute = node.getAttribute(token.attributes[i][0], 2); } if (attribute === null || attribute === undefined) { return false; } if ( LDomSelector.operators[token.attributes[i][1]] && !LDomSelector.operators[token.attributes[i][1]](attribute, token.attributes[i][2])) { return false; } } } if (token.pseudos.length) { for (var i = 0, len = token.pseudos.length; i < len; ++i) { if (LDomSelector.pseudos[token.pseudos[i][0]] && !LDomSelector.pseudos[token.pseudos[i][0]](node, token.pseudos[i][1])) { return false; } } } return (token.previous && token.previous.combinator !== ',') ? combinators[token.previous.combinator](node, token) : true; }; var foundCache = []; var parentCache = []; var regexCache = {}; var clearFoundCache = function() { for (var i = 0, len = foundCache.length; i < len; ++i) { try { // IE no like delete delete foundCache[i]._found; } catch(e) { foundCache[i].removeAttribute('_found'); } } foundCache = []; }; var clearParentCache = function() { if (!document.documentElement.children) { // caching children lookups for gecko return function() { for (var i = 0, len = parentCache.length; i < len; ++i) { delete parentCache[i]._children; } parentCache = []; }; } else return function() {}; // do nothing }(); var getRegExp = function(str, flags) { flags = flags || ''; if (!regexCache[str + flags]) { regexCache[str + flags] = new RegExp(str, flags); } return regexCache[str + flags]; }; var combinators = { ' ': function(node, token) { while (node = node.parentNode) { if (rTestNode(node, '', token.previous)) { return true; } } return false; }, '>': function(node, token) { return rTestNode(node.parentNode, null, token.previous); }, '+': function(node, token) { var sib = node.previousSibling; while (sib && sib.nodeType !== 1) { sib = sib.previousSibling; } if (sib && rTestNode(sib, null, token.previous)) { return true; } return false; }, '~': function(node, token) { var sib = node.previousSibling; while (sib) { if (sib.nodeType === 1 && rTestNode(sib, null, token.previous)) { return true; } sib = sib.previousSibling; } return false; } }; var getChildren = function() { if (document.documentElement.children) { // document for capability test return function(node, tag) { return (tag) ? node.children.tags(tag) : node.children || []; }; } else { return function(node, tag) { if (node._children) { return node._children; } var children = [], childNodes = node.childNodes; for (var i = 0, len = childNodes.length; i < len; ++i) { if (childNodes[i].tagName) { if (!tag || childNodes[i].tagName.toLowerCase() === tag) { children[children.length] = childNodes[i]; } } } node._children = children; parentCache[parentCache.length] = node; return children; }; } }(); /* an+b = get every _a_th node starting at the _b_th 0n+b = no repeat ("0" and "n" may both be omitted (together) , e.g. "0n+1" or "1", not "0+1"), return only the _b_th element 1n+b = get every element starting from b ("1" may may be omitted, e.g. "1n+0" or "n+0" or "n") an+0 = get every _a_th element, "0" may be omitted */ var getNth = function(node, expr, tag, reverse) { if (tag) tag = tag.toLowerCase(); reNth.test(expr); var a = parseInt(RegExp.$1, 10), // include every _a_ elements (zero means no repeat, just first _a_) n = RegExp.$2, // "n" oddeven = RegExp.$3, // "odd" or "even" b = parseInt(RegExp.$4, 10) || 0, // start scan from element _b_ result = []; var siblings = getChildren(node.parentNode, tag); if (oddeven) { a = 2; // always every other op = '+'; n = 'n'; b = (oddeven === 'odd') ? 1 : 0; } else if ( isNaN(a) ) { a = (n) ? 1 : 0; // start from the first or no repeat } if (a === 0) { // just the first if (reverse) { b = siblings.length - b + 1; } if (siblings[b - 1] === node) { return true; } else { return false; } } else if (a < 0) { reverse = !!reverse; a = Math.abs(a); } if (!reverse) { for (var i = b - 1, len = siblings.length; i < len; i += a) { if ( i >= 0 && siblings[i] === node ) { return true; } } } else { for (var i = siblings.length - b, len = siblings.length; i >= 0; i -= a) { if ( i < len && siblings[i] === node ) { return true; } } } return false; }; var getId = function(attr) { for (var i = 0, len = attr.length; i < len; ++i) { if (attr[i][0] == 'id' && attr[i][1] === '=') { return attr[i][2]; } } }; var getIdTokenIndex = function(tokens) { for (var i = 0, len = tokens.length; i < len; ++i) { if (getId(tokens[i].attributes)) { return i; } } return -1; }; var patterns = { tag: /^((?:-?[_a-z]+[\w-]*)|\*)/i, attributes: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^\]]*?)['"]?\]/i, //attributes: /^\[([a-z]+\w*)+([~\|\^\$\*!=]=?)?['"]?([^'"\]]*)['"]?\]*/i, pseudos: /^:([-\w]+)(?:\(['"]?(.+)['"]?\))*/i, combinator: /^\s*([>+~]|\s)\s*/ }; /** Break selector into token units per simple selector. Combinator is attached to left-hand selector. */ var tokenize = function(selector) { var token = {}, // one token per simple selector (left selector holds combinator) tokens = [], // array of tokens id, // unique id for the simple selector (if found) found = false, // whether or not any matches were found this pass match; // the regex match selector = replaceShorthand(selector); // convert ID and CLASS shortcuts to attributes /* Search for selector patterns, store, and strip them from the selector string until no patterns match (invalid selector) or we run out of chars. Multiple attributes and pseudos are allowed, in any order. for example: 'form:first-child[type=button]:not(button)[lang|=en]' */ do { found = false; // reset after full pass for (var re in patterns) { if (!DU.hasOwnProperty(patterns, re)) { continue; } if (re != 'tag' && re != 'combinator') { // only one allowed token[re] = token[re] || []; } if (match = patterns[re].exec(selector)) { // note assignment found = true; if (re != 'tag' && re != 'combinator') { // only one allowed //token[re] = token[re] || []; // capture ID for fast path to element if (re === 'attributes' && match[1] === 'id') { token.id = match[3]; } token[re].push(match.slice(1)); } else { // single selector (tag, combinator) token[re] = match[1]; } selector = selector.replace(match[0], ''); // strip current match from selector if (re === 'combinator' || !selector.length) { // next token or done token.attributes = fixAttributes(token.attributes); token.pseudos = token.pseudos || []; token.tag = token.tag ? token.tag.toUpperCase() : '*'; tokens.push(token); token = { // prep next token previous: token }; } } } } while (found); return tokens; }; var fixAttributes = function(attr) { var aliases = LDomSelector.attrAliases; attr = attr || []; for (var i = 0, len = attr.length; i < len; ++i) { if (aliases[attr[i][0]]) { // convert reserved words, etc attr[i][0] = aliases[attr[i][0]]; } if (!attr[i][1]) { // use exists operator attr[i][1] = ''; } } return attr; }; var replaceShorthand = function(selector) { var shorthand = LDomSelector.shorthand; var attrs = selector.match(patterns.attributes); // pull attributes to avoid false pos on "." and "#" if (attrs) { selector = selector.replace(patterns.attributes, 'REPLACED_ATTRIBUTE'); } for (var re in shorthand) { if (!DU.hasOwnProperty(shorthand, re)) { continue; } selector = selector.replace(getRegExp(re, 'gi'), shorthand[re]); } if (attrs) { for (var i = 0, len = attrs.length; i < len; ++i) { selector = selector.replace('REPLACED_ATTRIBUTE', attrs[i]); } } return selector; }; LDomSelector = new LDomSelector(); LDomSelector.patterns = patterns; Y.LDomSelector = LDomSelector; //msie 8일 경우 className이 아니고 class이다. if (DU.browser.msie) { // rewrite class for IE (others use getAttribute('class')// && eval(DU.browser.version) < 8 Y.LDomSelector.attrAliases['class'] = 'className'; Y.LDomSelector.attrAliases['for'] = 'htmlFor'; } })(); /** * LDateLocale은 현재 en과 ko만 default 탑재되어 있다. * 다른 나라의 locale이 필요할 경우는 Project의 공통 js파일에 DU.util.LDateLocale['fr']등의 형태로 정의를 해서 탑재하면 된다. * default 탑재된 en과 ko의 locale 정보의 수정은 du_config.js의 core.dateLocale 부분에서 override할 수 있다. * LDateLocale class는 DU.util.LDate에 의해 사용되는 모든 * localised date 문자열을 위한 컨테이너이며 base 클래스 이다. * 이것은 내부적으로 사용되지만, 새로운 date localisation을 제공하기 위해 확장될 수 있다. * * 자신의 LDateLocale 생성하기 위해서, 다음 과정을 따른다: ** DU.util.LDateLocale['fr'] = DU.merge(DU.util.LDateLocale, { * a: ['dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam'], * A: ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'], * b: ['jan', 'fév', 'mar', 'avr', 'mai', 'jun', 'jui', 'aoû', 'sep', 'oct', 'nov', 'déc'], * B: ['janvier', 'février', 'mars', 'avril', 'mai', 'juin', 'juillet', 'août', 'septembre', 'octobre', 'novembre', 'décembre'], * c: '%a %d %b %Y %T %Z', * p: ['', ''], * P: ['', ''], * x: '%d.%m.%Y', * X: '%T' * }); **
* DU.util.LDateLocale['fr-CA'] = DU.merge(DU.util.LDateLocale['fr'], { * x: '%Y-%m-%d' * }); **
* var d = new Date("2008/04/22"); * DU.util.LDate.format(d, {format: "%A, %d %B == %x"}, "fr"); ** will return: *
* mardi, 22 avril == 22.04.2008 ** And *
* DU.util.LDate.format(d, {format: "%A, %d %B == %x"}, "fr-CA"); ** Will return: *
* mardi, 22 avril == 2008-04-22 ** @module util * @namespace DU.util * @requires DU * @class LDateLocale */ DU.util.LDateLocale = { a: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], A: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], b: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], B: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], c: '%a %d %b %Y %T %Z', p: ['AM', 'PM'], P: ['am', 'pm'], q: '%m%d%Y', Q: '%m%d%Y%H%M%S', r: '%I:%M:%S %p', x: '%d/%m/%Y', X: '%T' }; DU.util.LDateLocale['en'] = DU.merge(DU.util.LDateLocale, {}); DU.util.LDateLocale['en_US'] = DU.merge(DU.util.LDateLocale['en'], { c: '%a %d %b %Y %I:%M:%S %p %Z', x: '%m/%d/%Y', X: '%I:%M:%S %p' }); DU.util.LDateLocale['en_GB'] = DU.merge(DU.util.LDateLocale['en'], { r: '%l:%M:%S %P %Z' }); DU.util.LDateLocale['en_AU'] = DU.merge(DU.util.LDateLocale['en']); DU.util.LDateLocale['ko'] = DU.merge(DU.util.LDateLocale, { a: ['일', '월', '화', '수', '목', '금', '토'], A: ['일요일', '월요일', '화요일', '수요일', '목요일', '금요일', '토요일'], b: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], B: ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12'], c: '%Y년 %b월 %d일 %a %T %Z', p: ['오전', '오후'], P: ['오전', '오후'], q: '%Y%m%d', Q: '%Y%m%d%H%M%S', x: '%Y-%m-%d', X: '%T' }); DU.util.LDateLocale['ko_KR'] = DU.merge(DU.util.LDateLocale['ko']); DU.namespace("DU.util"); /** * @description 인스턴스를 얻어오는 메소드 * @method getInstance * @public * @static * @return {DU.util.LDateLocale} */ DU.util.LDateLocale.getInstance = function(sLocale) { var dateLocale = DU.util.LDateLocale[sLocale]; var dateLocaleList = (DU.getConfig) ? DU.getConfig().getFirst('$.core.dateLocale.' + sLocale) : []; for(var key in dateLocaleList) { var val = dateLocaleList[key]; dateLocale[key] = val; } return dateLocale; } DU.util.LDateLocale.prototype = { otype : 'DU.util.LDateLocale', instanceObj : null }; /** * Represents an HTML fragment template. Templates can be precompiled for greater performance. * For a list of available format functions, see {@link DU.util.LFormat}.