/* * */ /* * @(#) du_core.js * build version : 1.0.0 $Revision: 15341 $ * * Copyright ⓒ LG CNS, Inc. All rights reserved. * * devon@lgcns.com * http://www.dev-on.com * * Do Not Erase This Comment!!! (이 주석문을 지우지 말것) * * dujsf/license.txt를 반드시 읽어보고 사용하시기 바랍니다. * * 1. 사내 사용시 KAMS를 통해 요청하여 사용허가를 받아야만 소프트웨어 라이센스 계약서에 동의하는 것으로 간주됩니다. * 2. DevOn RUI가 포함된 제품을 판매할 경우에도 KAMS를 통해 요청하여 사용허가를 받아야만 합니다. * 3. KAMS를 통해 사용허가를 받지 않은 경우 소프트웨어 라이센스 계약을 위반한 것으로 간주됩니다. * 4. 별도로 판매될 경우 LGCNS의 소프트웨어 판매정책을 따릅니다. (KAMS에 문의 바랍니다.) * * (주의!) 원저자의 허락없이 재배포 할 수 없으며 * LG CNS 외부로의 유출을 하여서는 안 된다. */ /** * DU 객체는 네임스페이스, 상속, 로깅을 포함하는 utility이다. * @module core * @namespace * @title DU Global */ (function(){ /** * DU global namespace object. * DU가 이미 정의된 경우, 기존에 존재하는 DU object는 정의된 namespace들이 * 보존되도록 덮어쓰여지지 않는다. * @class DU * @static */ /** * millisecond 이후에 제공된 obecjt의 컨텍스트에서 제공된 함수를 실행한다. * periodic을 true로 설정하지 않는다면, 함수를 한번만 실행한다. * @method later * @static * @since 2.4.0 * @param when {int} fn이 실행될 때까지 기다릴 millisecond 숫자 * @param {object} o 컨텍스트 object * @param {Function|String} fn 실행할 'o' object에서 실행할 함수나 method의 이름 * @param {Array} data 함수에 제공될 데이터. * 이것은 하나의 항목이나 array를 받아들인다. * array가 제공되는 경우 함수는 각 array 항목에 대해 하나의 paprameter를 가지고 실행된다. * 하나의 array parameter를 전달할 필요가 있는 경우, 이것은 array [myarray]에서 * wrapping 되어야 할 필요가 있을 것이다. * @param {boolean} periodic true인 경우 취소될 때까지 제공된 interval에서 * 주기적으로 실행된다. * @return {object} timer object. timer를 멈추기 위하여 해당 object에서 cancel() method를 호출한다. */ DU.later = function(when, o, fn, data, periodic) { when = when || 0; o = o || {}; var m=fn, d=data, f, r; if (DU.isString(fn)) { m = o[fn]; } if (!m) { throw new TypeError("method undefined"); } if (!DU.isArray(d)) { d = [data]; } f = function() { m.apply(o, d); }; r = (periodic) ? setInterval(f, when) : setTimeout(f, when); return { interval: periodic, cancel: function() { if (this.interval) { clearInterval(r); } else { clearTimeout(r); } } }; } /** * 적합한 non-null값을 찾기 위한 편리한 method. * null/undefined/NaN에 대해서는 false, 0/false/''을 포함한 다른 값에 대해서는 * true를 반환한다. * @method isValue * @static * @since 2.3.0 * @param {any} o 테스트할 항목 * @return {boolean} null/undefined/NaN이 아니라면 true */ DU.isValue = function(o) { // return (o || o === false || o === 0 || o === ''); // Infinity fails return (DU.isObject(o) || DU.isString(o) || DU.isNumber(o) || DU.isBoolean(o)); } /** * LConfiguration 객체를 리턴한다. *
* var config = DU.getConfig(); * var name = "$.core.defaultLocale"; * alert(typeof config.get(name)); * alert(config.get(name)); ** @method getConfig * @static * @param {Boolean} isNew 신규 객체 여부 * @return {DU.config.LConfiguration} */ DU.getConfig = function(isNew) { isNew = isNew && isNew == true ? true : false; if(this.isUndefined(this._configuration) || isNew) { this._configuration = DU.config.LConfiguration.getInstance(); } return this._configuration; }, /** * getMessageManager 객체를 리턴한다. * @method getMessageManager * @static * @param {Object} config 환경정보 객체 * @param {Boolean} isNew 신규 객체 여부 * @return {DU.message.LMessageManager} */ DU.getMessageManager = function(config, isNew) { this._messageManager = isNew ? undefined : this._messageManager; if(this.isUndefined(this._messageManager)) { this._messageManager = new DU.message.LMessageManager(config); } return this._messageManager; }, /** * js파일을 동적으로 로딩한다. *
* DU.includeJs('/dujsf/js/locale/lang-en.js'); ** @method includeJs * @static * @return void */ DU.includeJs = function(jsFile, sync) { var oHead = document.getElementsByTagName('head')[0]; var isInclude = false; var newJsFile = jsFile; newJsFile = DU.util.LString.startsWith(newJsFile, "./") ? newJsFile.substring(1) : newJsFile; var fullUrl = location.host + newJsFile; var childNodes = oHead.childNodes; for(var i = 0 ; i < childNodes.length; i++) { var headNode = childNodes[i]; if(headNode){ var currentSrc = headNode.syncSrc || headNode.src; if(currentSrc == fullUrl) { isInclude = true; break; } } } if (isInclude == false) { var oScript = document.createElement('script'); oScript.type = 'text/javascript'; if(sync || sync == true) { var o = DU.LConnect.getConnectionObject(); o.conn.open('GET', jsFile, false); o.conn.send(null); oScript.text = o.conn.responseText; oScript.syncSrc = fullUrl; } else { oScript.src = jsFile; } oHead.appendChild(oScript); } }, /** * css파일을 동적으로 로딩한다. *
* DU.includeCSS('/dujsf/resources/css/du_logger.css'); ** @method includeCSS * @static * @return void */ DU.includeCSS = function(cssFile, charset) { charset = DU.isUndefined(charset) ? DU.getConfig().get('$.core.css.charset')[0] : charset; var oHead = document.getElementsByTagName('head')[0]; var isInclude = false; for(var i = 0 ; i < oHead.childNodes.length; i++) { if(oHead.childNodes && oHead.childNodes[i].href && oHead.childNodes[i].href == location.host + cssFile) isInclude = true; } if(isInclude == false) { var oLink = document.createElement('link'); oLink.rel = 'stylesheet'; oLink.type = 'text/css'; oLink.charset = charset; oLink.href = cssFile; oHead.appendChild(oLink); } } /** * 주어진 CSS selector에 기반한 노드들의 집합을 필터링한다. * @method filter * * @param {array} nodes 필터링할 node/id들의 집합. * @param {string} selector 각 노드를 테스트할때 사용할 selector. * @return{array} 주어진 selector와 일치하는 제공된 array로부터의 노드들의 array * @static */ DU.filter = function (nodes, selector) { return DU.util.LDomSelector.filter(nodes, selector); } })(); /** * The static String class provides helper functions to deal with data of type * Object. * @module core * @title DU Global * @namespace prototype * @class Object * @static */ /** * static String 클래스는 String 타입의 데이터를 처리하는데 도움을 주는 함수들을 제공한다. * @module core * @title DU Global * @namespace prototype * @class String * @static */ /** * @description 문자열에 모든 공백 제거 * @method trimAll * @return {String} 모든 공백 제거된 문자열 */ String.prototype.trimAll = function() { return DU.util.LString.trimAll(this); } /** * @description 문자열을 주어진 길이만큼 잘라낸다. * @method cut * @param {Int} start 시작위치 * @param {Int} length 잘라낼 길이 * @return {String} 잘라낸 후 문자열 */ String.prototype.cut = function(start, length) { return DU.util.LString.cut(this, start, length); } /** * @description 문자열을 처음부터 주어진 위치까지 잘라낸다. * @method lastCut * @param {Int} pos 잘라낼 위치 * @return {String} 잘라낸 후 문자열 */ String.prototype.lastCut = function(pos) { return DU.util.LString.lastCut(this, pos); } /** * @description 시작 문자열이 pattern에 맞는지 여부를 리턴한다. * @method startsWith * @param {String} pattern 문자패턴 * @return {Boolean} 결과 */ String.prototype.startsWith = function(pattern) { return DU.util.LString.startsWith(this, pattern); } /** * @description 종료 문자열이 pattern에 맞는지 여부를 리턴한다. * @method endsWith * @param {String} s 작업 대상 문자열 * @param {String} pattern 문자패턴 * @return {Boolean} 결과 */ String.prototype.endsWith = function(pattern) { return DU.util.LString.endsWith(this, pattern); } /** * 자바스크립트의 내장 객체인 String 객체에 simpleReplace 메소드를 추가한다. simpleReplace 메소드는 * 스트링 내에 있는 특정 스트링을 다른 스트링으로 모두 변환한다. String 객체의 replace 메소드와 동일한 * 기능을 하지만 간단한 스트링의 치환시에 보다 유용하게 사용할 수 있다. *
* var str = "abcde" * str = str.simpleReplace("cd", "xx"); ** 위의 예에서 str는 "abxxe"가 된다. * @param {String} oldStr required 바뀌어야 될 기존의 스트링 * @param {String} newStr required 바뀌어질 새로운 스트링 * @return {String} replaced String. */ String.prototype.simpleReplace = function(oldStr, newStr) { return DU.util.LString.simpleReplace(this, oldStr, newStr); } /** * 자바스크립트의 내장 객체인 String 객체에 insert 메소드를 추가한다. insert 메소드는 스트링의 특정 영역에 * 주어진 스트링을 삽입한다. *
* var str = "abcde" * str = str.insert(3, "xyz"); ** 위의 예에서 str는 "abcxyzde"가 된다. * @param {Int} index required 삽입할 위치. 해당 스트링의 index 바로 앞에 삽입된다. index는 0부터 시작. * @param {String} str required 삽입할 스트링. * @return {String} inserted String. */ String.prototype.insert = function(index, str) { return this.substring(0, index) + str + this.substr(index); } /** * @description 문자열을 구분자를 통해 잘라낸다. * @method advancedSplit * @param {String} delim 구분자 * @parma {String} 옵션 I : 옵션 T: * @return {Array} */ String.prototype.advancedSplit = function(delim, options){ return DU.util.LString.advancedSplit(this, delim, options); } /** * @description 첫 문자만 대문자로 변환한다. * @method firstUpperCase * @return {String} 변환 후 문자열 */ String.prototype.firstUpperCase = function() { return DU.util.LString.firstUpperCase(this); } /** * @description 스트링의 자릿수를 Byte 단위로 환산하여 알려준다. 영문, 숫자는 1Byte이고 한글은 2Byte이다.(자/모 중에 하나만 있는 글자도 2Byte이다.) * @method getByteLength * @static * @return {Int} 스트링의 길이 */ String.prototype.getByteLength = function() { return DU.util.LString.getByteLength(this); } /** * @description 입력된 문자열이 한글로 된 정보인지를 체크한다. 해당문자열이 한글과 스페이스의 조합일때만 true를 리턴한다. * @method isHangul * @return {Boolean} 한글 여부 */ String.prototype.isHangul = function() { return DU.util.LString.isHangul(this); } /** * static Date 클래스는 Date 타입의 데이터를 처리하는데 도움을 주는 함수들을 제공한다. * @module core * @title DU Global * @namespace prototype * @class Date * @static */ /** * startDate와 endDate 사이에 포함되어 있는지 여부 * @method between * @param {Date} startDate 범위 시작일자 * @param {Date} endDate 범위 종료일자The end of the range * @return {Boolean} 날짜가 비교날짜 사이에 있으면 true, 아닐 경우 false. */ Date.prototype.between = function(startDate, endDate){ return DU.util.LDate.between(this, startDate, endDate) } /** * Date객체의 Pattern에 따른 날짜 비교 * @method compareString * @param {Date} date2 Date2 객체 * @param {Date} pattern [optional] format pattern 문자 * @return {Boolean} true */ Date.prototype.compareString = function(date2, pattern){ pattern = pattern || { format: '%q' }; return DU.util.LDate.compareString(this, date2, pattern); } /** * 1일에 해당되는 Date 객체를 리턴 * @method getFirstDayOfMonth * @return {Date} The JavaScript Date representing the first day of the month */ Date.prototype.getFirstDayOfMonth = function(){ return DU.util.LDate.getFirstDayOfMonth(this); } /** * 마지막 날짜에 해당되는 Date 객체를 리턴 * @method getLastDayOfMonth * @return {Date} The JavaScript Date representing the first day of the month */ Date.prototype.getLastDayOfMonth = function(){ return DU.util.LDate.getLastDayOfMonth(this); } /** * startOfWeek에 해당되는 요일에 맞는 Date 객체를 리턴 * @method getFirstDayOfWeek * @param {Date} dt The date in the week for which the first day is required. * @param {Number} startOfWeek The index for the first day of the week, 0 = Sun, 1 = Mon ... 6 = Sat (defaults to 0) * @return {Date} The first day of the week */ Date.prototype.getFirstDayOfWeek = function(startOfWeek){ return DU.util.LDate.getFirstDayOfWeek(this, startOfWeek); } /** * static 문자열 클래스는 number 타입의 데이터를 처리하는데 도움을 주는 함수들을 제공한다. * @module core * @title DU Global * @namespace prototype * @class Array * @static */ /** * static Number 클래스는 Number 타입의 데이터를 처리하는데 도움을 주는 함수들을 제공한다. * @module core * @title DU Global * @namespace prototype * @class Number * @static */ /** * 사용자에게 표시하기 위한 native JavaScript Number와 문자열 포맷을 가져온다. * * @method format * @param nData {Number} Number. * @param {Object} oConfig (Optional) Optional 설정 값들: *
* var str = "abcde" * str = simpleReplace(str, "cd", "xx"); ** 위의 예에서 str는 "abxxe"가 된다. * @static * @param {String} str required 기존의 스트링 * @param {String} oldStr required 바뀌어야 될 기존의 스트링 * @param {String} newStr required 바뀌어질 새로운 스트링 * @return {String} replaced String. */ simpleReplace : function(str, oldStr, newStr) { var rStr = oldStr; rStr = rStr.replace(/\\/g, "\\\\"); rStr = rStr.replace(/\^/g, "\\^"); rStr = rStr.replace(/\$/g, "\\$"); rStr = rStr.replace(/\*/g, "\\*"); rStr = rStr.replace(/\+/g, "\\+"); rStr = rStr.replace(/\?/g, "\\?"); rStr = rStr.replace(/\./g, "\\."); rStr = rStr.replace(/\(/g, "\\("); rStr = rStr.replace(/\)/g, "\\)"); rStr = rStr.replace(/\|/g, "\\|"); rStr = rStr.replace(/\,/g, "\\,"); rStr = rStr.replace(/\{/g, "\\{"); rStr = rStr.replace(/\}/g, "\\}"); rStr = rStr.replace(/\[/g, "\\["); rStr = rStr.replace(/\]/g, "\\]"); rStr = rStr.replace(/\-/g, "\\-"); var re = new RegExp(rStr, "g"); return str.replace(re, newStr); }, /** * value의 값을 클립보드에 저장한 후 결과를 리턴한다. * @method toClipboard * @static * @param {String} value 저장할 값 * @return {boolean} 결과 여부 */ toClipboard: function(value) { try { if(window.clipboardData){ clipboardData.setData("text",value); return true; }else if(window.netscape){ //http://www-archive.mozilla.org/xpfe/xptoolkit/clipboard.html netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); var clip = Components.classes['@mozilla.org/widget/clipboard;1'].createInstance(Components.interfaces.nsIClipboard); if(!clip) return; var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable); if(!trans) return; trans.addDataFlavor('text/unicode'); var str = new Object(),len = new Object(); var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString); str.data=value; trans.setTransferData("text/unicode",str,value.length*2); var clipid=Components.interfaces.nsIClipboard; if(!clipid) return false; clip.setData(trans,null,clipid.kGlobalClipboard); return true; } } catch(e) { return false; } return false; }, /** * value의 값을 클립보드값을 리턴한다. * @method getClipboard * @static * @return {String} 결과 */ getClipboard: function() { try { if(window.clipboardData){ return clipboardData.getData("text");; }else if(window.netscape){ //http://www-archive.mozilla.org/xpfe/xptoolkit/clipboard.html netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect'); var clip = Components.classes['@mozilla.org/widget/clipboard;1'].createInstance(Components.interfaces.nsIClipboard); if (!clip) return; var trans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable); if (!trans) return; trans.addDataFlavor('text/unicode'); clip.getData(trans,clip.kGlobalClipboard); var str = new Object(); var len = new Object(); try { trans.getTransferData('text/unicode',str,len); } catch(error) { return; } if (str) { if (Components.interfaces.nsISupportsWString) str=str.value.QueryInterface(Components.interfaces.nsISupportsWString); else if (Components.interfaces.nsISupportsString) str=str.value.QueryInterface(Components.interfaces.nsISupportsString); else str = null; } if (str) return(str.data.substring(0,len.value / 2)); } } catch(e) { return false; } } }); DU.util.LString.format = /^((\w|[\-\.])+)@((\w|[\-\.])+)\.([A-Za-z]+)$/ })(); (function(){ 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(); }; /** * The static Date class provides helper functions to deal with data of type Date. * static Date 클래스는 Date 타입의 데이터를 처리하는데 도움을 주는 함수들을 제공한다. *
* 원인과 해결 방안은 다음에서 확인 가능하다: * http://brianary.blogspot.com/2006/03/safari-date-bug.html *
* @method _addDays * @param {Date} d 자바스크립트 date object * @param {Number} nDays date object에 추가할 날짜들의 숫자(음수 가능) * @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); }, /** * Subtracts the specified amount of time from the this instance. * 해당 인스턴스로 부터 지정된 분량의 시간을 차감한다. * @method subtract * @param {Date} date 차감시 수행할 자바스크립트 Date object * @param {Number} field 차감 실행에 대해 사용될 필드 상수 * @param {Number} amount date로부터 차감할 유닛들의 숫자(필드 상수에서 측정된) * @return {Date} Date object 결과 */ subtract: function(date, field, amount) { return this.add(date, field, (amount * -1)); }, /** * 주어진 날짜가 달력의 다른 날짜 이전인지 여부에 대하여 결정한다. * @method before * @param {Date} date 비교 argument와 비교할 Date object * @param {Date} compareTo 비교시 사용할 Date object * @return {Boolean} 비교 날짜 이전에 날짜가 있으면 true, 아니면 false */ before: function(date, compareTo) { var ms = compareTo.getTime(); if (date.getTime() < ms) { return true; } else { return false; } }, /** * 주어진 날짜가 달력의 다른날짜 이후인지 여부에 대하여 결정한다. * @method after * @param {Date} date 비교 argument와 비교할 Date object * @param {Date} compareTo 비교시 사용할 Date object * @return {Boolean} 비교 날짜 이후에 날짜가 있으면 true, 아니면 false */ after: function(date, compareTo) { var ms = compareTo.getTime(); if (date.getTime() > ms) { return true; } else { return false; } }, /** * 주어진 날짜가 달력의 두 날짜 사이에 있는지 여부에 대하여 결정한다. * @method between * @param {Date} date 체크할 날짜 * @param {Date} dateBegin 범위의 시작일 * @param {Date} dateEnd 범위의 종료일 * @return {Boolean} 비교할 날짜가 중간에 있으면 true, 아니면 false */ between: function(date, dateBegin, dateEnd) { if (this.after(date, dateBegin) && this.before(date, dateEnd)) { return true; } else { return false; } }, /** * Date객체의 Pattern에 따른 날짜 비교 * @method compareString * @param {Date} date1 Date1 객체 * @param {Date} date2 Date2 객체 * @param {Date} pattern format pattern 문자 * @return {Boolean} true */ compareString : function(date1, date2, pattern) { var dateString1 = this.format(date1, pattern); var dateString2 = this.format(date2, pattern); return (dateString1 == dateString2); }, /** * 주어진 연도의 1월 1일을 표시하는 자바스크립트 date object를 조회한다. * @method getJan1 * @param {Number} calendarYear 1월 1일을 조회하기 위한 달력의 연도 * @return {Date} 명시된 달력 연도의 1월 1일 */ getJan1: function(calendarYear) { return this.getDate(calendarYear, 0, 1); }, /** * 특정 연도의 1월 1일부터 특정 일자까지의 일수를 계산한다. * 0의 offset 값을 이 함수에서 반환하기 위해서는 1월 1일을 전달한다. * @method getDayOffset * @param {Date} date offset을 찾을 자바크스립트 date * @param {Number} calendarYear offset을 결정하기 위해 사용하는 연도 * @return {Number} 주어진 연도의 1월 1일 부터의 일수 */ getDayOffset: function(date, calendarYear) { var beginYear = this.getJan1(calendarYear); // Find the start of the year. This will be in week 1. // Find the number of days the passed in date is away from the calendar year start var dayOffset = Math.ceil((date.getTime() - beginYear.getTime()) / this.ONE_DAY_MS); return dayOffset; }, /** * 주어진 날짜에 대한 week number를 계산한다. * 올해의 첫번째 주를 1월 1일로 정의하는 것에 기반하는 standard U.S. week number와 * 올해의 첫번째 주를 1월 4일로 정의하는 것에 기반하는 ISO8601 week number를 일번적으로 지원할 수 있다. * * @method getWeekNumber * @param {Date} date week number를 찾을 자바스크립트 date * @param {Number} firstDayOfWeek 주의 첫번째 날짜의 인덱스(0 = Sun, 1 = Mon ... 6 = Sat). 기본값은 0 * @param {Number} janDate 올해의 한주를 정의 하는 1월의 첫째주의 date * 기본값은 1(Jan 1st)인, DU.widget.LDateMath.WEEK_ONE_JAN_DATE의 값. * U.S에 대해서는 일반적으로 1월 1일 이다. ISO8601은 올해의 첫째주를 정의하기 위하여 1월 4일을 사용한다. * @return {Number} 주어진 날짜를 포함하는 week numner */ getWeekNumber: function(date, firstDayOfWeek, janDate) { // Setup Defaults firstDayOfWeek = firstDayOfWeek || 0; janDate = janDate || this.WEEK_ONE_JAN_DATE; var targetDate = this.clearTime(date), startOfWeek, endOfWeek; if (targetDate.getDay() === firstDayOfWeek) { startOfWeek = targetDate; } else { startOfWeek = this.getFirstDayOfWeek(targetDate, firstDayOfWeek); } var startYear = startOfWeek.getFullYear(), startTime = startOfWeek.getTime(); // DST shouldn't be a problem here, math is quicker than setDate(); endOfWeek = new Date(startOfWeek.getTime() + 6 * this.ONE_DAY_MS); var weekNum; if (startYear !== endOfWeek.getFullYear() && endOfWeek.getDate() >= janDate) { // If years don't match, endOfWeek is in Jan. and if the // week has WEEK_ONE_JAN_DATE in it, it's week one by definition. weekNum = 1; } else { // Get the 1st day of the 1st week, and // find how many days away we are from it. var weekOne = this.clearTime(this.getDate(startYear, 0, janDate)), weekOneDayOne = this.getFirstDayOfWeek(weekOne, firstDayOfWeek); // Round days to smoothen out 1 hr DST diff var daysDiff = Math.round((targetDate.getTime() - weekOneDayOne.getTime()) / this.ONE_DAY_MS); // Calc. Full Weeks var rem = daysDiff % 7; var weeksDiff = (daysDiff - rem) / 7; weekNum = weeksDiff + 1; } return weekNum; }, /** * 주어진 날짜에 대한 주의 첫번째 날짜를 가져 온다. * @param {Date} dt 첫번째 날짜가 필요한 주의 date * @param {Number} startOfWeek 주의 첫번째 날짜에 대한 인덱스, 0 = Sun, 1 = Mon ... 6 = Sat (기본값은 0) * @return {Date} 주의 첫번째 날짜 */ getFirstDayOfWeek: function(dt, startOfWeek) { startOfWeek = startOfWeek || 0; var dayOfWeekIndex = dt.getDay(), dayOfWeek = (dayOfWeekIndex - startOfWeek + 7) % 7; return this.subtract(dt, this.DAY, dayOfWeek); }, /** * 주어진 week가 두개의 다른 연도에 겹쳐지는지 대한 여부를 결정한다. * @method isYearOverlapWeek * @param {Date} weekBeginDate 주의 첫번째 날짜를 표시하는 자바스크립트 Date * @return {Boolean} 날짜가 두개의 다른 연도에 겹쳐지면 true */ isYearOverlapWeek: function(weekBeginDate) { var overlaps = false; var nextWeek = this.add(weekBeginDate, this.DAY, 6); if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) { overlaps = true; } return overlaps; }, /** * 주어진 week가 두개의 다른 달에 겹쳐지는지 대한 여부를 결정한다. * @method isMonthOverlapWeek * @param {Date} weekBeginDate 주의 첫번째 날짜를 표시하는 자바스크립트 Date * @return {Boolean} 날짜가 두개의 다른 달에 겹쳐지면 true */ isMonthOverlapWeek: function(weekBeginDate) { var overlaps = false; var nextWeek = this.add(weekBeginDate, this.DAY, 6); if (nextWeek.getMonth() != weekBeginDate.getMonth()) { overlaps = true; } return overlaps; }, /** * 주어진 날짜를 포함하는 달의 첫번째 날짜를 가져온다. * @method getFirstDayOfMonth * @param {Date} date 달의 시작을 계산하는데 사용할 자바스크립트 Date * @return {Date} 달의 첫째날을 표시하는 자바스크립트 Date */ getFirstDayOfMonth: function(date) { var start = this.getDate(date.getFullYear(), date.getMonth(), 1); return start; }, /** * 주어진 날짜를 포함하는 달의 마지막 날짜를 가져온다. * @method getLastDayOfMonth * @param {Date} date 달의 끝을 계산하는데 사용할 자바스크릅트 Date * @return {Date} 달의 마지막날을 표시하는 자바스크립트 Date */ getLastDayOfMonth: function(date) { var start = this.getFirstDayOfMonth(date); var nextMonth = this.add(start, this.MONTH, 1); var end = this.subtract(nextMonth, this.DAY, 1); return end; }, /** * 주어진 날짜로부터 시간 필드를 초기화 하고, 효과적으로 시간을 낮 12시로 설정한다. * @method clearTime * @param {Date} date 초기화할 시간 필드에 대한 자바스크립트 Date * @return {Date} 모든 시간 필드들이 초기화 된 자바스크립트 Date */ clearTime: function(date) { date.setHours(12, 0, 0, 0); return date; }, /** * 주어진 년, 월, 일을 표시하는 새로운 자바스크립트 Date object를 반환한다. * 새로운 Date object의 시간 필드(hr, min, sec, ms)들은 0으로 설정된다. * method는 100이하의 연도로 생성되기 위한 Date 인스턴스들을 허용한다. * "new Date(year, month, date)" 구현은 100 이하의 year (xx)가 제공되는 경우 * 19xx로 연도를 설정한다. ** NOTE:argument의 Validation은 실행되지 않는다. * new Date(year, month[, date]) 생성자에 대해 ECMAScript-262 Date object 명시에 따라서 * argument의 적합성을 확보하는 것은 caller의 책임이다. *
* @method getDate * @param {Number} y Year. * @param {Number} m 0(Jan)부터 11(Dec)까지의 월 인덱스 * @param {Number} d (optional) 1부터 31까지의 날짜. 만약 제공되지 않으면 기본적으로 1. * @return {Date} 제공된 년월일로 설정된 자바스크립트 date object */ getDate: function(y, m, d) { var dt = null; if (DU.isUndefined(d)) { d = 1; } if (y >= 100) { dt = new Date(y, m, d); } else { dt = new Date(); dt.setFullYear(y); dt.setMonth(m); dt.setDate(d); dt.setHours(0, 0, 0, 0); } return dt; }, /***************************************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' }, /** * native JavaScript Date를 가져와서 사용자에게 표시할 문자열로 포맷화 한다. * * @method format * @param oDate {Date} Date. * @param {Object} oConfig (Optional) 부가적인 설정 값들 * @return {String} 표시를 위한 형식화된 날짜 */ format : function (oDate, oConfig) { oConfig = typeof oConfig === 'string' ? {format: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 get locale, default and so on... * @param {String} sLocale * @return DU.util.LDateLocale */ getLocale : function (sLocale){ sLocale = sLocale || DU.getConfig().getFirst("$.core.defaultLocale") || "en"; // Make sure we have a definition for the requested locale, or default to en. /* if(!(sLocale in DU.util.LDateLocale)) { if(sLocale.replace(/-[a-zA-Z]+$/, '') in DU.util.LDateLocale) { sLocale = sLocale.replace(/-[a-zA-Z]+$/, ''); } else { sLocale = "en"; } } */ 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 inx월에 해당되는 마지막 날짜 * @method getDayInMonth * @param {Int} inx * @return {Int} */ getDayInMonth : function(inx) { return DU.util.LDate.DAYS_IN_MONTH[inx]; }, /** * @description inx월에 다국어 표현 날짜 (예: 01월) * @method getMonthInYear * @param {Int} inx * @return {String} */ getMonthInYear : function(inx) { return DU.getMessageManager().get('$.core.monthInYear')[inx]; }, /** * @description inx월에 다국어 표현 짧은 날짜 (예: 1월) * @method getShortMonthInYear * @param {Int} inx * @return {String} */ getShortMonthInYear : function(inx) { return DU.getMessageManager().get('$.core.shortMonthInYear')[inx]; }, /** * @description inx에 해당되는 다국어 요일 (예: 월요일) * @method getDayInWeek * @param {Int} inx * @return {String} */ getDayInWeek : function(inx) { return DU.getMessageManager().get('$.core.dayInWeek')[inx]; }, /** * @description inx에 해당되는 다국어 짧은 요일 (예: 월) * @method getShortDayInWeek * @param {Int} inx * @return {String} */ getShortDayInWeek : function(inx) { return DU.getMessageManager().get('$.core.shortDayInWeek')[inx]; }, /** * @description o의 객체가 Date객체인지 여부 * @method isDate * @param {Object} o * @return {boolean} */ isDate : function(o) { return o && (typeof o.getFullYear == 'function'); } }; /** * 형식화된 문자열에 기반한 문자열로부터 세부 시간을 파싱하는 *strptime
의 부분적인 구현.
*
* 이러한 구현은 대부분 [00,59]보다 [00,61]을 제한하는 second format의 익셉션을 가진
* http://docs.python.org/lib/module-Dt.html에 문서화 된
* Python의 time
모듈에 대한 문서로 부터 cue를 가져온다.
*
* 지원되는 서식은 다음과 같다: *
Directive | *Meaning | *
---|---|
%b |
* Locale의 단축 월 이름 | *
%B |
* Locale의 전체 월 이름 | *
%d |
* [01,31]의 10진수로 된 월의 날짜. | *
%H |
* [00,23]의 10진수로 된 시간(24시간제). | *
%I |
* [00,12]의 10진수로 된 시간(12시간제). | *
%m |
* [01.12]의 10진수로 된 월. | *
%M |
* [00,59]의 10진수로 된 분. | *
%p |
*
* 지역의 AM이나 PM 여부 표시(시간을 파싱하기 위하여 %I 지시어가
* 사용되는 경우 시간 필드 출력에만 영향을 준다.)
* |
*
%S |
* [00,59]의 10진수로 된 초. | *
%y |
* [00,99]의 10진수로 된 세기값이 없는 년도. | *
%Y |
* 10진수로 된 세기값이 있는 년도. | *
%% |
* "%" 리터럴 문자. | *
regexp
에
* 의해 매치될 예상되는 서식 지시어 코드 목록
*
* @type Array
*/
this.expected = expected;
};
/**
* 지시어에 해당하는 데이터나 locale에 의존하는 지시어의 경우 locale을 가져가고
* 정규 표현식 패턴 조각을 생성하는 함수를 캡쳐하는 정규 표현식 패턴 조각에 지시 코드를 맵핑한다.
*
* @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
};
/**
* 여러 데이터 항목들을 포함할수 있는 몇몇 지시어 목록으로 지정된 각 지시어에 대해
* 예상되는 캡쳐된 지시어 코드에 대하여 지시어 코드를 매핑한다.
*
* @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 | *
* var mm = new DU.message.LMessageManager(); * mm.setLocale('ko_KR'); ** @method setLocale * @param {String} currentLocale 변경하고자 하는 locale 정보 * @return void */ setLocale : function(currentLocale) { this.currentLocale = currentLocale; }, /** * 메시지 데이터를 직접 추가한다. *
* var localeData = { locale : 'ko_KR', message:{test:'테스트'} } * var mm = new DU.message.LMessageManager(); * mm.addLocaleData(localeData); ** @method addLocaleData * @param {Object} localeData 실제 메시지 데이터를 가지는 객체 * @return void */ addLocaleData : function(localeData) { if(!localeData.locale) { throw new TypeError("LMessageManager.addLocaleData(): Not found locale attribute in localeData."); } var oldData = this.localeData[localeData.locale] || {}; var rootLevel = ["core", "base", "message"]; for(var i = 0 ; i < rootLevel.length ; i++) { if(!oldData[rootLevel[i]]) { oldData[rootLevel[i]] = {} } } for(var i = 0 ; i < rootLevel.length ; i++) { var levelCode = rootLevel[i]; for(m in localeData[levelCode]) { if(!Object.prototype[m]) { oldData[levelCode][m] = localeData[levelCode][m]; } } } this.localeData[localeData.locale] = oldData; }, /** * 메시지 데이터를 읽어 온다. *
* var mm_Ko = new DU.message.LMessageManager(); * mm_Ko.load({locale:'ko_KR'}); * alert(mm_Ko.get('$.core.test')); * var mm_En = new DU.message.LMessageManager({locale:'en_US'}); * * var newData_ko_KR = { * locale:'ko_KR', * message : { * test2:'?쒓?' * } * } * * var newData_en_US = { * locale:'en_US', * message : { * test2:'english' * } * } * * mm_Ko.addLocaleData(newData_ko_KR); * mm_En.addLocaleData(newData_en_US); * * var data = mm_Ko.get('$.message.test2'); * alert(data); * * var data = mm_En.get('$.message.test2'); * alert(data); ** @method get * @param {Object} name 읽어오고자하는 메시지 키값 * @param {Array} paramArray 읽어올때 @로 대체될 값 * @return {String} 결과 메시지 */ get : function(name, paramArray, locale) { if(DU.isUndefined(name)) { throw new TypeError("LMessageManager.get(): not found name attribute"); } if(!DU.isUndefined(locale)) this.setLocale(locale); var currentLocaleData = this.localeData[this.currentLocale]; var message = currentLocaleData ? DU.util.LJson.jsonPath(currentLocaleData, name, {resultType: "VALUE"})[0] : null; if(DU.isNull(message) || DU.isUndefined(message)) { if(this.isAutoLoad) { this.load({locale:this.currentLocale}); currentLocaleData = this.localeData[this.currentLocale]; if (!currentLocaleData) { throw new Error('LMessageManager.get(): Not found message Data. : ' + this.currentLocale); } message = DU.util.LJson.jsonPath(currentLocaleData, name, {resultType: "VALUE"})[0]; } else { throw new Error('LMessageManager.get(): Not found message Data. : ' + this.currentLocale); } } if (DU.isNull(message) || DU.isUndefined(message)) { throw new Error('LMessageManager.get(): Not found message.'); } if(message == false) return null; var index = 0; var re = /@/g; var count = 0; if (paramArray == null) { return message; } while ( (index = message.indexOf("@", index)) != -1) { if (paramArray[count] == null) { paramArray[count] = ""; } message = message.substr(0, index) + String(paramArray[count]) + message.substring(index + 1); index = index + String(paramArray[count++]).length; } return message; }, /** * Locale에 해당되는 데이터를 읽어온다. * @method load * @param {Object} oConfig 읽어올 환경정보를 가지는 객체 * @return void */ load : function(oConfig) { oConfig = oConfig ? oConfig : {locale:this.currentLocale}; this.createRootLocale(oConfig); // 업무 메시지 로드 var contextPath = DU.getConfig().getFirst('$.core.contextPath'); var dujsfRootPath = DU.getConfig().getFirst('$.core.dujsfRootPath'); var localePath = DU.getConfig().getFirst('$.core.message.localePath'); if(!oConfig.jsFile) { oConfig.jsFile = 'lang-' + oConfig.locale + '.js'; } DU.includeJs(contextPath + dujsfRootPath + localePath + '/' + oConfig.jsFile, true); var currentLocaleData = eval('DU.message.locale.' + oConfig.locale); this.addLocaleData(currentLocaleData); }, /** * Core Locale에 해당되는 데이터를 읽어온다. * @method createRootLocale * @param {Object} oConfig 읽어올 환경정보를 가지는 객체 * @return void */ createRootLocale : function(oConfig) { // core 메시지 로드 this.fireEvent('createRootLocale'); var localeObj = eval('DU.message.locale.' + oConfig.locale); if(DU.isUndefined(localeObj)) { DU.namespace('DU.message.locale.' + oConfig.locale); } } }); (function() { // internal shorthand var Dom = DU.util.LDom, LAttributeProvider = DU.util.LAttributeProvider; DU.applyObject(DU.LElement.prototype, { /** * box-model 이슈를 위해 width와 height 설정을 자동으로 * 조절하기 위해서 true로 설정(기본적으로 true) */ autoBoxAdjust : true, /** * The default unit to append to CSS values where a unit isn't provided (defaults to px). * unit이 제공되지 않는 CSS 값들에 추가하기 위한 기본 unit(기본적으로 px). * @property defaultUnit * @type String */ defaultUnit : 'px', /** * @description element의 disabled CSS * @property CSS_ELEMENT_DISABLED * @private * @type {String} */ CSS_ELEMENT_DISABLED : 'L-disabled', /** * @description element의 invalid CSS * @property CSS_ELEMENT_INVALID * @private * @type {String} */ CSS_ELEMENT_INVALID : "L-invalid", /** * @description element의 repaint CSS * @property CSS_ELEMENT_REPAINT * @private * @type {String} */ CSS_ELEMENT_REPAINT : "L-repaint", /** * @description element의 masked CSS * @property CSS_ELEMENT_MASKED * @private * @type {String} */ CSS_ELEMENT_MASKED : "L-masked", /** * @description element의 masked의 출력 Panel CSS * @property CSS_ELEMENT_MASKED_PANEL * @private * @type {String} */ CSS_ELEMENT_MASKED_PANEL : "L-masked-panel", /** * @description 제공된 노드가 제공된 selector와 일치하는 경우를 테스트. * @method test * @param {string} selector node를 대상으로 테스트할 CSS LDomSelector. * @return{boolean} 노드가 selector와 일치하는지에 대한 여부. * @static */ test : function(selector) { return DU.util.LDomSelector.test(this.dom, selector); }, /** * @description HTMLElement method에 대한 Wrapper. * @method removeChild * @param {HTMLElement} child 삭제할 HTMLElement * @return {HTMLElement} 삭제된 DOM element. */ removeChild: function(child) { child = child.get ? child.get('element') : child; return this.get('element').removeChild(child); }, /** * @description HTMLElement method에 대한 Wrapper. * @method replaceChild * @param {HTMLElement} newNode 삽입할 HTMLElement * @param {HTMLElement} oldNode 교체할 HTMLElement * @return {HTMLElement} 교체된 DOM element. */ replaceChild: function(newNode, oldNode) { newNode = newNode.get ? newNode.get('element') : newNode; oldNode = oldNode.get ? oldNode.get('element') : oldNode; return this.get('element').replaceChild(newNode, oldNode); }, /** * HTMLElement chid 노드들의 array를 반환한다. * @static * @method getChildren * @return {Array} HTMLElement들의 static array */ getChildren : function(isDom) { var list = DU.util.LDom.getChildren(this.dom); if(!isDom || isDom === true) { for(var i = 0 ; i < list.length ; i++) list[i] = DU.get(list[i]); } return list; }, /** * @description mouse over시 class 적용 * @method addClassOnOver * @param {String} className 추가할 클래스 이름 * @return {DU.LElement} this */ addClassOnOver : function(className) { var me = this; me.hover(function(){ me.addClass(className); }, function(){ me.removeClass(className); }); return me; }, /** * @description mouse focus시 class 적용 * @method addClassOnFocus * @param {String} className 추가할 클래스 이름 * @return {DU.LElement} this */ addClassOnFocus : function(className) { var me = this; me.on('focus', function(e) { me.addClass(className); }, me.dom); me.on('blur', function(e) { me.removeClass(className); }, me.dom); return me; }, /** * @description mouse click시 class 적용 * @method addClassOnClick * @param {String} className 추가할 클래스 이름 * @return {DU.LElement} this */ addClassOnClick : function(className) { var me = this; me.on('mousedown', function(e) { me.addClass(className); }, me.dom); var mouseUp = function(e) { me.removeClass(className); me.unOn('blur', mouseUp); } me.on("mouseup", mouseUp, me.dom); return me; }, /** * @description Dom method를 위한 Wrapper. * @method replaceClass * @param {String} oldClassName 교체할 클래스 이름 * @param {String} newClassName 추가할 클래스 이름 */ replaceClass: function(oldClassName, newClassName) { return Dom.replaceClass(this.get('element'), oldClassName, newClassName); }, /** * @description toggle시에 class를 추가하거나 제거한다. * @method toggleClass * @param {String} className 추가할 클래스 이름 * @return {DU.LElement} this */ toggleClass: function(className) { return this.hasClass(className) ? this.removeClass(className) : this.addClass(className); }, /** * @description style 정보를 모두 적용한다. * @method applyStyles * @param {String|Object|Function} styles 적용할 style정보 * @return {DU.LElement} this */ applyStyles : function(styles){ DU.util.LDom.applyStyles(this, styles); return this; }, /** * @description 페이지 좌표에 기반한 element의 현재 위치를 가져온다. * element는 반드시 페이지 좌표를 가지는 DOM 트리의 부분이어야 한다 * (display:none 혹은 element들이 추가되어 있지 않으면 false를 반환). * @method getXY * @return {Array} element의 XY 위치 */ getXY: function() { return Dom.getXY(this.dom); }, /** * @description element가 위치되는 방법에 개의치 않고 페이지 좌표에서 html element의 위치를 설정한다. * element는 반드시 페이지 좌표를 가지는 DOM 트리의 부분이어야 한다 * (display:none 혹은 element들이 추가되어 있지 않으면 false를 반환). * @method setXY * @param {Array} pos 새 위치에 대한 X & Y를 포함한 값들(페이지에 기반한 좌표) * @param {Boolean} noRetry 첫번째가 실패할 경우 기본적으로 두번째로 위치를 설정한다. */ setXY: function(pos, noRetry) { return Dom.setXY(this.dom, pos, noRetry); }, /** * @description 페이지 좌표에 기반한 element의 현재 X 위치를 가져온다. * element는 반드시 페이지 좌표를 가지는 DOM 트리의 부분이어야 한다 * (display:none 혹은 element들이 추가되어 있지 않으면 false를 반환). * @method getX * @return {Number | Array} element의 X 위치 */ getX: function() { return Dom.getX(this.dom); }, /** * @description element가 위치되는 방법에 개의치 않고 페이지 좌표에서 html element의 X 위치를 설정한다. * element는 반드시 페이지 좌표를 가지는 DOM 트리의 부분이어야 한다 * (display:none 혹은 element들이 추가되어 있지 않으면 false를 반환). * @method setX * @param {Int} x element에 대한 X 좌표로 사용할 값. */ setX: function(x) { return Dom.setX(this.dom, x); }, /** * @description 페이지 좌표에 기반한 element의 현재 Y 위치를 가져온다. * element는 반드시 페이지 좌표를 가지는 DOM 트리의 부분이어야 한다 * (display:none 혹은 element들이 추가되어 있지 않으면 false를 반환). * @method getY * @return {Number | Array} element의 Y 위치 */ getY: function() { return Dom.getY(this.dom); }, /** * @description element가 위치되는 방법에 개의치 않고 페이지 좌표에서 html element의 Y 위치를 설정한다. * element는 반드시 페이지 좌표를 가지는 DOM 트리의 부분이어야 한다 * (display:none 혹은 element들이 추가되어 있지 않으면 false를 반환). * @method setY * @param {Int} y element에 대한 Y 좌표로 사용할 값. */ setY: function(y) { return Dom.setY(this.dom, y); }, /** * @description element가 위치되는 방법에 개의치 않고 페이지 좌표에서 element의 위치를 설정한다. * element는 반드시 페이지 좌표를 가지는 DOM 트리의 부분이어야 한다 * (display:none 혹은 element들이 추가되어 있지 않으면 false를 반환). * @method moveTo * @param {Number} x 새로운 위치에 대한 X값(페이지에 기반한 좌표) * @param {Number} y 새로운 위치에 대한 Y값(페이지에 기반한 좌표) * @param {Boolean/Object} anim (optional) 기본 animation에 대한 true, * 혹은 표준 standard Element animation config object * @return {DU.LElement} this */ moveTo : function(x, y, anim){ if(anim) { if(anim === true) anim = { points: { to: [x, y] } }; anim = DU.applyIf(anim, { type: 'LMotion' }); } var currAnim = this.getAnimation(anim, this.dom.id); (currAnim != null) ? currAnim.animate() : this.setXY([x, y]); return this; }, /** * @description animation 효과를 적용한다. * @method animate * @param {Object} anim animation 효과를 적용할 정보 * @return {DU.LElement} this */ animate: function(anim) { anim.type = anim.type || 'LMotion'; var currAnim = this.getAnimation(anim, this.dom.id); if (currAnim != null) { if (anim.delay) { DU.util.LFunction.defer(function(){ if (anim.onStart) currAnim.onStart.on(anim.onStart); currAnim.animate(); }, anim.delay, this); } else { if (anim.onStart) currAnim.onStart.on(anim.onStart); currAnim.animate(); } } return this; }, /* * @private */ addUnits : function(v, defaultUnit){ if(v === "" || v == "auto"){ return v; } if(v === undefined){ return ''; } if(typeof v == "number" || !El.unitPattern.test(v)){ return v + (defaultUnit || 'px'); } return v; }, /** * @description CSS 스타일을 사용하여 element의 left 위치를 직접 설정한다. ({@link #setX} 대신). * @method setLeft * @param {String} left left CSS property 값 * @return {DU.LElement} this */ setLeft : function(left){ this.setStyle("left", this.addUnits(left)); return this; }, /** * @description CSS 스타일을 사용하여 element의 top 위치를 직접 설정한다. ({@link #setY} 대신). * @method setTop * @param {String} top top CSS property 값 * @return {DU.LElement} this */ setTop : function(top){ this.setStyle("top", this.addUnits(top)); return this; }, /** * @description element의 CSS right 스타일을 설정한다. * @method setRight * @param {String} right right CSS property 값 * @return {DU.LElement} this */ setRight : function(right){ this.setStyle("right", this.addUnits(right)); return this; }, /** * @description element의 CSS bottom 스타일을 설정한다. * @method setBottom * @param {String} bottom bottom CSS property 값 * @return {DU.LElement} this */ setBottom : function(bottom){ this.setStyle("bottom", this.addUnits(bottom)); return this; }, /** * @description size를 설정한다. * @method setSize * @param {String} width element의 width offset * @param {String} height element의 height offset * @param {Boolean/Object} anim (optional) 기본 animation에 대한 true, * 혹은 표준 standard Element animation config object * @return {DU.LElement} this */ setSize : function(width, height, anim) { if(anim) { if(anim === true) anim = { width: { to: width }, height: { to: height } }; anim = DU.applyIf(anim, { type: 'LAnim' }); } var currAnim = this.getAnimation(anim, this.dom.id); if (currAnim != null) { currAnim.animate(); } else { this.setWidth(width); this.setHeight(height); } }, /** * @description left X 좌표를 가져온다. * @method getLeft * @param {Boolean} local 페이지 좌표 대신 local css 위치를 가져오기 위해서는 true * @return {Number} */ getLeft : function(local){ return !local ? this.getX() : parseInt(this.getStyle("left"), 10) || 0; }, /** * @description element의 right X 좌표를 가져온다.(element의 X 위치 + element width) * @method getRight * @param {Boolean} local 페이지 좌표 대신 local css 위치를 가져오기 위해서는 true * @return {Number} */ getRight : function(local){ return !local ? this.getX() + this.getWidth() : (this.getLeft(true) + this.getWidth()) || 0; }, /** * @description top Y 좌표를 가져온다. * @method getTop * @param {Boolean} local 페이지 좌표 대신 local css 위치를 가져오기 위해서는 true * @return {Number} */ getTop : function(local) { return !local ? this.getY() : parseInt(this.getStyle("top"), 10) || 0; }, /** * @description element의 bottom Y 좌표를 가져온다.(element의 Y 위치 + element height) * @method getBottom * @param {Boolean} local 페이지 좌표 대신 local css 위치를 가져오기 위해서는 true * @return {Number} */ getBottom : function(local){ return !local ? this.getY() + this.getHeight() : (this.getTop(true) + this.getHeight()) || 0; }, /** * @description 큐에 설정된 call들을 적용한다. * @method fireQueue */ fireQueue: function() { var queue = this._queue; for (var i = 0, len = queue.length; i < len; ++i) { this[queue[i][0]].apply(this, queue[i][1]); } }, /** * @description 제공된 parent 노드에 HTMLElement를 추가한다. * @method appendTo * @param {HTMLElement | Element} parentNode 추가될 노드 * @param {HTMLElement | Element} before 이전에 삽입할 부가적인 노드 * @return {HTMLElement} 추가된 DOM element */ appendTo: function(parent, before) { parent = (parent.get) ? parent.get('element') : Dom.get(parent); this.fireEvent('beforeAppendTo', { type: 'beforeAppendTo', target: parent }); before = (before && before.get) ? before.get('element') : Dom.get(before); var element = this.get('element'); if (!element) { return false; } if (!parent) { return false; } if (element.parent != parent) { if (before) { parent.insertBefore(element, before); } else { parent.appendChild(element); } } this.fireEvent('appendTo', { type: 'appendTo', target: parent }); return element; }, /** * @description attribute의 현재 값을 반환한다. * @method get * @param {String} key 반환될 값을 가진 attribute. * @return {Any} attribute의 현재 값. */ get: function(key) { var configs = this._configs || {}; var el = configs.element; // avoid loop due to 'element' if (el && !configs[key] && !DU.isUndefined(el.value[key]) ) { return el.value[key]; } return LAttributeProvider.prototype.get.call(this, key); }, /** * @description 여러 attribute의 값들을 설정한다. * @method setAttributes * @param {Object} map attribute들의 key-value map * @param {Boolean} silent change event들의 억제 여부 */ setAttributes: function(map, silent){ var el = this.get('element'); for (var key in map) { // need to configure if setting unconfigured HTMLElement attribute if ( !this._configs[key] && !DU.isUndefined(el[key]) ) { this.setAttributeConfig(key); } } // set based on configOrder for (var i = 0, len = this._configOrder.length; i < len; ++i) { if (map[this._configOrder[i]] !== undefined) { this.set(this._configOrder[i], map[this._configOrder[i]], silent); } } }, /** * 현재 overflow 설정을 저장하고 element의 overflow를 고정시킨다. - 삭제하기 위해서 {@link #unclip}를 사용한다. * @method clip * @return {DU.LElement} this */ clip : function(){ if(!this.isClipped){ this.isClipped = true; this.originalClip = { o: this.getStyle("overflow"), x: this.getStyle("overflow-x"), y: this.getStyle("overflow-y") }; this.setStyle("overflow", "hidden"); this.setStyle("overflow-x", "hidden"); this.setStyle("overflow-y", "hidden"); } return this; }, /** * @description {@link #clip} 호출되기 전에 원래 clip된 overflow를 반환한다. * @method unclip * @return {DU.LElement} this */ unclip : function(){ if(this.isClipped){ this.isClipped = false; var o = this.originalClip; if(o.o){this.setStyle("overflow", o.o);} if(o.x){this.setStyle("overflow-x", o.x);} if(o.y){this.setStyle("overflow-y", o.y);} } return this; }, /** * @description 객체를 다시 그린다. * @method repaint * @return {DU.Elemnent} this */ repaint : function() { var thisObj = this; if(!thisObj.hasClass(thisObj.CSS_ELEMENT_REPAINT)) thisObj.addClass(thisObj.CSS_ELEMENT_REPAINT); setTimeout(DU.util.LFunction.createDelegate(function() { thisObj.removeClass(thisObj.CSS_ELEMENT_REPAINT); }, thisObj), 1); return thisObj; }, /** * 특정 anchor 포인트들로 연결되는 다른 element를 가지고 해당 element를 정렬한다. * 다른 element가 socument인 경우 그것은 viewport(화면상의 화상표시 영역)로 정렬한다. * 다음은 지원되는 anchor 위치들의 모든 목록이다: tl, t, tr, l, c, r, bl, b, br * @param {Mixed} element 정렬할 element * @param {String} position 정렬할 위치 * @param {Array} offsets (optional) [x, y]에 의한 위치 offset * @return {DU.LElement} this */ alignTo : function(element, position, offsets){ return this.setXY(this.getAlignToXY(element, position, offsets)); }, /** * element의 anchor 위치에 의해 명시된 x,y 좌표를 가져온다. * @param {String} anchor (optional) 명시된 anchor 위치(기본적으로 "c"). * 제공되는 anchor 위치들에 대한 세부사항은 {@link #alignTo}을 참조한다. * @param {Boolean} local (optional) 페이지 좌표대신 local (element top/left-relative) anchor 위치를 * 가져오기 위해서는 true * of page coordinates * @param {Object} size (optional) anchor 위치를 계산하기 위해 사용되는 size를 포함한 object * {width: (target width), height: (target height)} (기본적으로 element의 현재 사이즈) * @return {Array} [x, y] element의 x와 y 좌표를 포함하는 array */ getAnchorXY : function(anchor, local, s){ anchor = (anchor || "tl").toLowerCase(); s = s || {}; var vp = this.dom == document.body || this.dom == document; var w = s.width || vp ? DU.util.LDom.getViewportWidth() : this.getWidth(); var h = s.height || vp ? DU.util.LDom.getViewportHeight() : this.getHeight(); var xy; var r = Math.round; var o = this.getXY(); var scroll = this.getScroll(); var extraX = vp ? scroll.left : !local ? o[0] : 0; var extraY = vp ? scroll.top : !local ? o[1] : 0; var hash = { c: [r(w * 0.5), r(h * 0.5)], t: [r(w * 0.5), 0], l: [0, r(h * 0.5)], r: [w, r(h * 0.5)], b: [r(w * 0.5), h], tl: [0, 0], bl: [0, h], br: [w, h], tr: [w, 0] }; xy = hash[anchor]; return [xy[0] + extraX, xy[1] + extraY]; }, /** * 다른 element와 해당 element를 정렬하기 위한 x,y 좌표를 가져온다. * 지원되는 위치 값들에 대한 더 많은 정보를 위해서는 {@link #alignTo}를 참조한다. * @param {Mixed} element 정렬하기 위한 element * @param {String} position 정렬하기 위한 위치 * @param {Array} offsets (optional) [x, y]에 의한 위치 offset * @return {Array} [x, y] */ getAlignToXY : function(el, p, o){ el = DU.get(el); if(!el || !el.dom) throw "LElement.alignToXY with an element that doesn't exist"; o = o || [0,0]; p = (p == "?" ? "tl-bl?" : (!/-/.test(p) && p !== "" ? "tl-" + p : p || "tl-bl")).toLowerCase(); var d = this.dom, a1, a2, w, h, x, y, r, c = false, p1 = "", p2 = ""; var dw = DU.util.LDom.getViewportWidth() -10, // ie는 margin 10px dh = DU.util.LDom.getViewportHeight()-10; // ie는 margin 10px var p1y, p1x, p2y, p2x, swapY, swapX; var doc = document, docElement = doc.documentElement, docBody = doc.body; var scrollX = (docElement.scrollLeft || (docBody && docBody.scrollLeft) || 0)+5; var scrollY = (docElement.scrollTop || (docBody && docBody.scrollTop) || 0)+5; var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/); if(!m) throw "LElement.alignTo with an invalid alignment " + p; p2 = m[2]; p1 = m[1]; c = !!m[3]; a2 = el.getAnchorXY(p2, false); a1 = this.getAnchorXY(p1, true); x = a2[0] - a1[0] + o[0]; y = a2[1] - a1[1] + o[1]; if(c){ h = this.getHeight(); w = this.getWidth(); r = el.getRegion(); p2y = p2.charAt(0); p2x = p2.charAt(p2.length-1); p1y = p1.charAt(0); p1x = p1.charAt(p1.length-1); swapX = ( (p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r") ); swapY = ( (p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") ); if (x + w > dw + scrollX) x = swapX ? r.left-w : dw+scrollX-w; if (x < scrollX) x = swapX ? r.right : scrollX; if (y + h > dh + scrollY) y = swapY ? r.top-h : dh+scrollY-h; if (y < scrollY) y = swapY ? r.bottom : scrollY; } return [x,y]; }, /** * viewport의 element나 다른 element를 중앙에 위치시킨다. * @param {Mixed} centerIn (optional) element 중앙에 위치시킬 element */ center : function(centerIn){ return this.alignTo(centerIn || document, 'c-c'); }, /** * element의 현재 스크롤 위치를 반환한다. * @return {Object} {left: (scrollLeft), top: (scrollTop)} 포맷의 스크롤 위치를 포함한 object */ getScroll : function(){ var d = this.dom, doc = document, body = doc.body, docElement = doc.documentElement, l, t, ret; if(d == doc || d == body){ if(DU.browser.msie && DU.isStrict){ l = docElement.scrollLeft; t = docElement.scrollTop; }else{ l = window.pageXOffset; t = window.pageYOffset; } ret = {left: l || (body ? body.scrollLeft : 0), top: t || (body ? body.scrollTop : 0)}; }else{ ret = {left: d.scrollLeft, top: d.scrollTop}; } return ret; }, /** * @description scroll position 설정 * @param {object} objLeftTop {left:scrollLeft,top:scrollTop} * @return {void} */ setScroll : function(objLeftTop){ var d = this.dom, doc = document, body = doc.body, docElement = doc.documentElement, l, t, ret; if(d == doc || d == body){ if (objLeftTop.left) { var setOk = false; if (DU.browser.msie && DU.isStrict) { if (docElement.scrollLeft) { docElement.scrollLeft = objLeftTop.left; setOk = true; } } else { if (window.pageXOffset) { window.pageXOffset = objLeftTop.left; setOk = true; } } if(!setOk && body){ body.scrollLeft = objLeftTop.left; } } if (objLeftTop.top) { var setOk = false; if (DU.browser.msie && DU.isStrict) { if (docElement.scrollTop) { docElement.scrollTop = objLeftTop.top; setOk = true; } } else { if (window.pageYOffset) { window.pageYOffset = objLeftTop.top; setOk = true; } } if(!setOk && body){ body.scrollTop = objLeftTop.top; } } }else{ if (objLeftTop.left) { d.scrollLeft = objLeftTop.left; } if(objLeftTop.top){ d.scrollTop = objLeftTop.top; } } }, /** * @description targetEl이 안보이는 경우 scroll 이동하기 * @method getVisibleScrollXY * @param {string|HTMLElement} id * @param {boolean} movingX x축 자동 scroll 여부, default는 true * @param {boolean} movingY y축 자동 scroll 여부, default는 true * @return {array} [x,y] child의 변경된 좌표 return */ getVisibleScrollXY : function(targetEl,movingX,movingY){ movingX = movingX === false ? false : true; movingY = movingY === false ? false : true; var newScroll = null; if (movingX || movingY) { newScroll = {}; var scrollerEl = this; var scroll = scrollerEl.getScroll(); var startXY = scrollerEl.getXY(); var scrollerWH = [scrollerEl.getWidth(), scrollerEl.getHeight()]; var endXY = [startXY[0] + scrollerWH[0], startXY[1] + scrollerWH[1]]; var targetXY = targetEl.getXY(); var targetWH = [targetEl.getWidth(), targetEl.getHeight()]; var childs = scrollerEl.getChildren(); if (childs.length > 0) { //첫번째 놈만 비교한다. var childEl = DU.get(childs[0]); var childWH = [childEl.getWidth(), childEl.getHeight()]; var scrollBarWH = [childWH[0] > scrollerWH[0] ? 17 : 0, childWH[1] > scrollerWH[1] ? 17 : 0]; //scrollbar가 없을수도 있다. if (movingX) { if (targetXY[0] >= startXY[0] && targetXY[0] + targetWH[0] <= endXY[0] - scrollBarWH[0]) { newScroll.left = null; } else { if (targetXY[0] < startXY[0]) { newScroll.left = scroll.left - (startXY[0] - targetXY[0]); } else if (targetXY[0] + targetWH[0] > endXY[0] - scrollBarWH[0]) { newScroll.left = scroll.left + (targetXY[0] + targetWH[0] - (endXY[0] - scrollBarWH[0])); } } } if (movingY) { if (targetXY[1] >= startXY[1] && targetXY[1] + targetWH[1] <= endXY[1] - scrollBarWH[1]) { newScroll.top = null; } else { if (targetXY[1] < startXY[1]) { newScroll.top = scroll.top - (startXY[1] - targetXY[1]); } else if (targetXY[1] + targetWH[1] > endXY[1] - scrollBarWH[1]) { newScroll.top = scroll.top + (targetXY[1] + targetWH[1] - (endXY[1] - scrollBarWH[1])); } } } /*/ scroll event가 늦게 발생되는 문제로 custom event먼저 처리된 후 scroll event가 발생해 처리되지 결과적으로 되지 않는다. if(!this.delayTask) { this.delayTask = new DU.util.LDelayedTask(function(){ scrollerEl.setScroll(newScroll); this.delayTask = null; }, this); this.delayTask.delay(1000); } //*/ } } return newScroll; }, /** * @description targetEl이 안보이는 경우 scroll 이동하기 * @method moveScroll * @param {string|HTMLElement} id * @param {boolean} movingX x축 자동 scroll 여부, default는 true * @param {boolean} movingY y축 자동 scroll 여부, default는 true * @return {array} [x,y] child의 변경된 좌표 return */ moveScroll : function(id,movingX,movingY){ var targetEl = DU.get(id); var newScroll = this.getVisibleScrollXY(targetEl,movingX,movingY); if(newScroll != null) this.setScroll(newScroll); return targetEl.getXY(); }, /** * @description table의 colSpan, rowSpan 정보를 2차원 배열로 return한다. * @method setTableSpanWidth * @param {Int} cellCount cell수 */ setTableSpanWidth : function(widths){ this.getTableSpanInfo(widths); }, /** * @description table의 colSpan, rowSpan 정보를 2차원 배열로 return한다. * @method getTableSpanInfo * @param {Int} cellCount cell수 * @return {Array} 2차원 array */ getTableSpanInfo : function(widths){ var th = this; var cellCount = null; var isWidths = true; if (typeof widths === 'int') { cellCount = widths; isWidths = false; } else{ cellCount = widths.length; } //table 분석 var colSpans = new Array(); //초기화 var rowSpans = new Array(); for(var i=0;i
* // assumes DU, dom, and event are already on the page * DU.util.LGet.script( * ["http://yui.yahooapis.com/2.3.1/build/dragdrop/dragdrop-min.js", * "http://yui.yahooapis.com/2.3.1/build/animation/animation-min.js"], { * onSuccess: function(o) { * new DU.dd.LDDProxy("dd1"); // also new o.reference("dd1"); would work * this.log("won't cause error because DU is the scope"); * this.log(o.nodes.length === 2) // true * // o.purge(); // optionally remove the script nodes immediately * }, * onFailure: function(o) { * }, * data: "foo", * timeout: 10000, // 10 second timeout * scope: DU, * // win: otherframe // target another window/frame * autopurge: true // allow the utility to choose when to remove the nodes * }); ** @return {string} 트랜잭션에 대한 정보를 포함하고 있는 object tId */ script: function(url, opts) { return _queue("script", url, opts); }, /** * 현재 document나 특정 window의 document의 head에 하나 혹은 그 이상의 * css 링크 노드들을 붙이거나 삽입한다. * @method css * @static * @param url {string} css 파일에 대한 url * @param opts Options: *
* DU.util.LGet.css("http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css"); **
* DU.util.LGet.css(["http://yui.yahooapis.com/2.3.1/build/menu/assets/skins/sam/menu.css", ** @return {string} 트랜잭션에 대한 정보를 포함하고 있는 object tId */ css: function(url, opts) { return _queue("css", url, opts); } }; }(); /** * Collection 관리를 위한 유틸리티 * @module util * @title LCollection Utility * @namespace DU.util * @requires DU */ DU.namespace("util"); /** * LCollection utility. * @class LCollection * @static */ DU.util.LCollection = function() { this.items = []; this.keys = []; this.map = []; this.length = 0; } DU.util.LCollection.prototype = { /** * item을 idx위치에 삽입하는 메소드 * @method insert * @param {Int} idx 삽입할 위치 * @param {String} key 키 * @param {Object} item 입력할 객체 * @return {void} */ insert : function(idx, key, item) { if (arguments.length == 2) { item = key; key = key.id ? key.id : null; } if(idx >= this.length) return this.add(key, item); this.items.splice(idx, 0, item); this.keys.splice(idx, 0, key); if(key != null){ this.map[key] = item; } this.length++; }, /** * item을 추가하는 메소드 * @method add * @param {String} key 키 * @param {Object} item 입력할 객체 * @return {void} */ add : function(key, item) { if (arguments.length == 1) { item = key; key = key.id ? key.id : null; } this.keys.push(key); this.items.push(item); this.map[key] = item; this.length++; }, /** * item을 삭제하는 메소드 * @method remove * @param {String} key 키 * @return {Boolean} */ remove : function(key) { var o = this.map[key]; var idx = DU.util.LArray.indexOf(this.keys, key); if(idx < 0) return false; this.keys.splice(idx, 1); delete this.map[key]; this.items.splice(idx, 1); this.length--; if(this.length < 0) throw new DU.LException('Collection.remove() : IndexOutOfBoundsException ['+this.length+']'); return true; }, /** * key에 해당하는 item의 위치를 리턴하는 메소드 * @method indexOfKey * @param {String} key 키 * @return {Int} */ indexOfKey : function(key) { var o = this.map[key]; if(DU.isUndefined(o)) { return -1; } else { return DU.util.LArray.indexOf(this.items, o); } }, /** * key에 해당하는 item을 리턴하는 메소드 * @method get * @param {String} key 키 * @return {Object} */ get : function(key) { return this.map[key]; }, /** * key에 해당하는 item을 변경하는 메소드 * @method set * @param {String} key 키 * @param {Object} item 객체 * @return {Object} */ set : function(key, item) { var oldData = this.map[key]; this.map[key] = item; var idx = DU.util.LArray.indexOf(this.items, oldData); if(idx < 0) { throw new Error('Collection.set() : IndexOutOfBoundsException['+idx+']'); } this.items[idx] = item; }, /** * idx에 해당하는 key값을 리턴하는 메소드 * @method getKey * @param {Int} idx 위치 * @return {String} */ getKey : function(idx) { return this.keys[idx]; }, /** * idx 위치에 해당하는 item을 리턴하는 메소드 * @method getAt * @param {Int} idx 위치 * @return {Object} */ getAt : function(idx) { return this.items[idx]; }, /** * 모두 초기화 하는 메소드 * @method clear * @return {void} */ clear : function() { this.items = []; this.keys = []; this.map = []; this.length = 0; }, /** * items 정보에 해당되는 객체를 Function으로 호출하는 메소드 * @method each * @param {Function} func Array 배열 * @param {Object} scope Array 배열 * @return void */ each : function(func, scope) { var newItems = [].concat(this.items); var count = this.length; for(var i = 0 ; i < count; i++) { if(func.call(scope || window, this.keys[i], this.items[i], i, count) == false) break; } }, /** * func에 해당되는 값을 LCollection으로 리턴하는 메소드 * @method query * @param {Function} func Array 배열 * @param {Object} scope Array 배열 * @return {DU.util.LCollection} */ query : function(func, scope) { var newData = new DU.util.LCollection(); this.each(function(id, item, i, count){ if(func.call(scope || this, id, item, i) === true) { newData.add(id, item); } }, this); return newData; }, /** * func에 해당되는 값으로 정렬하는 메소드 * @method sort * @param {Function} func Array 배열 * @param {String} dir 정렬 방향 * @return {void} */ sort : function(fn, dir) { var desc = String(dir).toUpperCase() == "DESC" ? -1 : 1; this.items.sort(function(a, b) {return fn(a, b, dir) * desc;}); }, /** * 역순 정렬하는 메소드 * @method reverse * @return {void} */ reverse : function() { this.items.reverse(); }, /** * LCollection을 복제하여 리턴하는 메소드 * @method clone * @return {DU.util.LCollection} */ clone : function() { var o = new DU.util.LCollection(); for(var i = 0 ; i < this.length ; i++) { var key = this.getKey(i); o.insert(i, key, this.get(key)); } return o; }, /** * @description 객체의 toString * @method toString * @public * @return {String} */ toString : function() { return 'DU.util.LCollection '; } }; /** * @description
사이즈 조절 가능한 element를 만든다.
* @namespace DU.util * @requires DU, dom, dragdrop, element, event * @optional animation * @module util */ (function() { var D = DU.util.LDom, Event = DU.util.LEvent; /** * @constructor * @class LResize * @extends DU.LElement * @description사이즈 조절 가능한 element를 만든다.
* @param {String/HTMLElement} el 리사이즈 가능하게 만들 element * @param {Object} attrs 설정 parameter를 포함하는 Object liternal */ var Resize = function(el, config) { var oConfig = { element: el, attributes: config || {} }; Resize.superclass.constructor.call(this, oConfig.element, oConfig.attributes); }; /** * @private * @static * @property _instances * @description 모든 리사이즈 인스턴스에 대한 내부적인 hash 테이블 * @type Object */ Resize._instances = {}; /** * @static * @method getResizeById * @description resize object와 연관된 element의 HTML id로 resize object를 가져온다. * @return {Object} The Resize Object */ Resize.getResizeById = function(id) { if (Resize._instances[id]) { return Resize._instances[id]; } return false; }; DU.extend(Resize, DU.LElement, { /** * @private * @property CSS_RESIZE * @description 기본 CSS 클래스 이름 * @type String */ CSS_RESIZE: 'L-resize', /** * @private * @property CSS_DRAG * @description 드래그가 가능할때 추가되는 클래스 이름 * @type String */ CSS_DRAG: 'L-draggable', /** * @private * @property CSS_HOVER * @description 핸들링만 하는 hover에 대해 사용된 클래스 이름 * @type String */ CSS_HOVER: 'L-resize-hover', /** * @private * @property CSS_PROXY * @description proxy element에 주어진 클래스 이름 * @type String */ CSS_PROXY: 'L-resize-proxy', /** * @private * @property CSS_WRAP * @description wrap element에 주어진 클래스 이름 * @type String */ CSS_WRAP: 'L-resize-wrap', /** * @private * @property CSS_KNOB * @description knob style 핸들링을 만들기 위해 사용된 클래스 이름 * @type String */ CSS_KNOB: 'L-resize-knob', /** * @private * @property CSS_HIDDEN * @description 히든값의 모든 것을 핸들링 하기 위한 wrap element에 주어진 클래스 이름 * @type String */ CSS_HIDDEN: 'L-resize-hidden', /** * @private * @property CSS_HANDLE * @description 단일 핸들링의 이름에 대한 기반으로 사용하는 모든 핸들링에 주어진 클래스 이름. * Handle "t"는 this.CSS_HANDLE 뿐만 아니라 this.CSS_HANDLE + '-t'을 가져 올것이다. * @type String */ CSS_HANDLE: 'L-resize-handle', /** * @private * @property CSS_STATUS * @description status element에 주어진 클래스 이름 * @type String */ CSS_STATUS: 'L-resize-status', /** * @private * @property CSS_GHOST * @description ghost property가 활성화 될때 wrap element에 주어진 클래스 이름 * @type String */ CSS_GHOST: 'L-resize-ghost', /** * @private * @property CSS_RESIZING * @description 리사이즈 액션이 자리를 차지할때 wrap element에 주어진 클래스 이름. * @type String */ CSS_RESIZING: 'L-resize-resizing', /** * @private * @property _resizeEvent * @description 리사이즈하는데 사용되는 마우스 event * @type Event */ _resizeEvent: null, /** * @private * @property dd * @description 드래그 설정가능이 true인 경우 사용된 * DU.dd.LDragDrop 인스턴스 * @type Object */ dd: null, /** * @private * @property browser * @description DU.env.ua property의 복사본 * @type Object */ browser: DU.browser, /** * @private * @property _locked * @description 리사이즈가 잠긴 경우를 표시하기 위한 flag * @type Boolean */ _locked: null, /** * @private * @property _positioned * @description element가 절대 좌표로 위치한 경우를 표시하기 위한 flag * @type Boolean */ _positioned: null, /** * @private * @property _dds * @description 리사이즈를 핸들링 하기 위해 사용되는 * DU.dd.LDragDrop 인스턴스들의 모든 것에 대한 참조를 포함하는 object * @type Object */ _dds: null, /** * @private * @property _wrap * @description element wrapper의 HTML 참조 * @type HTMLElement */ _wrap: null, /** * @private * @property _proxy * @description element proxy의 HTML 참조 * @type HTMLElement */ _proxy: null, /** * @private * @property _handles * @description 리사이즈 핸들링의 모든 것에 대한 참조들을 포함하고 있는 object * @type Object */ _handles: null, /** * @private * @property _currentHandle * @description 현재 활성화된 핸들링의 문자열 식별자. 예. 'r', 'br', 'tl' * @type String */ _currentHandle: null, /** * @private * @property _currentDD * @description 현재 활성화된 LDD object에의 링크 * @type Object */ _currentDD: null, /** * @private * @property _cache * @description 리사이즈된 element에 대한 key 정보를 포함하는 조회 테이블. * 예. height, width, x 위치, y 위치 등.. * @type Object */ _cache: null, /** * @private * @property _active * @description 리사이즈가 활성화 되어 있는 경우를 표시하기 위한 flag. event들을 위해 사용된다. * @type Boolean */ _active: null, /** * @private * @method _createProxy * @description proxy 설정이 true인 경우 proxy element를 생성한다. */ _createProxy: function() { if (this.get('proxy')) { this._proxy = document.createElement('div'); this._proxy.className = this.CSS_PROXY; this._proxy.style.height = this.get('element').clientHeight + 'px'; this._proxy.style.width = this.get('element').clientWidth + 'px'; this._wrap.parentNode.appendChild(this._proxy); } else { this.set('animate', false); } }, /** * @private * @method _createWrap * @description wrap 설정이 true인 경우 wrap element를 생성한다. * 다음 element 타입들은 자동으로 wrap 될것이다: img, textarea, input, iframe, select */ _createWrap: function() { this._positioned = false; //Force wrap for elements that can't have children switch (this.get('element').tagName.toLowerCase()) { case 'img': case 'textarea': case 'input': case 'iframe': case 'select': this.set('wrap', true); break; } if (this.get('wrap') === true) { this._wrap = document.createElement('div'); this._wrap.id = this.get('element').id + '_wrap'; this._wrap.className = this.CSS_WRAP; D.setStyle(this._wrap, 'width', this.get('width') + 'px'); D.setStyle(this._wrap, 'height', this.get('height') + 'px'); D.setStyle(this._wrap, 'z-index', this.getStyle('z-index')); this.setStyle('z-index', 0); var pos = D.getStyle(this.get('element'), 'position'); D.setStyle(this._wrap, 'position', ((pos == 'static') ? 'relative' : pos)); D.setStyle(this._wrap, 'top', D.getStyle(this.get('element'), 'top')); D.setStyle(this._wrap, 'left', D.getStyle(this.get('element'), 'left')); if (D.getStyle(this.get('element'), 'position') == 'absolute') { this._positioned = true; D.setStyle(this.get('element'), 'position', 'relative'); D.setStyle(this.get('element'), 'top', '0'); D.setStyle(this.get('element'), 'left', '0'); } var par = this.get('element').parentNode; par.replaceChild(this._wrap, this.get('element')); this._wrap.appendChild(this.get('element')); } else { this._wrap = this.get('element'); if (D.getStyle(this._wrap, 'position') == 'absolute') { this._positioned = true; } } if (this.get('draggable')) { this._setupDragDrop(); } if (this.get('hover')) { D.addClass(this._wrap, this.CSS_HOVER); } if (this.get('knobHandles')) { D.addClass(this._wrap, this.CSS_KNOB); } if (this.get('hiddenHandles')) { D.addClass(this._wrap, this.CSS_HIDDEN); } D.addClass(this._wrap, this.CSS_RESIZE); }, /** * @private * @method _setupDragDrop * @description element에 DU.dd.LDragDrop 인스턴스를 셋업한다. */ _setupDragDrop: function() { D.addClass(this._wrap, this.CSS_DRAG); this.dd = new DU.dd.LDD(this._wrap, this.get('id') + '-resize', { dragOnly: true, useShim: this.get('useShim') }); this.dd.on('dragEvent', function() { this.fireEvent('dragEvent', arguments); }, this, true); }, /** * @private * @method _createHandles * @description 설정에 명시된대로 핸들링을 생성한다. */ _createHandles: function() { this._handles = {}; this._dds = {}; var h = this.get('handles'); for (var i = 0; i < h.length; i++) { this._handles[h[i]] = document.createElement('div'); this._handles[h[i]].id = D.generateId(this._handles[h[i]]); this._handles[h[i]].className = this.CSS_HANDLE + ' ' + this.CSS_HANDLE + '-' + h[i]; var k = document.createElement('div'); k.className = this.CSS_HANDLE + '-inner-' + h[i]; this._handles[h[i]].appendChild(k); this._wrap.appendChild(this._handles[h[i]]); Event.on(this._handles[h[i]], 'mouseover', this._handleMouseOver, this, true); Event.on(this._handles[h[i]], 'mouseout', this._handleMouseOut, this, true); this._dds[h[i]] = new DU.dd.LDragDrop(this._handles[h[i]], this.get('id') + '-handle-' + h, { useShim: this.get('useShim') }); this._dds[h[i]].setPadding(15, 15, 15, 15); this._dds[h[i]].on('startDragEvent', this._handleStartDrag, this._dds[h[i]], this); this._dds[h[i]].on('mouseDownEvent', this._handleMouseDown, this._dds[h[i]], this); } this._status = document.createElement('span'); this._status.className = this.CSS_STATUS; document.body.insertBefore(this._status, document.body.firstChild); }, /** * @private * @method _ieSelectFix * @description Internet Explorer에서 드래그를 시작할때 onselectstart handler로써 사용할 함수 */ _ieSelectFix: function() { return false; }, /** * @private * @property _ieSelectBack * @description 해당 property에 현재 "onselectstart" method의 복사본을 유지할 것이며, * 그것을 사용한 이후에 그것을 재설정한다. */ _ieSelectBack: null, /** * @private * @method _setAutoRatio * @param {Event} ev 마우스 event. * @description 이 method는 "autoRatio" 설정이 되어 있는 경우를 확인한다. * 만약 설정된 경우 "Shift Key"가 눌린 경우를 확인한다. 또한 그런 경우 config ratio를 true로 설정한다. */ _setAutoRatio: function(ev) { if (this.get('autoRatio')) { if (ev && ev.shiftKey) { //Shift Pressed this.set('ratio', true); } else { this.set('ratio', this._configs.ratio._initialConfig.value); } } }, /** * @private * @method _handleMouseDown * @param {Event} ev 마우스 event. * @description 이 method는 MouseDown에 autoRatio를 준비한다. */ _handleMouseDown: function(ev) { if (this._locked) { return false; } if (D.getStyle(this._wrap, 'position') == 'absolute') { this._positioned = true; } if (ev) { this._setAutoRatio(ev); } if (this.browser.msie) { this._ieSelectBack = document.body.onselectstart; document.body.onselectstart = this._ieSelectFix; } }, /** * @private * @method _handleMouseOver * @param {Event} ev 마우스 event. * @description 핸들링에 대한 CSS 클래스 이름들을 추가한다. */ _handleMouseOver: function(ev) { if (this._locked) { return false; } //Internet Explorer needs this D.removeClass(this._wrap, this.CSS_RESIZE); if (this.get('hover')) { D.removeClass(this._wrap, this.CSS_HOVER); } var tar = Event.getTarget(ev); if (!D.hasClass(tar, this.CSS_HANDLE)) { tar = tar.parentNode; } if (D.hasClass(tar, this.CSS_HANDLE) && !this._active) { D.addClass(tar, this.CSS_HANDLE + '-active'); for (var i in this._handles) { if (DU.hasOwnProperty(this._handles, i)) { if (this._handles[i] == tar) { D.addClass(tar, this.CSS_HANDLE + '-' + i + '-active'); break; } } } } //Internet Explorer needs this D.addClass(this._wrap, this.CSS_RESIZE); }, /** * @private * @method _handleMouseOut * @param {Event} ev 마우스 event. * @description 핸들링에 대한 CSS 클래스 이름을 제거한다. */ _handleMouseOut: function(ev) { //Internet Explorer needs this D.removeClass(this._wrap, this.CSS_RESIZE); if (this.get('hover') && !this._active) { D.addClass(this._wrap, this.CSS_HOVER); } var tar = Event.getTarget(ev); if (!D.hasClass(tar, this.CSS_HANDLE)) { tar = tar.parentNode; } if (D.hasClass(tar, this.CSS_HANDLE) && !this._active) { D.removeClass(tar, this.CSS_HANDLE + '-active'); for (var i in this._handles) { if (DU.hasOwnProperty(this._handles, i)) { if (this._handles[i] == tar) { D.removeClass(tar, this.CSS_HANDLE + '-' + i + '-active'); break; } } } } //Internet Explorer needs this D.addClass(this._wrap, this.CSS_RESIZE); }, /** * @private * @method _handleStartDrag * @param {Object} args LCustomEvent로부터 전달된 argument들 * @param {Object} dd 작업할 DU.dd.LDragDrop object * @description proxy를 리사이즈 하고, DU.dd.LDragDrop handler를 * 셋업하고 div의 상태를 업데이트 하며, 캐시를 준비한다. */ _handleStartDrag: function(args, dd) { var tar = dd.getDragEl(); if (D.hasClass(tar, this.CSS_HANDLE)) { if (D.getStyle(this._wrap, 'position') == 'absolute') { this._positioned = true; } this._active = true; this._currentDD = dd; if (this._proxy) { this._proxy.style.visibility = 'visible'; this._proxy.style.zIndex = '1000'; this._proxy.style.height = this.get('element').clientHeight + 'px'; this._proxy.style.width = this.get('element').clientWidth + 'px'; } for (var i in this._handles) { if (DU.hasOwnProperty(this._handles, i)) { if (this._handles[i] == tar) { this._currentHandle = i; var handle = '_handle_for_' + i; D.addClass(tar, this.CSS_HANDLE + '-' + i + '-active'); dd.on('dragEvent', this[handle], this, true); dd.on('mouseUpEvent', this._handleMouseUp, this, true); break; } } } D.addClass(tar, this.CSS_HANDLE + '-active'); if (this.get('proxy')) { var xy = D.getXY(this.get('element')); D.setXY(this._proxy, xy); if (this.get('ghost')) { this.addClass(this.CSS_GHOST); } } D.addClass(this._wrap, this.CSS_RESIZING); this._setCache(); this._updateStatus(this._cache.height, this._cache.width, this._cache.top, this._cache.left); this.fireEvent('startResize', { type: 'startresize', target: this}); } }, /** * @private * @method _setCache * @description this._cache hash 테이블을 셋업한다. */ _setCache: function() { this._cache.xy = D.getXY(this._wrap); D.setXY(this._wrap, this._cache.xy); this._cache.height = this.get('clientHeight'); this._cache.width = this.get('clientWidth'); this._cache.start.height = this._cache.height; this._cache.start.width = this._cache.width; this._cache.start.top = this._cache.xy[1]; this._cache.start.left = this._cache.xy[0]; this._cache.top = this._cache.xy[1]; this._cache.left = this._cache.xy[0]; this.set('height', this._cache.height, true); this.set('width', this._cache.width, true); }, /** * @private * @method _handleMouseUp * @param {Event} ev 마우스 event. * @description listener들을 초기화 하고, proxy element를 숨기며 클래스 이름을 삭제한다. */ _handleMouseUp: function(ev) { this._active = false; var handle = '_handle_for_' + this._currentHandle; this._currentDD.unOn('dragEvent', this[handle], this, true); this._currentDD.unOn('mouseUpEvent', this._handleMouseUp, this, true); if (this._proxy) { this._proxy.style.visibility = 'hidden'; this._proxy.style.zIndex = '-1'; if (this.get('setSize')) { this.resize(ev, this._cache.height, this._cache.width, this._cache.top, this._cache.left, true); } else { this.fireEvent('resize', { ev: 'resize', target: this, height: this._cache.height, width: this._cache.width, top: this._cache.top, left: this._cache.left }); } if (this.get('ghost')) { this.removeClass(this.CSS_GHOST); } } if (this.get('hover')) { D.addClass(this._wrap, this.CSS_HOVER); } if (this._status) { D.setStyle(this._status, 'display', 'none'); } if (this.browser.msie) { document.body.onselectstart = this._ieSelectBack; } if (this.browser.msie) { D.removeClass(this._wrap, this.CSS_RESIZE); } for (var i in this._handles) { if (DU.hasOwnProperty(this._handles, i)) { D.removeClass(this._handles[i], this.CSS_HANDLE + '-active'); } } if (this.get('hover') && !this._active) { D.addClass(this._wrap, this.CSS_HOVER); } D.removeClass(this._wrap, this.CSS_RESIZING); D.removeClass(this._handles[this._currentHandle], this.CSS_HANDLE + '-' + this._currentHandle + '-active'); D.removeClass(this._handles[this._currentHandle], this.CSS_HANDLE + '-active'); if (this.browser.msie) { D.addClass(this._wrap, this.CSS_RESIZE); } this._resizeEvent = null; this._currentHandle = null; if (!this.get('animate')) { this.set('height', this._cache.height, true); this.set('width', this._cache.width, true); } this.fireEvent('endResize', { ev: 'endResize', target: this, height: this._cache.height, width: this._cache.width, top: this._cache.top, left: this._cache.left }); }, /** * @private * @method _setRatio * @param {Number} h The height offset. * @param {Number} w The with offset. * @param {Number} t The top offset. * @param {Number} l The left offset. * @description Height, Width, Top, Left을 사용하여 원래 element 사이즈에 기반해서 재계산을 한다. * @return {Array} 새로운 Height, Width, Top, Left 설정 */ _setRatio: function(h, w, t, l) { var oh = h, ow = w; if (this.get('ratio')) { var orgH = this._cache.height, orgW = this._cache.width, nh = parseInt(this.get('height'), 10), nw = parseInt(this.get('width'), 10), maxH = this.get('maxHeight'), minH = this.get('minHeight'), maxW = this.get('maxWidth'), minW = this.get('minWidth'); switch (this._currentHandle) { case 'l': h = nh * (w / nw); h = Math.min(Math.max(minH, h), maxH); w = nw * (h / nh); t = (this._cache.start.top - (-((nh - h) / 2))); l = (this._cache.start.left - (-((nw - w)))); break; case 'r': h = nh * (w / nw); h = Math.min(Math.max(minH, h), maxH); w = nw * (h / nh); t = (this._cache.start.top - (-((nh - h) / 2))); break; case 't': w = nw * (h / nh); h = nh * (w / nw); l = (this._cache.start.left - (-((nw - w) / 2))); t = (this._cache.start.top - (-((nh - h)))); break; case 'b': w = nw * (h / nh); h = nh * (w / nw); l = (this._cache.start.left - (-((nw - w) / 2))); break; case 'bl': h = nh * (w / nw); w = nw * (h / nh); l = (this._cache.start.left - (-((nw - w)))); break; case 'br': h = nh * (w / nw); w = nw * (h / nh); break; case 'tl': h = nh * (w / nw); w = nw * (h / nh); l = (this._cache.start.left - (-((nw - w)))); t = (this._cache.start.top - (-((nh - h)))); break; case 'tr': h = nh * (w / nw); w = nw * (h / nh); l = (this._cache.start.left); t = (this._cache.start.top - (-((nh - h)))); break; } oh = this._checkHeight(h); ow = this._checkWidth(w); if ((oh != h) || (ow != w)) { t = 0; l = 0; if (oh != h) { ow = this._cache.width; } if (ow != w) { oh = this._cache.height; } } } return [oh, ow, t, l]; }, /** * @private * @method _updateStatus * @param {Number} h 새로운 height 설정 * @param {Number} w 새로운 width 설정 * @param {Number} t 새로운 top 설정 * @param {Number} l 새로운 left 설정 * @description Height, Width, Top, Left을 사용하여 element 사이즈를 가지고 status element를 업데이트 한다. */ _updateStatus: function(h, w, t, l) { if (this._resizeEvent && (!DU.isString(this._resizeEvent))) { if (this.get('status')) { D.setStyle(this._status, 'display', 'inline'); } h = ((h === 0) ? this._cache.start.height : h); w = ((w === 0) ? this._cache.start.width : w); var h1 = parseInt(this.get('height'), 10), w1 = parseInt(this.get('width'), 10); if (isNaN(h1)) { h1 = parseInt(h, 10); } if (isNaN(w1)) { w1 = parseInt(w, 10); } var diffH = (parseInt(h, 10) - h1); var diffW = (parseInt(w, 10) - w1); this._cache.offsetHeight = diffH; this._cache.offsetWidth = diffW; this._status.innerHTML = '' + parseInt(h, 10) + ' x ' + parseInt(w, 10) + '' + ((diffH > 0) ? '+' : '') + diffH + ' x ' + ((diffW > 0) ? '+' : '') + diffW + ''; D.setXY(this._status, [Event.getPageX(this._resizeEvent) + 12, Event.getPageY(this._resizeEvent) + 12]); } }, /** * @method lock * @description 리사이즈 될 수 없도록 리사이즈를 locking 한다. * @param {Boolean} dd 드래그 가능하도록 설정되어 있는 경우에도 역시 lock 됨 * @return {DU.util.LResize} 리사이즈 인스턴스 */ lock: function(dd) { this._locked = true; if (dd && this.dd) { D.removeClass(this._wrap, 'L-draggable'); this.dd.lock(); } return this; }, /** * @method unlock * @description 리사이즈 될 수 있도록 unlocking 한다. * @param {Boolean} dd 드래그 가능하도록 설정되어 있는 경우에도 역시 unlock 됨 * @return {DU.util.LResize} 리사이즈 인스턴스 */ unlock: function(dd) { this._locked = false; if (dd && this.dd) { D.addClass(this._wrap, 'L-draggable'); this.dd.unlock(); } return this; }, /** * @method isLocked * @description 리사이즈 인스턴스의 lock 상태를 체크한다. * @return {Boolean} */ isLocked: function() { return this._locked; }, /** * @method reset * @description start 상태가 되도록 element를 리셋한다. * @return {DU.util.LResize} 리사이즈 인스턴스 */ reset: function() { this.resize(null, this._cache.start.height, this._cache.start.width, this._cache.start.top, this._cache.start.left, true); return this; }, /** * @private * @method resize * @param {Event} ev 마우스 event. * @param {Number} h 새로운 height 설정 * @param {Number} w 새로운 width 설정 * @param {Number} t 새로운 top 설정 * @param {Number} l 새로운 left 설정 * @param {Boolean} force element를 리사이즈한다.(proxy 리사이즈에 대해 사용됨) * @param {Boolean} silent beforeResize Event 전에는 발생하지 않도록 한다. * @description handler로 부터의 데이터에 기반한 wrapper나 proxy element를 리사이즈 한다. * @return {DU.util.LResize} 리사이즈 인스턴스 */ resize: function(ev, h, w, t, l, force, silent) { if (this._locked) { return false; } this._resizeEvent = ev; var el = this._wrap, anim = this.get('animate'), set = true; if (this._proxy && !force) { el = this._proxy; anim = false; } this._setAutoRatio(ev); if (this._positioned) { if (this._proxy) { t = this._cache.top - t; l = this._cache.left - l; } } var ratio = this._setRatio(h, w, t, l); h = parseInt(ratio[0], 10); w = parseInt(ratio[1], 10); t = parseInt(ratio[2], 10); l = parseInt(ratio[3], 10); if (t == 0) { //No Offset, get from cache t = D.getY(el); } if (l == 0) { //No Offset, get from cache l = D.getX(el); } if (this._positioned) { if (this._proxy && force) { if (!anim) { el.style.top = this._proxy.style.top; el.style.left = this._proxy.style.left; } else { t = this._proxy.style.top; l = this._proxy.style.left; } } else { if (!this.get('ratio') && !this._proxy) { t = this._cache.top + -(t); l = this._cache.left + -(l); } if (t) { if (this.get('minY')) { if (t < this.get('minY')) { t = this.get('minY'); } } if (this.get('maxY')) { if (t > this.get('maxY')) { t = this.get('maxY'); } } } if (l) { if (this.get('minX')) { if (l < this.get('minX')) { l = this.get('minX'); } } if (this.get('maxX')) { if ((l + w) > this.get('maxX')) { l = (this.get('maxX') - w); } } } } } if (!silent) { var beforeReturn = this.fireEvent('beforeResize', { ev: 'beforeResize', target: this, height: h, width: w, top: t, left: l }); if (beforeReturn === false) { return false; } } this._updateStatus(h, w, t, l); if (this._positioned) { if (this._proxy && force) { //Do nothing } else { if (t) { D.setY(el, t); this._cache.top = t; } if (l) { D.setX(el, l); this._cache.left = l; } } } if (h) { if (!anim) { set = true; if (this._proxy && force) { if (!this.get('setSize')) { set = false; } } if (set) { if (this.browser.msie > 6) { if (h === this._cache.height) { h = h + 1; } } el.style.height = h + 'px'; } if ((this._proxy && force) || !this._proxy) { if (this._wrap != this.get('element')) { this.get('element').style.height = h + 'px'; } } } this._cache.height = h; } if (w) { this._cache.width = w; if (!anim) { set = true; if (this._proxy && force) { if (!this.get('setSize')) { set = false; } } if (set) { el.style.width = w + 'px'; } if ((this._proxy && force) || !this._proxy) { if (this._wrap != this.get('element')) { this.get('element').style.width = w + 'px'; } } } } if (anim) { if (DU.util.LAnim) { var _anim = new DU.util.LAnim(el, { height: { to: this._cache.height }, width: { to: this._cache.width } }, this.get('animateDuration'), this.get('animateEasing')); if (this._positioned) { if (t) { _anim.attributes.top = { to: parseInt(t, 10) }; } if (l) { _anim.attributes.left = { to: parseInt(l, 10) }; } } if (this._wrap != this.get('element')) { _anim.onTween.on(function() { this.get('element').style.height = el.style.height; this.get('element').style.width = el.style.width; }, this, true); } _anim.onComplete.on(function() { this.set('height', h); this.set('width', w); this.fireEvent('resize', { ev: 'resize', target: this, height: h, width: w, top: t, left: l }); }, this, true); _anim.animate(); } } else { if (this._proxy && !force) { this.fireEvent('proxyResize', { ev: 'proxyresize', target: this, height: h, width: w, top: t, left: l }); } else { this.fireEvent('resize', { ev: 'resize', target: this, height: h, width: w, top: t, left: l }); } } return this; }, /** * @private * @method _handle_for_br * @param {Object} args LCustomEvent로부터의 argument * @description Bottom Right handle에 대한 사이즈를 핸들링 한다. */ _handle_for_br: function(args) { var newW = this._setWidth(args.e); var newH = this._setHeight(args.e); this.resize(args.e, (newH + 1), newW, 0, 0); }, /** * @private * @method _handle_for_bl * @param {Object} args LCustomEvent로부터의 argument * @description Bottom Left handle에 대한 사이즈를 핸들링 한다. */ _handle_for_bl: function(args) { var newW = this._setWidth(args.e, true); var newH = this._setHeight(args.e); var l = (newW - this._cache.width); this.resize(args.e, newH, newW, 0, l); }, /** * @private * @method _handle_for_tl * @param {Object} args LCustomEvent로부터의 argument * @description Top Left handle에 대한 사이즈를 핸들링 한다. */ _handle_for_tl: function(args) { var newW = this._setWidth(args.e, true); var newH = this._setHeight(args.e, true); var t = (newH - this._cache.height); var l = (newW - this._cache.width); this.resize(args.e, newH, newW, t, l); }, /** * @private * @method _handle_for_tr * @param {Object} args LCustomEvent로부터의 argument * @description Top Right handle에 대한 사이즈를 핸들링 한다. */ _handle_for_tr: function(args) { var newW = this._setWidth(args.e); var newH = this._setHeight(args.e, true); var t = (newH - this._cache.height); this.resize(args.e, newH, newW, t, 0); }, /** * @private * @method _handle_for_r * @param {Object} args LCustomEvent로부터의 argument * @description Right handle에 대한 사이즈를 핸들링 한다. */ _handle_for_r: function(args) { this._dds.r.setYConstraint(0,0); var newW = this._setWidth(args.e); this.resize(args.e, 0, newW, 0, 0); }, /** * @private * @method _handle_for_l * @param {Object} args LCustomEvent로부터의 argument * @description Left handle에 대한 사이즈를 핸들링 한다. */ _handle_for_l: function(args) { this._dds.l.setYConstraint(0,0); var newW = this._setWidth(args.e, true); var l = (newW - this._cache.width); this.resize(args.e, 0, newW, 0, l); }, /** * @private * @method _handle_for_b * @param {Object} args LCustomEvent로부터의 argument * @description Bottom handle에 대한 사이즈를 핸들링 한다. */ _handle_for_b: function(args) { this._dds.b.setXConstraint(0,0); var newH = this._setHeight(args.e); this.resize(args.e, newH, 0, 0, 0); }, /** * @private * @method _handle_for_t * @param {Object} args LCustomEvent로부터의 argument * @description Top handle에 대한 사이즈를 핸들링 한다. */ _handle_for_t: function(args) { this._dds.t.setXConstraint(0,0); var newH = this._setHeight(args.e, true); var t = (newH - this._cache.height); this.resize(args.e, newH, 0, t, 0); }, /** * @private * @method _setWidth * @param {Event} ev 마우스 event. * @param {Boolean} flip 이동의 방향성 여부에 대한 argument * @description 마우스 event에 기반한 width를 계산한다. * @return {Number} 새로운 값 */ _setWidth: function(ev, flip) { var xy = this._cache.xy[0], w = this._cache.width, x = Event.getPageX(ev), nw = (x - xy); if (flip) { nw = (xy - x) + parseInt(this.get('width'), 10); } nw = this._snapTick(nw, this.get('yTicks')); nw = this._checkWidth(nw); return nw; }, /** * @private * @method _checkWidth * @param {Number} w 체크할 width * @description maxWidth와 minWidth에 대하여 전달된 값을 체크한다. * @return {Number} 새로운 값 */ _checkWidth: function(w) { if (this.get('minWidth')) { if (w <= this.get('minWidth')) { w = this.get('minWidth'); } } if (this.get('maxWidth')) { if (w >= this.get('maxWidth')) { w = this.get('maxWidth'); } } return w; }, /** * @private * @method _checkHeight * @param {Number} h 체크할 height * @description maxHeight와 minHeight에 대하여 전달된 값을 체크한다. * @return {Number} The new value */ _checkHeight: function(h) { if (this.get('minHeight')) { if (h <= this.get('minHeight')) { h = this.get('minHeight'); } } if (this.get('maxHeight')) { if (h >= this.get('maxHeight')) { h = this.get('maxHeight'); } } return h; }, /** * @private * @method _setHeight * @param {Event} ev 마우스 event. * @param {Boolean} flip 이동의 방향성 여부에 대한 argument * @description 마우스 event에 기반한 height를 계산한다. * @return {Number} 새로운 값 */ _setHeight: function(ev, flip) { var xy = this._cache.xy[1], h = this._cache.height, y = Event.getPageY(ev), nh = (y - xy); if (flip) { nh = (xy - y) + parseInt(this.get('height'), 10); } nh = this._snapTick(nh, this.get('xTicks')); nh = this._checkHeight(nh); return nh; }, /** * @private * @method _snapTick * @param {Number} size tick에 대한 사이즈 * @param {Number} pix The tick pixels. * @description 사용된 tick에 기반한 숫자를 조절한다. * @return {Number} 새로 snap된 위치 */ _snapTick: function(size, pix) { if (!size || !pix) { return size; } var _s = size; var _x = size % pix; if (_x > 0) { if (_x > (pix / 2)) { _s = size + (pix - _x); } else { _s = size - _x; } } return _s; }, /** * @private * @method init * @description Resize 클래스의 초기화 method */ init: function(p_oElement, p_oAttributes) { this._locked = false; this._cache = { xy: [], height: 0, width: 0, top: 0, left: 0, offsetHeight: 0, offsetWidth: 0, start: { height: 0, width: 0, top: 0, left: 0 } }; Resize.superclass.init.call(this, p_oElement, p_oAttributes); this.set('setSize', this.get('setSize')); if (p_oAttributes.height) { this.set('height', parseInt(p_oAttributes.height, 10)); } if (p_oAttributes.width) { this.set('width', parseInt(p_oAttributes.width, 10)); } var id = p_oElement; if (!DU.isString(id)) { id = D.generateId(id); } Resize._instances[id] = this; this._active = false; this._createWrap(); this._createProxy(); this._createHandles(); }, /** * @method getProxyEl * @description proxy에 대한 HTML 참조를 가져오며, proxy가 아닌 경우 null을 반환한다. * @return {HTMLElement} The proxy element */ getProxyEl: function() { return this._proxy; }, /** * @method getWrapEl * @description wrap element에 대한 HTML 참조를 가져오며, warp되어 있지 않다면, 현재 element를 반환한다. * @return {HTMLElement} The wrap element */ getWrapEl: function() { return this._wrap; }, /** * @method getStatusEl * @description status element에 대한 HTML 참조를 가져온다. * @return {HTMLElement} The status element */ getStatusEl: function() { return this._status; }, /** * @method getActiveHandleEl * @description 현재 활성화된 resize handle에 대한 HTML 참조를 가져온다. * @return {HTMLElement} 활성화된 handle element */ getActiveHandleEl: function() { return this._handles[this._currentHandle]; }, /** * @method isActive * @description 리사이즈 작업이 현재 element에 활성화 되어 있는지에 따라 true나 false를 반환한다. * @return {Boolean} */ isActive: function() { return ((this._active) ? true : false); }, /** * @private * @method initAttributes * @description 리사이즈 가능한 element를 생성하기 위해 사용된 설정 attribute의 모든 것을 초기화 한다. * @param {Object} attr 유틸리티를 생성하기 위해 사용된 설정 attribute의 집합을 명시하는 Object literal */ initAttributes: function(attr) { Resize.superclass.initAttributes.call(this, attr); /** * @attribute useShime * @description 이 설정은 resize handle과 드래그 가능한 property에 대하여 * LDragDrop 인스턴스에 전달될 것이다. * 이 property는 iframe과 다른 element들에 대하여 작업하기 위해서 resize를 * 핸들링하고자 하는 경우 사용되어야 한다. * @type Boolean */ this.setAttributeConfig('useShim', { value: ((attr.useShim === true) ? true : false), validator: DU.isBoolean, method: function(u) { for (var i in this._dds) { if (DU.hasOwnProperty(this._dds, i)) { this._dds[i].useShim = u; } } if (this.dd) { this.dd.useShim = u; } } }); /** * @attribute setSize * @description 리사이즈된 element의 사이즈를 설정하며 false로 설정하면 element는 자동으로 * 라사이즈 되지 않는다. resize event는 최종 사용자가 리사이즈 할수 있는 배열을 포함할 것이다. * 이 설정은 true 설정인 proxy와 false 설정인 animattion에서만 작동할 것이다. * @type Boolean */ this.setAttributeConfig('setSize', { value: ((attr.setSize === false) ? false : true), validator: DU.isBoolean }); /** * @attribute wrap * @description element를 wrapping 한다. * @type Boolean */ this.setAttributeConfig('wrap', { writeOnce: true, validator: DU.isBoolean, value: attr.wrap || false }); /** * @attribute handles * @description 사용하기 위한 handle들(다음 조합의): 't', 'b', 'r', 'l', 'bl', 'br', 'tl', 'tr'. 기본값: ['r', 'b', 'br']. * 모든 바로 가기를 사용할 수 있다. 참고: 8방향의 리사이징은 absolute 위치인 element에 대하여 수행되어야 한다. * @type Array */ this.setAttributeConfig('handles', { writeOnce: true, value: attr.handles || ['r', 'b', 'br'], validator: function(handles) { if (DU.isString(handles) && handles.toLowerCase() == 'all') { handles = ['t', 'b', 'r', 'l', 'bl', 'br', 'tl', 'tr']; } if (!DU.isArray(handles)) { handles = handles.replace(/, /g, ','); handles = handles.split(','); } this._configs.handles.value = handles; } }); /** * @attribute width * @description element의 width * @type Number */ this.setAttributeConfig('width', { value: attr.width || parseInt(this.getStyle('width'), 10), validator: DU.isNumber, method: function(width) { width = parseInt(width, 10); if (width > 0) { if (this.get('setSize')) { this.setStyle('width', width + 'px'); } this._cache.width = width; this._configs.width.value = width; } } }); /** * @attribute height * @description element의 height * @type Number */ this.setAttributeConfig('height', { value: attr.height || parseInt(this.getStyle('height'), 10), validator: DU.isNumber, method: function(height) { height = parseInt(height, 10); if (height > 0) { if (this.get('setSize')) { this.setStyle('height', height + 'px'); } this._cache.height = height; this._configs.height.value = height; } } }); /** * @attribute minWidth * @description element의 최소 width * @type Number */ this.setAttributeConfig('minWidth', { value: attr.minWidth || 15, validator: DU.isNumber }); /** * @attribute minHeight * @description element의 최소 height * @type Number */ this.setAttributeConfig('minHeight', { value: attr.minHeight || 15, validator: DU.isNumber }); /** * @attribute maxWidth * @description element의 최대 width * @type Number */ this.setAttributeConfig('maxWidth', { value: attr.maxWidth || 10000, validator: DU.isNumber }); /** * @attribute maxHeight * @description element의 최대 height * @type Number */ this.setAttributeConfig('maxHeight', { value: attr.maxHeight || 10000, validator: DU.isNumber }); /** * @attribute minY * @description element의 최소 y 좌표 * @type Number */ this.setAttributeConfig('minY', { value: attr.minY || false }); /** * @attribute minX * @description element의 최소 x 좌표 * @type Number */ this.setAttributeConfig('minX', { value: attr.minX || false }); /** * @attribute maxY * @description element의 최대 y 좌표 * @type Number */ this.setAttributeConfig('maxY', { value: attr.maxY || false }); /** * @attribute maxX * @description element의 최대 x 좌표 * @type Number */ this.setAttributeConfig('maxX', { value: attr.maxX || false }); /** * @attribute animate * @description element를 리사이즈 하기 위해서 animation을 사용하여야 한다.(proxy를 사용하는 경우만 사용할 수 있음) * @type Boolean */ this.setAttributeConfig('animate', { value: attr.animate || false, validator: function(value) { var ret = true; if (!DU.util.LAnim) { ret = false; } return ret; } }); /** * @attribute animateEasing * @description animation에 대해 적용하기 위한 LEasing. * @type Object */ this.setAttributeConfig('animateEasing', { value: attr.animateEasing || function() { var easing = false; if (DU.util.LEasing && DU.util.LEasing.easeOut) { easing = DU.util.LEasing.easeOut; } return easing; }() }); /** * @attribute animateDuration * @description The Duration to apply to the animation. * @description animation에 대해 적용하기 위한 Duration * @type Number */ this.setAttributeConfig('animateDuration', { value: attr.animateDuration || 0.5 }); /** * @attribute proxy * @description 실제 element 대신 proxy element를 리사이즈 한다. * @type Boolean */ this.setAttributeConfig('proxy', { value: attr.proxy || false, validator: DU.isBoolean }); /** * @attribute ratio * @description 리사이징할 때 element의 ratio를 유지한다. * @type Boolean */ this.setAttributeConfig('ratio', { value: attr.ratio || false, validator: DU.isBoolean }); /** * @attribute ghost * @description 리사이즈 되는 element에 대한 불투명 필터를 적용한다.(proxy에서만 작동함) * @type Boolean */ this.setAttributeConfig('ghost', { value: attr.ghost || false, validator: DU.isBoolean }); /** * @attribute draggable * @description element를 드래그 가능하게 만들기 위한 편의성 method * @type Boolean */ this.setAttributeConfig('draggable', { value: attr.draggable || false, validator: DU.isBoolean, method: function(dd) { if (dd && this._wrap) { this._setupDragDrop(); } else { if (this.dd) { D.removeClass(this._wrap, this.CSS_DRAG); this.dd.unreg(); } } } }); /** * @attribute hover * @description 마우스가 over 됐을때 handle만 보여준다. * @type Boolean */ this.setAttributeConfig('hover', { value: attr.hover || false, validator: DU.isBoolean }); /** * @attribute hiddenHandles * @description handle을 보여주지 않고, 사용자가 커서만 사용하게 한다. * @type Boolean */ this.setAttributeConfig('hiddenHandles', { value: attr.hiddenHandles || false, validator: DU.isBoolean }); /** * @attribute knobHandles * @description 최대 사이즈 handle의 경우 대신 더 작은 handle을 사용한다. * @type Boolean */ this.setAttributeConfig('knobHandles', { value: attr.knobHandles || false, validator: DU.isBoolean }); /** * @attribute xTicks * @description 리사이즈할 span에 대한 x tick의 숫자 * @type Number or False */ this.setAttributeConfig('xTicks', { value: attr.xTicks || false }); /** * @attribute yTicks * @description 리사이즈할 span에 대한 y tick의 숫자 * @type Number or False */ this.setAttributeConfig('yTicks', { value: attr.yTicks || false }); /** * @attribute status * @description resize의 상태(새로운 사이즈)를 보여준다. * @type Boolean */ this.setAttributeConfig('status', { value: attr.status || false, validator: DU.isBoolean }); /** * @attribute autoRatio * @description 리사이즈하는 동안 shift 키를 사용하는 것은 ratio 설정을 토글할 것이다. * @type Boolean */ this.setAttributeConfig('autoRatio', { value: attr.autoRatio || false, validator: DU.isBoolean }); }, /** * @method destroy * @description resize object와 그것의 모든 element와 listner들을 없앤다. */ destroy: function() { for (var h in this._handles) { if (DU.hasOwnProperty(this._handles, h)) { Event.purgeElement(this._handles[h]); this._handles[h].parentNode.removeChild(this._handles[h]); } } if (this._proxy) { this._proxy.parentNode.removeChild(this._proxy); } if (this._status) { this._status.parentNode.removeChild(this._status); } if (this.dd) { this.dd.unreg(); D.removeClass(this._wrap, this.CSS_DRAG); } if (this._wrap != this.get('element')) { this.setStyle('position', ''); this.setStyle('top', ''); this.setStyle('left', ''); this._wrap.parentNode.replaceChild(this.get('element'), this._wrap); } this.removeClass(this.CSS_RESIZE); delete DU.util.LResize._instances[this.get('id')]; //Brutal Object Destroy for (var i in this) { if (DU.hasOwnProperty(this, i)) { this[i] = null; delete this[i]; } } }, /** * @method toString * @description Resize object를 표한하는 문자열을 반환한다. * @return {String} */ toString: function() { if (this.get) { return 'Resize (#' + this.get('id') + ')'; } return 'Resize Utility'; } }); DU.util.LResize = Resize; /** * @event dragEvent * @description DU.dd.LDragDrop dragEvent가 드래그 가능한 설정 옵션에 대해 발생되었을때 발생하는 event * @type DU.util.LCustomEvent */ /** * @event startResize * @description resize 액션이 시작되었을때 발생하는 event * @type DU.util.LCustomEvent */ /** * @event endResize * @description 드래그 인스턴스로부터의 mouseUp event가 발생했을때 발생하는 event * @type DU.util.LCustomEvent */ /** * @event resize * @description 모든 element 리사이즈에 발생하는 event(proxy 설정 세팅에 사용될때 오직 한번만 발생함) * @type DU.util.LCustomEvent */ /** * @event beforeResize * @description 모든 element 리사이즈 이전 및 사이즈 계산 후에 발생하며, 리사이즈가 중단될때 false를 반환하는 event * @type DU.util.LCustomEvent */ /** * @event proxyResize * @description 모든 proxy 리사이즈에 발생하는 event(proxy 설정 세팅에 사용될때만 발생함) * @type DU.util.LCustomEvent */ })(); (function(){ /** * @description LResizeMonitor, autoWidth일 경우 부모가 display none에서 block으로 될때 resize event를 fire한다. 이때 자식들의 sizing을 할 수 있다. * @module util * @title LResizeMonitor * @requires DU.util.LEventProvider */ DU.util.LResizeMonitor = function(oConfig){ var config = oConfig || {}; DU.util.LResizeMonitor.superclass.constructor.call(this); DU.applyObject(this, config, true); this.resizedEvent = this.createEvent('resized'); this.init(oConfig); } DU.extend(DU.util.LResizeMonitor, DU.util.LEventProvider, { /** * @description 객체를 초기화하는 메소드 * @method init * @private * @param {Object} oConfig 환경정보 객체 * @return void */ init: function(oConfig){ this.el = document.createElement('iframe'); this.el.scrolling = "no"; this.el.frameBorder = "0"; this.el.style.width = "90%"; this.el.style.height = "0px"; }, /** * @description 객체를 초기화하는 메소드 * @method init * @private * @param {Object} oConfig 환경정보 객체 * @return void */ onResized: function(e){ this.resizedEvent.fire(); }, /** * @description width auto시 resize가 일어나는지 모니터링하는 target object 설정 * @method monitor * @public * @param {String|Object} target 객체를 붙이고자 하는 Node정보 * @return void */ monitor: function(target){ var el = DU.get(target); el.appendChild(this.el); var ifrEl = DU.get(this.el); this.el.name = this.el.id; this.onResizedDelegate = DU.util.LFunction.createDelegate(this.onResized, this); try{ if (!DU.util.LEvent.on(this.el.contentWindow, "resize", this.onResizedDelegate)) { //IE DU.util.LEvent.on(this.el, "resize", this.onResizeDelegate); } } catch(e) { DU.log(e.message); } } }); })(); /** * @module util * @title LDelayedTask 유틸리티 * @namespace DU.util * @requires DU */ /** *LDelayedTask 클래스는 새로운 타임아웃이 예전 타임아웃을 취소하는 serTimeout를 수행하는 * method의 실행을 "buffer"하기 위해 편리한 방법을 제공한다. * 취소될때, 타스크는 실행 전에 특정 time period를 기다릴 것이다. * 해당 time period 동안 타스크가 다시 취소된다면, 원래 호출도 취소될 것이다. * 이러한 연속성때문에 함수는 각 반복에 대해 오직 한번만 호출된다.
*이 method는 사용자가 텍스트 필드에 타이핑을 마쳤는지의 여부를 확인하는 것 같은 * 일들에 특별히 유용하다. * 예제로써, 키가 눌렸을때 validation을 수행하는 것이다. * 밀리초의 특정 번호에 대한 키입력 이벤트를 버퍼링하기 위해 이 클래스를 사용할수 있으며, * 그것들이 그정도의 시간동안 중지하는 경우에만 수행을 한다. * 사용법:
var task = new DU.util.LDelayedTask(function(){
alert(DU.getDom('myInputField').value.length);
});
// Wait 500ms before calling our function. If the user presses another key
// during that 500ms, it will be cancelled and we'll wait another 500ms.
DU.get('myInputField').on('keypress', function(){
task.{@link #delay}(500);
});
*
* 요점을 설명하기 위하여 여기에 LDelayedTask를 사용하는 것을 유념해야 한다. * {@link DU.util.LEventProvider#addListener addListener/on}에 대한 설정 옵션 buffer는 * buffer 이벤트에 지연된 타스크를 셋업할 것이다.
*method
- {Function} REQUIRED callback 함수.scope
- {Object} callback을 실행하기 위한 scope. 기본적으로 global window scope 이다.argument
- {Array} 개별의 argument들로서 method에 전달될 parameter들.timeout
- {number} 이전 callback의 완료 이후와 해당 callback을 실행하기 전에 기다리기 위한 밀리초 지연시간. 음수값은 즉시 실행 차단을 일으킨다. 기본값은 0.until
- {Function} 각각의 반복 이전에 실행될 boolean 함수. 완료를 표시하고 다음 callback으로 진행하기 위해서 true를 반환한다.iterations
- {Number} chain에서 다음 callback으로 진행하기 이전에 callback을 실행하기 위한 번호. until
과 호환되지 않는다.
* DU.util.LFormat.rendererWrapper('dateToString', {format:'%x'});
* DU.util.LRenderer.dateRenderer('%x')
* 위 두개는 동일한 기능으로 수행 가능
*
* @method rendererWrapper
* @param {String} fnName LFormat에 등록된 모든 function명
* @return {Function}
*/
rendererWrapper: function(fnName) {
var fn = eval('DU.util.LFormat.' + fnName);
var a=arguments;
var param = [];
for(var i = 1 ; i < a.length; i++)
param.push(a[i]);
return function(v){
return fn.call(v, param);
};
}
};
})();
DU.namespace("DU.util");
/**
* Renderer
*
* @namespace DU.util
* @requires DU
* @class LRenderer
* @static
*/
DU.util.LRenderer = {
/**
* 여러 번 date 형식을 재사용할 수 있는 date rendering 함수를 리턴한다.
* @method dateRenderer
* @param {String} format
* @param {String} locale
* @return {function}
*/
dateRenderer: function(format,locale){
return function(v){
return DU.util.LFormat.dateToString(v, {format:format,locale:locale});
};
},
/**
* 여러번 number 형식을 재사용할 수 있는 number rendering 함수를 리턴한다.
* @method numberRenderer
* @param
* @return {function}
*/
numberRenderer : function() {
return function(v){
return DU.util.LFormat.numberFormat(v);
};
},
/**
* 여러번 money 형식을 재사용할 수 있는 money rendering 함수를 리턴한다.
* @method moneyRenderer
* @param
* @return {function}
*/
moneyRenderer : function(currency) {
return function(v){
return DU.util.LFormat.moneyFormat(v, currency);
};
},
/**
* 여러번 rate 형식을 재사용할 수 있는 rate rendering 함수를 리턴한다.
* @method rateRenderer
* @param {Object} point
* @return {function}
*/
rateRenderer : function(point) {
return function(v){
return DU.util.LFormat.stringToRate(v, point);
};
},
/**
* 여러번 time 형식을 재사용할 수 있는 time rendering 함수를 리턴한다.
* @method timeRenderer
* @param {Object} format
* @return {function}
*/
timeRenderer: function (format) {
return function(v){
return DU.util.LFormat.timeFormat(v, {format:format});
};
},
/**
* 여러번 weight 형식을 재사용할 수 있는 weight rendering 함수를 리턴한다.
* @method weightRenderer
* @param {Object} unit
* @param {Object} point
* @param {Object} thousandsSeparator
* @return {function}
*/
weightRenderer: function(unit, thousandsSeparator, point) {
return function(v){
return DU.util.LFormat.weightFormat(v, unit, thousandsSeparator, point);
};
},
/**
* 여러번 length 형식을 재사용할 수 있는 length rendering 함수를 리턴한다.
* @method lengthRenderer
* @param {Object} unit
* @param {Object} point
* @param {Object} thousandsSeparator
* @return {function}
*/
lengthRenderer: function(unit, thousandsSeparator, point) {
return function(v){
return DU.util.LFormat.lengthFormat(v, unit, thousandsSeparator, point);
};
}
};
(function () {
/**
* LPlugin
* @namespace DU.util
* @class LPlugin
* @extends DU.util.LEventProvider
* @constructor
* @param {Object} userConfig 해당 overlay에 대한 집합이어 하는 설정을 포함하는 설정 object literal.
* 더 자세한 사항은 설정 문서를 참고 한다.
*/
DU.util.LPlugin = function (oConfig) {
var config = oConfig || {};
DU.applyObject(this, config, true);
};
DU.extend(DU.util.LPlugin, DU.util.LEventProvider, {
initPlugin : function(parent) {
for(m in this) {
if(m != 'constructor' && m != 'initPlugin' && !DU.util.LEventProvider.prototype[m]) {
parent[m] = this[m];
}
}
}
});
}());
(function() {
DU.namespace('DU.animation');
var Y = DU.animation;
/**
* HTMLElement에 animation 효과주는 class
* @module animation
* @requires event, dom
*/
/**
* Base animation class는 animation효과들을 주는 interface를 제공한다.
* Usage: var myAnim = new DU.animation.LAnim(el, { width: { from: 10, to: 100 } }, 1, DU.animation.LEasing.easeOut);
* @class LAnim * @namespace DU.animation * @requires DU.animation.LAnimMgr * @requires DU.animation.LEasing * @requires DU.animation.LDom * @requires DU.animation.LEvent * @requires DU.animation.LCustomEvent * @constructor * @param {String | HTMLElement} el animation효과가 적용될 element * @param {Object} attributes animation효과 관련 attribute, 각 attribute는 object로 to나 by가 정의되어 있다. 이외에 from, units(px)가 있으며 camelCase로 표기한다. * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based * @param {Function} method (optional, defaults to DU.animation.LEasing.easeNone) Computes the values that are applied to the attributes per frame (generally a DU.animation.LEasing method) */ var LAnim = function(el, attributes, duration, method) { if (!el) { } this.init(el, attributes, duration, method); }; LAnim.NAME = 'LAnim'; LAnim.prototype = { /** * LAnim instance에 대한 이름 * @method toString * @return {String} */ toString: function() { var el = this.getEl() || {}; var id = el.id || el.tagName; return (this.constructor.NAME + ': ' + id); }, patterns: { // cached for performance noNegatives: /width|height|opacity|padding/i, // keep at zero or above offsetAttribute: /^((width|height)|(top|left))$/, // use offsetValue as default defaultUnit: /width|height|top$|bottom$|left$|right$/i, // use 'px' by default offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i // IE may return these, so convert these to offset }, /** * animation의 "method"에 의해 계산된 값을 return * @method doMethod * @param {String} attr The name of the attribute. * @param {Number} start The value this attribute should start from for this animation. * @param {Number} end The value this attribute should end at for this animation. * @return {Number} The Value to be applied to the attribute. */ doMethod: function(attr, start, end) { return this.method(this.currentFrame, start, end - start, this.totalFrames); }, /** * attribute에 값 설정 * @method setAttribute * @param {String} attr attribute명. * @param {Number} val attribute에 할당될 값. * @param {String} unit 값의 unit ('px', '%', etc.) */ setAttribute: function(attr, val, unit) { if ( this.patterns.noNegatives.test(attr) ) { val = (val > 0) ? val : 0; } DU.util.LDom.setStyle(this.getEl(), attr, val + unit); }, /** * attribute의 값 return. * @method getAttribute * @param {String} attr attribute명 * @return {Number} val 값 */ getAttribute: function(attr) { var el = this.getEl(); var val = DU.util.LDom.getStyle(el, attr); if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) { return parseFloat(val); } var a = this.patterns.offsetAttribute.exec(attr) || []; var pos = !!( a[3] ); // top or left var box = !!( a[2] ); // width or height // use offsets for width/height and abs pos top/left if ( box || (DU.util.LDom.getStyle(el, 'position') == 'absolute' && pos) ) { val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)]; } else { // default to zero for other 'auto' val = 0; } return val; }, /** * 기본 unit * @method getDefaultUnit * @param {attr} attr attribute명 * @return {String} 기본 unit */ getDefaultUnit: function(attr) { if ( this.patterns.defaultUnit.test(attr) ) { return 'px'; } return ''; }, /** * animation동안 사용될 실제 값들. subclass를 사용할때만 사용됨. * @method setRuntimeAttribute * @param {Object} attr attribute object * @private */ setRuntimeAttribute: function(attr) { var start; var end; var attributes = this.attributes; this.runtimeAttributes[attr] = {}; var isset = function(prop) { return (typeof prop !== 'undefined'); }; if ( !isset(attributes[attr]['to']) && !isset(attributes[attr]['by']) ) { return false; // note return; nothing to animate to } start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr); // To beats by, per SMIL 2.1 spec if ( isset(attributes[attr]['to']) ) { end = attributes[attr]['to']; } else if ( isset(attributes[attr]['by']) ) { if (start.constructor == Array) { end = []; for (var i = 0, len = start.length; i < len; ++i) { end[i] = start[i] + attributes[attr]['by'][i] * 1; // times 1 to cast "by" } } else { end = start + attributes[attr]['by'] * 1; } } this.runtimeAttributes[attr].start = start; this.runtimeAttributes[attr].end = end; // set units if needed this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr); return true; }, /** * Constructor for LAnim instance. * @method init * @param {String | HTMLElement} el animate될 element * @param {Object} attributes animation효과 관련 attribute, 각 attribute는 object로 to나 by가 정의되어 있다. 이외에 from, units(px)가 있으며 camelCase로 표기한다. * @param {Number} duration (optional, defaults to 1 second) Length of animation (frames or seconds), defaults to time-based * @param {Function} method (optional, defaults to DU.animation.LEasing.easeNone) Computes the values that are applied to the attributes per frame (generally a DU.animation.LEasing method) */ init: function(el, attributes, duration, method) { /** * animation이 작동될 지 여부 * @property isAnimated * @private * @type Boolean */ var isAnimated = false; /** * animation 시작시 생성되는 date object * @property startTime * @private * @type Date */ var startTime = null; /** * animation 실행시 보여질 frame 수 * @property actualFrames * @private * @type Int */ var actualFrames = 0; /** * animate될 element * @property el * @private * @type HTMLElement */ el = DU.util.LDom.get(el); /** * animate될 attribute들의 collection * 각 attribute들은 적어도 "to" 또는 "by"가 정의되어 있어야 한다. * "to"를 설정하면 해당 값으로 animation이 끝난다. * "by"를 설정하면 시작값에 해당 값을 더해서 animation이 끝난다. * 둘다 설정하면 "to"만 사용되고 "by"는 무시된다. * option으로 "from"은 animation시작값으로 기본값은 현재 값이다. 그리고 "unit"은 값들의 단위를 지정한다. * @property attributes * @type Object */ this.attributes = attributes || {}; /** * animation 시간으로 기본값은 "1"(초) * @property duration * @type Number */ this.duration = !DU.isUndefined(duration) ? duration : 1; /** * animation동안 attribute에 제공될 값을 만드는 method * Default는 "DU.animation.LEasing.easeNone". * @property method * @type Function */ this.method = method || Y.LEasing.easeNone; /** * duration에 초를 사용할 지 여부 * Defaults to true. * @property useSeconds * @type Boolean */ this.useSeconds = true; // default to seconds /** * timeline에서 현재 animation의 위치 * time-based animation에서 LAnimMgr에 의해 animation이 제시간에 끝났는지 확인용으로 사용된다. * @property currentFrame * @type Int */ this.currentFrame = 0; /** * 실행될 총 frame수 * time-based animation에서 LAnimMgr에 의해 animation이 제시간에 끝났는지 확인용으로 사용된다. * @property totalFrames * @type Int */ this.totalFrames = Y.LAnimMgr.fps; /** * animate될 element를 변경한다. * @method setEl */ this.setEl = function(element) { el = DU.util.LDom.get(element); }; /** * animate될 element를 return * @method getEl * @return {HTMLElement} */ this.getEl = function() { return el; }; /** * animate되고 있는지 여부 return * @method isAnimated * @return {Boolean} isAnimated의 현재 값 */ this.isAnimated = function() { return isAnimated; }; /** * animation 시작 시간 return * @method getStartTime * @return {Date} 시작시간 */ this.getStartTime = function() { return startTime; }; this.runtimeAttributes = {}; /** * animation manager에 등록하면서 animation을 시작한다. * @method animate */ this.animate = function() { if ( this.isAnimated() ) { return false; } this.currentFrame = 0; this.totalFrames = ( this.useSeconds ) ? Math.ceil(Y.LAnimMgr.fps * this.duration) : this.duration; if (this.duration === 0 && this.useSeconds) { // jump to last frame if zero second duration this.totalFrames = 1; } Y.LAnimMgr.registerElement(this); return true; }; /** * animation을 정지한다. 일반적으로 animation이 끝났을 경우 LAnimMgr에 의해 call된다. * @method stop * @param {Boolean} finish (optional) true면 마지막 frame로 이동한다. */ this.stop = function(finish) { if (!this.isAnimated()) { // nothing to stop return false; } if (finish) { this.currentFrame = this.totalFrames; this._onTween.fire(); } Y.LAnimMgr.stop(this); }; var onStart = function() { this.onStart.fire(); this.runtimeAttributes = {}; for (var attr in this.attributes) { this.setRuntimeAttribute(attr); } isAnimated = true; actualFrames = 0; startTime = new Date(); }; /** * 각각의 animated attribute에 대한 시작값, 종료값을 각 프레임 별로 넣고, 결과값을 각 attribute에 적용한다. * @private */ var onTween = function() { var data = { duration: new Date() - this.getStartTime(), currentFrame: this.currentFrame }; data.toString = function() { return ( 'duration: ' + data.duration + ', currentFrame: ' + data.currentFrame ); }; this.onTween.fire(data); var runtimeAttributes = this.runtimeAttributes; for (var attr in runtimeAttributes) { this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit); } actualFrames += 1; }; var onComplete = function() { var actual_duration = (new Date() - startTime) / 1000 ; var data = { duration: actual_duration, frames: actualFrames, fps: actualFrames / actual_duration }; data.toString = function() { return ( 'duration: ' + data.duration + ', frames: ' + data.frames + ', fps: ' + data.fps ); }; isAnimated = false; actualFrames = 0; this.onComplete.fire(data); }; /** * subclassing에 유용한, onStart 이후에 발생하는 Custom event * @private */ this._onStart = new DU.util.LCustomEvent('_start', this, true); /** * animation의 시작 event * @event onStart */ this.onStart = new DU.util.LCustomEvent('start', this); /** * 각 frame별로 fire되는 event * @event onTween */ this.onTween = new DU.util.LCustomEvent('tween', this); /** * onTween 이후에 발생하는 Custom event * @private */ this._onTween = new DU.util.LCustomEvent('_tween', this, true); /** * animation 종료 event * @event onComplete */ this.onComplete = new DU.util.LCustomEvent('complete', this); /** * onComplete 이후에 발생하는 Custom event * @private */ this._onComplete = new DU.util.LCustomEvent('_complete', this, true); this._onStart.on(onStart); this._onTween.on(onTween); this._onComplete.on(onComplete); } }; Y.LAnim = LAnim; })(); /** * animation과 theading 처리 * LAnim과 subclass 들에서 사용됨 * @class LAnimMgr * @namespace DU.animation */ DU.animation.LAnimMgr = new function() { /** * animation Interval을 위한 참조값. * @property thread * @private * @type Int */ var thread = null; /** * 등록된 animation object들 중 현재 queue object. * @property queue * @private * @type Array */ var queue = []; /** * 활성화(active)된 animation 갯수. * @property tweenCount * @private * @type Int */ var tweenCount = 0; /** * 기본 frame 비율 (frames per second). * 더 나은 x-browser calibration을 위해 임의로 증가(느린 브라우저들은 frame이 더 떨어짐) * @property fps * @type Int * */ this.fps = 1000; /** * milliseconds 단위의 지연 간격, 가능한 가장 빠른 속도로 deafult 설정된다. * @property delay * @type Int * */ this.delay = 1; /** * animation queue에 animation instance를 추가한다. * 모든 animation instance는 움직이기 위해 반드시 등록되어야 한다. * @method registerElement * @param {object} tween 등록될 LAnim instance 객체 */ this.registerElement = function(tween) { queue[queue.length] = tween; tweenCount += 1; tween._onStart.fire(); this.start(); }; /** * animation queue로 부터 animation instace를 제거한다. * 모든 animation instance는 움직이기 위해 반드시 등록되어야 한다. * @method unRegister * @param {object} tween 등록된 LAnim instance 객체 * @param {Int} index LAnim instance의 index * @private */ this.unRegister = function(tween, index) { index = index || getIndex(tween); if (!tween.isAnimated() || index == -1) { return false; } tween._onComplete.fire(); queue.splice(index, 1); tweenCount -= 1; if (tweenCount <= 0) { this.stop(); } return true; }; /** * animation thread를 시작한다. * 한번에 오직 하나의 thread만 실행할 수 있다. * @method start */ this.start = function() { if (thread === null) { thread = setInterval(this.run, this.delay); } }; /** * animation thread나 특정 animation instance를 중지한다. * @method stop * @param {object} tween 중지할 특정 LAnim instance(optional) * 만약 instance가 주어지지 않는다면, Manager는 thread와 모든 animation을 중지한다. */ this.stop = function(tween) { if (!tween) { clearInterval(thread); for (var i = 0, len = queue.length; i < len; ++i) { this.unRegister(queue[0], 0); } queue = []; thread = null; tweenCount = 0; } else { this.unRegister(tween); } }; /** * 각각의 animation frame를 처리하는 간격마다 호출된다. * @method run */ this.run = function() { for (var i = 0, len = queue.length; i < len; ++i) { var tween = queue[i]; if ( !tween || !tween.isAnimated() ) { continue; } if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null) { tween.currentFrame += 1; if (tween.useSeconds) { correctFrame(tween); } tween._onTween.fire(); } else { DU.animation.LAnimMgr.stop(tween, i); } } }; var getIndex = function(anim) { for (var i = 0, len = queue.length; i < len; ++i) { if (queue[i] == anim) { return i; // note return; } } return -1; }; /** * animation을 제시간으로 유지하기 위한 fly frame correction. * @method correctFrame * @private * @param {Object} tween The LAnim instance being corrected. */ var correctFrame = function(tween) { var frames = tween.totalFrames; var frame = tween.currentFrame; var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames); var elapsed = (new Date() - tween.getStartTime()); var tweak = 0; if (elapsed < tween.duration * 1000) { // check if falling behind tweak = Math.round((elapsed / expected - 1) * tween.currentFrame); } else { // went over duration, so jump to end tweak = frames - (frame + 1); } if (tweak > 0 && isFinite(tweak)) { // adjust if needed if (tween.currentFrame + tweak >= frames) {// dont go past last frame tweak = frames - (frame + 1); } tween.currentFrame += tweak; } }; }; (function() { /** * color 전환을 위한 LAnim subclass. *Usage: var myAnim = new Y.LColorAnim(el, { backgroundColor: { from: '#FF0000', to: '#FFFFFF' } }, 1, Y.LEasing.easeOut);
컬러값은 다음과 같이 지정될 수 있다. 112233, #112233,
* [255,255,255], or rgb(255,255,255)
Usage: var myAnim = new DU.animation.LMotion(el, { points: { to: [800, 800] } }, 1, DU.animation.LEasing.easeOut);
Usage: var myAnim = new DU.animation.LScroll(el, { scroll: { to: [0, 800] } }, 1, DU.animation.LEasing.easeOut);