You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

12686 lines
347 KiB

7 years ago
  1. /**
  2. * Jindo2 Framework
  3. * @version 1.5.2
  4. * NHN_Library:Jindo-1.5.2;JavaScript Framework;
  5. */
  6. /**
  7. * @fileOverview $와 $Class를 정의한 파일
  8. */
  9. if (typeof window != "undefined" && typeof window.nhn == "undefined") {
  10. window.nhn = {};
  11. }
  12. if (typeof window != "undefined") {
  13. if (typeof window.jindo == "undefined") {
  14. window.jindo = {};
  15. }
  16. } else {
  17. if (!jindo) {
  18. jindo = {};
  19. }
  20. }
  21. /**
  22. * $Jindo 객체를 리턴한다. $Jindo 객체는 프레임웍에 대한 정보와 유틸리티 함수를 제공한다.
  23. * @constructor
  24. * @class $Jindo 객체는 프레임웍에 대한 정보와 유틸리티 함수를 제공한다.
  25. * @description [Lite]
  26. */
  27. jindo.$Jindo = function() {
  28. var cl=arguments.callee;
  29. var cc=cl._cached;
  30. if (cc) return cc;
  31. if (!(this instanceof cl)) return new cl();
  32. if (!cc) cl._cached = this;
  33. this.version = "1.5.2";
  34. }
  35. /**
  36. * @function
  37. * $ 함수는 다음의 가지 역할을 한다.
  38. * <ul><li/>ID를 사용하여 HTML 엘리먼트를 가져온다. 매개변수를 이상 지정하면 HTML 엘리먼트를 원소로하는 배열을 리턴한다.
  39. * <li>또한 "<tagName>" 같은 형식의 문자열을 입력하면 tagName을 가지는 객체를 생성한다.</li></ul>
  40. * @param {String...} sID HTML 엘리먼트의 ID. ID는 하나 이상 지정할 있다. (1.4.6부터는 마지막 매개변수에 document을 지정할수 있다.)
  41. * @return {Element|Array} HTML 엘리먼트 혹은 HTML 엘리먼트를 원소로 가지는 배열을 리턴한다. 만약 ID에 해당하는 HTML 엘리먼트가 없으면 null을 리턴한다.
  42. * @description [Lite]
  43. * @example
  44. // ID를 이용하여 객체를 리턴한다.
  45. <div id="div1"></div>
  46. var el = $("div1");
  47. // ID를 이용하여 여러개의 객체를 리턴한다.
  48. <div id="div1"></div>
  49. <div id="div2"></div>
  50. var els = $("div1","div2"); // [$("div1"),$("div2")]와 같은 결과를 리턴한다.
  51. // tagName과 같은 형식의 문자열을 이용하여 객체를 생성한다.
  52. var el = $("<DIV>");
  53. var els = $("<DIV id='div1'><SPAN>hello</SPAN></DIV>");
  54. //IE는 iframe에 추가할 엘리먼트를 생성하려고 할 때는 document를 반드시 지정해야 한다.(1.4.6 부터 지원)
  55. var els = $("<div>" , iframe.contentWindow.document);
  56. //위와 같을 경우 div태그가 iframe.contentWindow.document기준으로 생김.
  57. */
  58. jindo.$ = function(sID/*, id1, id2*/) {
  59. var ret = [], arg = arguments, nArgLeng = arg.length, lastArgument = arg[nArgLeng-1],doc = document,el = null;
  60. var reg = /^<([a-z]+|h[1-5])>$/i;
  61. var reg2 = /^<([a-z]+|h[1-5])(\s+[^>]+)?>/i;
  62. if (nArgLeng > 1 && typeof lastArgument != "string" && lastArgument.body) {
  63. /*
  64. 마지막 인자가 document일때.
  65. */
  66. arg = Array.prototype.slice.apply(arg,[0,nArgLeng-1]);
  67. doc = lastArgument;
  68. }
  69. for(var i=0; i < nArgLeng; i++) {
  70. el = arg[i];
  71. if (typeof el == "string") {
  72. el = el.replace(/^\s+|\s+$/g, "");
  73. if (el.indexOf("<")>-1) {
  74. if (reg.test(el)) {
  75. el = doc.createElement(RegExp.$1);
  76. }else if (reg2.test(el)) {
  77. var p = { thead:'table', tbody:'table', tr:'tbody', td:'tr', dt:'dl', dd:'dl', li:'ul', legend:'fieldset',option:"select" };
  78. var tag = RegExp.$1.toLowerCase();
  79. var ele = jindo._createEle(p[tag],el,doc);
  80. for (var i=0,leng = ele.length; i < leng ; i++) {
  81. ret.push(ele[i]);
  82. };
  83. el = null;
  84. }
  85. }else {
  86. el = doc.getElementById(el);
  87. }
  88. }
  89. if (el) ret[ret.length] = el;
  90. }
  91. return ret.length>1?ret:(ret[0] || null);
  92. }
  93. jindo._createEle = function(sParentTag,sHTML,oDoc,bWantParent){
  94. var sId = 'R' + new Date().getTime() + parseInt(Math.random() * 100000,10);
  95. var oDummy = oDoc.createElement("div");
  96. switch (sParentTag) {
  97. case 'select':
  98. case 'table':
  99. case 'dl':
  100. case 'ul':
  101. case 'fieldset':
  102. oDummy.innerHTML = '<' + sParentTag + ' class="' + sId + '">' + sHTML + '</' + sParentTag + '>';
  103. break;
  104. case 'thead':
  105. case 'tbody':
  106. case 'col':
  107. oDummy.innerHTML = '<table><' + sParentTag + ' class="' + sId + '">' + sHTML + '</' + sParentTag + '></table>';
  108. break;
  109. case 'tr':
  110. oDummy.innerHTML = '<table><tbody><tr class="' + sId + '">' + sHTML + '</tr></tbody></table>';
  111. break;
  112. default:
  113. oDummy.innerHTML = '<div class="' + sId + '">' + sHTML + '</div>';
  114. break;
  115. }
  116. var oFound;
  117. for (oFound = oDummy.firstChild; oFound; oFound = oFound.firstChild){
  118. if (oFound.className==sId) break;
  119. }
  120. return bWantParent? oFound : oFound.childNodes;
  121. }
  122. /**
  123. * 클래스 객체를 생성한다.
  124. * @extends core
  125. * @class $Class는 Jindo에서 객체 지향 프로그래밍(OOP) 구현하는 객체이다. $Class.$init 메소드는 클래스를 생성할 클래스 인스턴스에 대한 생성자 함수를 정의한다.
  126. * @param {Object} oDef 클래스를 정의하는 객체. 메서드, 프로퍼티와 생성자를 정의한다. $staic 키워드는 인스턴스를 생성하지 않아도 사용할 있는 메서드의 집합이다.
  127. * @return {$Class} 클래스 객체
  128. * @description [Lite]
  129. * @example
  130. var CClass = $Class({
  131. prop : null,
  132. $init : function() {
  133. this.prop = $Ajax();
  134. ...
  135. },
  136. $static : {
  137. static_method : function(){ return 1;}
  138. }
  139. });
  140. var c1 = new CClass();
  141. var c2 = new CClass();
  142. // c1과 c2는 서로 다른 $Ajax 객체를 각각 가진다.
  143. CClass.static_method(); -> 1
  144. */
  145. jindo.$Class = function(oDef) {
  146. function typeClass() {
  147. var t = this;
  148. var a = [];
  149. var superFunc = function(m, superClass, func) {
  150. if(m!='constructor' && func.toString().indexOf("$super")>-1 ){
  151. var funcArg = func.toString().replace(/function\s*\(([^\)]*)[\w\W]*/g,"$1").split(",");
  152. // var funcStr = func.toString().replace(/function\s*\(.*\)\s*\{/,"").replace(/this\.\$super/g,"this.$super.$super");
  153. var funcStr = func.toString().replace(/function[^{]*{/,"").replace(/(\w|\.?)(this\.\$super|this)/g,function(m,m2,m3){
  154. if(!m2){
  155. return m3+".$super"
  156. }
  157. return m;
  158. });
  159. funcStr = funcStr.substr(0,funcStr.length-1);
  160. func = superClass[m] = eval("false||function("+funcArg.join(",")+"){"+funcStr+"}");
  161. }
  162. return function() {
  163. var f = this.$this[m];
  164. var t = this.$this;
  165. var r = (t[m] = func).apply(t, arguments);
  166. t[m] = f;
  167. return r;
  168. };
  169. }
  170. while(typeof t._$superClass != "undefined") {
  171. t.$super = new Object;
  172. t.$super.$this = this;
  173. for(var x in t._$superClass.prototype) {
  174. if (t._$superClass.prototype.hasOwnProperty(x)){
  175. if (typeof this[x] == "undefined" && x !="$init") this[x] = t._$superClass.prototype[x];
  176. if (x!='constructor' && x!='_$superClass' && typeof t._$superClass.prototype[x] == "function") {
  177. t.$super[x] = superFunc(x, t._$superClass, t._$superClass.prototype[x]);
  178. } else {
  179. t.$super[x] = t._$superClass.prototype[x];
  180. }
  181. }
  182. }
  183. if (typeof t.$super.$init == "function") a[a.length] = t;
  184. t = t.$super;
  185. }
  186. for(var i=a.length-1; i > -1; i--) a[i].$super.$init.apply(a[i].$super, arguments);
  187. if (typeof this.$init == "function") this.$init.apply(this,arguments);
  188. }
  189. if (typeof oDef.$static != "undefined") {
  190. var i=0, x;
  191. for(x in oDef){
  192. if (oDef.hasOwnProperty(x)) {
  193. x=="$static"||i++;
  194. }
  195. }
  196. for(x in oDef.$static){
  197. if (oDef.$static.hasOwnProperty(x)) {
  198. typeClass[x] = oDef.$static[x];
  199. }
  200. }
  201. if (!i) return oDef.$static;
  202. delete oDef.$static;
  203. }
  204. // if (typeof oDef.$destroy == "undefined") {
  205. // oDef.$destroy = function(){
  206. // if(this.$super&&(arguments.callee==this.$super.$destroy)){this.$super.$destroy();}
  207. // }
  208. // } else {
  209. // oDef.$destroy = eval("false||"+oDef.$destroy.toString().replace(/\}$/,"console.log(this.$super);console.log(arguments.callee!=this.$super.$destroy);if(this.$super&&(arguments.callee==this.$destroy)){this.$super.$destroy();}}"));
  210. // }
  211. //
  212. typeClass.prototype = oDef;
  213. typeClass.prototype.constructor = typeClass;
  214. typeClass.extend = jindo.$Class.extend;
  215. return typeClass;
  216. }
  217. /**
  218. * 클래스를 상속한다.
  219. * 하위 클래스는 this.$super.method 상위 클래스의 메서드에 접근할 있으나, this.$super.$super.method 같이 단계 이상의 상위 클래스는 접근할 없다.
  220. * @name $Class#extend
  221. * @type $Class
  222. * @function
  223. * @param {$Class} superClass 수퍼 클래스 객체
  224. * @return {$Class} 상속된 클래스
  225. * @description [Lite]
  226. * @example
  227. var ClassExt = $Class(classDefinition);
  228. ClassExt.extend(superClass);
  229. // ClassExt는 SuperClass를 상속받는다.
  230. */
  231. jindo.$Class.extend = function(superClass) {
  232. // superClass._$has_super = true;
  233. if (typeof superClass == "undefined" || superClass === null || !superClass.extend) {
  234. throw new Error("extend시 슈퍼 클래스는 Class여야 합니다.");
  235. }
  236. this.prototype._$superClass = superClass;
  237. // inherit static methods of parent
  238. for(var x in superClass) {
  239. if (superClass.hasOwnProperty(x)) {
  240. if (x == "prototype") continue;
  241. this[x] = superClass[x];
  242. }
  243. }
  244. return this;
  245. };
  246. /**
  247. 부모 클래스의 메서드에 접근할 사용한다. 부모 클래스와 자식 클래스가 같은 이름의 메서드를 가지고 있고 $super로 메서드를 호출하면, 자식 클래스의 메서드를 사용한다.
  248. @name $Class#$super
  249. @type $Class
  250. @example
  251. var Parent = $Class ({
  252. a: 100,
  253. b: 200,
  254. c: 300,
  255. sum2: function () {
  256. var init = this.sum();
  257. return init;
  258. },
  259. sum: function () {
  260. return this.a + this.b
  261. }
  262. });
  263. var Child = $Class ({
  264. a: 10,
  265. b: 20,
  266. sum2 : function () {
  267. var init = this.sum();
  268. return init;
  269. },
  270. sum: function () {
  271. return this.b;
  272. }
  273. }).extend (Parent);
  274. var oChild = new Child();
  275. var oParent = new Parent();
  276. oChild.sum(); // 20
  277. oChild.sum2(); // 20
  278. oChild.$super.sum(); // 30 -> 부모 클래스의 100(a)과 200(b)대신 자식 클래스의 10(a)과 20(b)을 더한다.
  279. oChild.$super.sum2(); // 20 -> 부모 클래스의 sum2 메서드에서 부모 클래스의 sum()이 아닌 자식 클래스의 sum()을 호출한다.
  280. */
  281. /**
  282. * @fileOverview CSS 셀렉터를 사용한 엘리먼트 선택 엔진
  283. * @name cssquery.js
  284. * @author Hooriza
  285. */
  286. /**
  287. * CSS 셀렉터를 사용하여 객체를 탐색한다.
  288. *
  289. * @function CSS 셀렉터를 사용하여 객체를 탐색한다.
  290. * @param {String} CSS셀렉터
  291. * @param {Element} 탐색 대상이 되는 요소, 요소의 하위 노드에서만 탐색한다.
  292. * @return {Array} 조건에 해당하는 요소의 배열을 반환한다.
  293. * @description [Lite]
  294. * @example
  295. // 문서에서 IMG 태그를 찾는다.
  296. var imgs = $$('IMG');
  297. // div 요소 하위에서 IMG 태그를 찾는다.
  298. var imgsInDiv = $$('IMG', $('div'));
  299. // 문서에서 IMG 태그 중 가장 첫 요소를 찾는다.
  300. var firstImg = $$.getSingle('IMG');
  301. */
  302. jindo.$$ = jindo.cssquery = (function() {
  303. /*
  304. querySelector 설정.
  305. */
  306. var sVersion = '3.0';
  307. var debugOption = { repeat : 1 };
  308. /*
  309. 빠른 처리를 위해 노드마다 유일키 셋팅
  310. */
  311. var UID = 1;
  312. var cost = 0;
  313. var validUID = {};
  314. var bSupportByClassName = document.getElementsByClassName ? true : false;
  315. var safeHTML = false;
  316. var getUID4HTML = function(oEl) {
  317. var nUID = safeHTML ? (oEl._cssquery_UID && oEl._cssquery_UID[0]) : oEl._cssquery_UID;
  318. if (nUID && validUID[nUID] == oEl) return nUID;
  319. nUID = UID++;
  320. oEl._cssquery_UID = safeHTML ? [ nUID ] : nUID;
  321. validUID[nUID] = oEl;
  322. return nUID;
  323. };
  324. var getUID4XML = function(oEl) {
  325. var oAttr = oEl.getAttribute('_cssquery_UID');
  326. var nUID = safeHTML ? (oAttr && oAttr[0]) : oAttr;
  327. if (!nUID) {
  328. nUID = UID++;
  329. oEl.setAttribute('_cssquery_UID', safeHTML ? [ nUID ] : nUID);
  330. }
  331. return nUID;
  332. };
  333. var getUID = getUID4HTML;
  334. var uniqid = function(sPrefix) {
  335. return (sPrefix || '') + new Date().getTime() + parseInt(Math.random() * 100000000,10);
  336. };
  337. function getElementsByClass(searchClass,node,tag) {
  338. var classElements = new Array();
  339. if ( node == null )
  340. node = document;
  341. if ( tag == null )
  342. tag = '*';
  343. var els = node.getElementsByTagName(tag);
  344. var elsLen = els.length;
  345. var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
  346. for (i = 0, j = 0; i < elsLen; i++) {
  347. if ( pattern.test(els[i].className) ) {
  348. classElements[j] = els[i];
  349. j++;
  350. }
  351. }
  352. return classElements;
  353. }
  354. var getChilds_dontShrink = function(oEl, sTagName, sClassName) {
  355. if (bSupportByClassName && sClassName) {
  356. if(oEl.getElementsByClassName)
  357. return oEl.getElementsByClassName(sClassName);
  358. if(oEl.querySelectorAll)
  359. return oEl.querySelectorAll(sClassName);
  360. return getElementsByClass(sClassName, oEl, sTagName);
  361. }else if (sTagName == '*') {
  362. return oEl.all || oEl.getElementsByTagName(sTagName);
  363. }
  364. return oEl.getElementsByTagName(sTagName);
  365. };
  366. var clearKeys = function() {
  367. backupKeys._keys = {};
  368. };
  369. var oDocument_dontShrink = document;
  370. var bXMLDocument = false;
  371. /*
  372. 따옴표, [] 파싱에 문제가 있는 부분 replace 시켜놓기
  373. */
  374. var backupKeys = function(sQuery) {
  375. var oKeys = backupKeys._keys;
  376. /*
  377. 작은 따옴표 걷어내기
  378. */
  379. sQuery = sQuery.replace(/'(\\'|[^'])*'/g, function(sAll) {
  380. var uid = uniqid('QUOT');
  381. oKeys[uid] = sAll;
  382. return uid;
  383. });
  384. /*
  385. 따옴표 걷어내기
  386. */
  387. sQuery = sQuery.replace(/"(\\"|[^"])*"/g, function(sAll) {
  388. var uid = uniqid('QUOT');
  389. oKeys[uid] = sAll;
  390. return uid;
  391. });
  392. /*
  393. [ ] 형태 걷어내기
  394. */
  395. sQuery = sQuery.replace(/\[(.*?)\]/g, function(sAll, sBody) {
  396. if (sBody.indexOf('ATTR') == 0) return sAll;
  397. var uid = '[' + uniqid('ATTR') + ']';
  398. oKeys[uid] = sAll;
  399. return uid;
  400. });
  401. /*
  402. ( ) 형태 걷어내기
  403. */
  404. var bChanged;
  405. do {
  406. bChanged = false;
  407. sQuery = sQuery.replace(/\(((\\\)|[^)|^(])*)\)/g, function(sAll, sBody) {
  408. if (sBody.indexOf('BRCE') == 0) return sAll;
  409. var uid = '_' + uniqid('BRCE');
  410. oKeys[uid] = sAll;
  411. bChanged = true;
  412. return uid;
  413. });
  414. } while(bChanged);
  415. return sQuery;
  416. };
  417. /*
  418. replace 시켜놓은 부분 복구하기
  419. */
  420. var restoreKeys = function(sQuery, bOnlyAttrBrace) {
  421. var oKeys = backupKeys._keys;
  422. var bChanged;
  423. var rRegex = bOnlyAttrBrace ? /(\[ATTR[0-9]+\])/g : /(QUOT[0-9]+|\[ATTR[0-9]+\])/g;
  424. do {
  425. bChanged = false;
  426. sQuery = sQuery.replace(rRegex, function(sKey) {
  427. if (oKeys[sKey]) {
  428. bChanged = true;
  429. return oKeys[sKey];
  430. }
  431. return sKey;
  432. });
  433. } while(bChanged);
  434. /*
  435. ( ) 한꺼풀만 벗겨내기
  436. */
  437. sQuery = sQuery.replace(/_BRCE[0-9]+/g, function(sKey) {
  438. return oKeys[sKey] ? oKeys[sKey] : sKey;
  439. });
  440. return sQuery;
  441. };
  442. /*
  443. replace 시켜놓은 문자열에서 Quot 제외하고 리턴
  444. */
  445. var restoreString = function(sKey) {
  446. var oKeys = backupKeys._keys;
  447. var sOrg = oKeys[sKey];
  448. if (!sOrg) return sKey;
  449. return eval(sOrg);
  450. };
  451. var wrapQuot = function(sStr) {
  452. return '"' + sStr.replace(/"/g, '\\"') + '"';
  453. };
  454. var getStyleKey = function(sKey) {
  455. if (/^@/.test(sKey)) return sKey.substr(1);
  456. return null;
  457. };
  458. var getCSS = function(oEl, sKey) {
  459. if (oEl.currentStyle) {
  460. if (sKey == "float") sKey = "styleFloat";
  461. return oEl.currentStyle[sKey] || oEl.style[sKey];
  462. } else if (window.getComputedStyle) {
  463. return oDocument_dontShrink.defaultView.getComputedStyle(oEl, null).getPropertyValue(sKey.replace(/([A-Z])/g,"-$1").toLowerCase()) || oEl.style[sKey];
  464. }
  465. if (sKey == "float" && /MSIE/.test(window.navigator.userAgent)) sKey = "styleFloat";
  466. return oEl.style[sKey];
  467. };
  468. var oCamels = {
  469. 'accesskey' : 'accessKey',
  470. 'cellspacing' : 'cellSpacing',
  471. 'cellpadding' : 'cellPadding',
  472. 'class' : 'className',
  473. 'colspan' : 'colSpan',
  474. 'for' : 'htmlFor',
  475. 'maxlength' : 'maxLength',
  476. 'readonly' : 'readOnly',
  477. 'rowspan' : 'rowSpan',
  478. 'tabindex' : 'tabIndex',
  479. 'valign' : 'vAlign'
  480. };
  481. var getDefineCode = function(sKey) {
  482. var sVal;
  483. var sStyleKey;
  484. if (bXMLDocument) {
  485. sVal = 'oEl.getAttribute("' + sKey + '",2)';
  486. } else {
  487. if (sStyleKey = getStyleKey(sKey)) {
  488. sKey = '$$' + sStyleKey;
  489. sVal = 'getCSS(oEl, "' + sStyleKey + '")';
  490. } else {
  491. switch (sKey) {
  492. case 'checked':
  493. sVal = 'oEl.checked + ""';
  494. break;
  495. case 'disabled':
  496. sVal = 'oEl.disabled + ""';
  497. break;
  498. case 'enabled':
  499. sVal = '!oEl.disabled + ""';
  500. break;
  501. case 'readonly':
  502. sVal = 'oEl.readOnly + ""';
  503. break;
  504. case 'selected':
  505. sVal = 'oEl.selected + ""';
  506. break;
  507. default:
  508. if (oCamels[sKey]) {
  509. sVal = 'oEl.' + oCamels[sKey];
  510. } else {
  511. sVal = 'oEl.getAttribute("' + sKey + '",2)';
  512. }
  513. }
  514. }
  515. }
  516. return '_' + sKey + ' = ' + sVal;
  517. };
  518. var getReturnCode = function(oExpr) {
  519. var sStyleKey = getStyleKey(oExpr.key);
  520. var sVar = '_' + (sStyleKey ? '$$' + sStyleKey : oExpr.key);
  521. var sVal = oExpr.val ? wrapQuot(oExpr.val) : '';
  522. switch (oExpr.op) {
  523. case '~=':
  524. return '(' + sVar + ' && (" " + ' + sVar + ' + " ").indexOf(" " + ' + sVal + ' + " ") > -1)';
  525. case '^=':
  526. return '(' + sVar + ' && ' + sVar + '.indexOf(' + sVal + ') == 0)';
  527. case '$=':
  528. return '(' + sVar + ' && ' + sVar + '.substr(' + sVar + '.length - ' + oExpr.val.length + ') == ' + sVal + ')';
  529. case '*=':
  530. return '(' + sVar + ' && ' + sVar + '.indexOf(' + sVal + ') > -1)';
  531. case '!=':
  532. return '(' + sVar + ' != ' + sVal + ')';
  533. case '=':
  534. return '(' + sVar + ' == ' + sVal + ')';
  535. }
  536. return '(' + sVar + ')';
  537. };
  538. var getNodeIndex = function(oEl) {
  539. var nUID = getUID(oEl);
  540. var nIndex = oNodeIndexes[nUID] || 0;
  541. /*
  542. 노드 인덱스를 구할 없으면
  543. */
  544. if (nIndex == 0) {
  545. for (var oSib = (oEl.parentNode || oEl._IE5_parentNode).firstChild; oSib; oSib = oSib.nextSibling) {
  546. if (oSib.nodeType != 1){
  547. continue;
  548. }
  549. nIndex++;
  550. setNodeIndex(oSib, nIndex);
  551. }
  552. nIndex = oNodeIndexes[nUID];
  553. }
  554. return nIndex;
  555. };
  556. /*
  557. 몇번째 자식인지 설정하는 부분
  558. */
  559. var oNodeIndexes = {};
  560. var setNodeIndex = function(oEl, nIndex) {
  561. var nUID = getUID(oEl);
  562. oNodeIndexes[nUID] = nIndex;
  563. };
  564. var unsetNodeIndexes = function() {
  565. setTimeout(function() { oNodeIndexes = {}; }, 0);
  566. };
  567. /*
  568. 가상 클래스
  569. */
  570. var oPseudoes_dontShrink = {
  571. 'contains' : function(oEl, sOption) {
  572. return (oEl.innerText || oEl.textContent || '').indexOf(sOption) > -1;
  573. },
  574. 'last-child' : function(oEl, sOption) {
  575. for (oEl = oEl.nextSibling; oEl; oEl = oEl.nextSibling){
  576. if (oEl.nodeType == 1)
  577. return false;
  578. }
  579. return true;
  580. },
  581. 'first-child' : function(oEl, sOption) {
  582. for (oEl = oEl.previousSibling; oEl; oEl = oEl.previousSibling){
  583. if (oEl.nodeType == 1)
  584. return false;
  585. }
  586. return true;
  587. },
  588. 'only-child' : function(oEl, sOption) {
  589. var nChild = 0;
  590. for (var oChild = (oEl.parentNode || oEl._IE5_parentNode).firstChild; oChild; oChild = oChild.nextSibling) {
  591. if (oChild.nodeType == 1) nChild++;
  592. if (nChild > 1) return false;
  593. }
  594. return nChild ? true : false;
  595. },
  596. 'empty' : function(oEl, _) {
  597. return oEl.firstChild ? false : true;
  598. },
  599. 'nth-child' : function(oEl, nMul, nAdd) {
  600. var nIndex = getNodeIndex(oEl);
  601. return nIndex % nMul == nAdd;
  602. },
  603. 'nth-last-child' : function(oEl, nMul, nAdd) {
  604. var oLast = (oEl.parentNode || oEl._IE5_parentNode).lastChild;
  605. for (; oLast; oLast = oLast.previousSibling){
  606. if (oLast.nodeType == 1) break;
  607. }
  608. var nTotal = getNodeIndex(oLast);
  609. var nIndex = getNodeIndex(oEl);
  610. var nLastIndex = nTotal - nIndex + 1;
  611. return nLastIndex % nMul == nAdd;
  612. },
  613. 'checked' : function(oEl){
  614. return !!oEl.checked;
  615. },
  616. 'selected' : function(oEl){
  617. return !!oEl.selected;
  618. },
  619. 'enabled' : function(oEl){
  620. return !oEl.disabled;
  621. },
  622. 'disabled' : function(oEl){
  623. return !!oEl.disabled;
  624. }
  625. };
  626. /*
  627. 단일 part body 에서 expression 뽑아냄
  628. */
  629. var getExpression = function(sBody) {
  630. var oRet = { defines : '', returns : 'true' };
  631. var sBody = restoreKeys(sBody, true);
  632. var aExprs = [];
  633. var aDefineCode = [], aReturnCode = [];
  634. var sId, sTagName;
  635. /*
  636. 유사클래스 조건 얻어내기
  637. */
  638. var sBody = sBody.replace(/:([\w-]+)(\(([^)]*)\))?/g, function(_1, sType, _2, sOption) {
  639. switch (sType) {
  640. case 'not':
  641. /*
  642. 괄호 안에 있는거 재귀파싱하기
  643. */
  644. var oInner = getExpression(sOption);
  645. var sFuncDefines = oInner.defines;
  646. var sFuncReturns = oInner.returnsID + oInner.returnsTAG + oInner.returns;
  647. aReturnCode.push('!(function() { ' + sFuncDefines + ' return ' + sFuncReturns + ' })()');
  648. break;
  649. case 'nth-child':
  650. case 'nth-last-child':
  651. sOption = restoreString(sOption);
  652. if (sOption == 'even'){
  653. sOption = '2n';
  654. }else if (sOption == 'odd') {
  655. sOption = '2n+1';
  656. }
  657. var nMul, nAdd;
  658. var matchstr = sOption.match(/([0-9]*)n([+-][0-9]+)*/);
  659. if (matchstr) {
  660. nMul = matchstr[1] || 1;
  661. nAdd = matchstr[2] || 0;
  662. } else {
  663. nMul = Infinity;
  664. nAdd = parseInt(sOption,10);
  665. }
  666. aReturnCode.push('oPseudoes_dontShrink[' + wrapQuot(sType) + '](oEl, ' + nMul + ', ' + nAdd + ')');
  667. break;
  668. case 'first-of-type':
  669. case 'last-of-type':
  670. sType = (sType == 'first-of-type' ? 'nth-of-type' : 'nth-last-of-type');
  671. sOption = 1;
  672. case 'nth-of-type':
  673. case 'nth-last-of-type':
  674. sOption = restoreString(sOption);
  675. if (sOption == 'even') {
  676. sOption = '2n';
  677. }else if (sOption == 'odd'){
  678. sOption = '2n+1';
  679. }
  680. var nMul, nAdd;
  681. if (/([0-9]*)n([+-][0-9]+)*/.test(sOption)) {
  682. nMul = parseInt(RegExp.$1,10) || 1;
  683. nAdd = parseInt(RegExp.$2,20) || 0;
  684. } else {
  685. nMul = Infinity;
  686. nAdd = parseInt(sOption,10);
  687. }
  688. oRet.nth = [ nMul, nAdd, sType ];
  689. break;
  690. default:
  691. sOption = sOption ? restoreString(sOption) : '';
  692. aReturnCode.push('oPseudoes_dontShrink[' + wrapQuot(sType) + '](oEl, ' + wrapQuot(sOption) + ')');
  693. break;
  694. }
  695. return '';
  696. });
  697. /*
  698. [key=value] 형태 조건 얻어내기
  699. */
  700. var sBody = sBody.replace(/\[(@?[\w-]+)(([!^~$*]?=)([^\]]*))?\]/g, function(_1, sKey, _2, sOp, sVal) {
  701. sKey = restoreString(sKey);
  702. sVal = restoreString(sVal);
  703. if (sKey == 'checked' || sKey == 'disabled' || sKey == 'enabled' || sKey == 'readonly' || sKey == 'selected') {
  704. if (!sVal) {
  705. sOp = '=';
  706. sVal = 'true';
  707. }
  708. }
  709. aExprs.push({ key : sKey, op : sOp, val : sVal });
  710. return '';
  711. });
  712. var sClassName = null;
  713. /*
  714. 클래스 조건 얻어내기
  715. */
  716. var sBody = sBody.replace(/\.([\w-]+)/g, function(_, sClass) {
  717. aExprs.push({ key : 'class', op : '~=', val : sClass });
  718. if (!sClassName) sClassName = sClass;
  719. return '';
  720. });
  721. /*
  722. id 조건 얻어내기
  723. */
  724. var sBody = sBody.replace(/#([\w-]+)/g, function(_, sIdValue) {
  725. if (bXMLDocument) {
  726. aExprs.push({ key : 'id', op : '=', val : sIdValue });
  727. }else{
  728. sId = sIdValue;
  729. }
  730. return '';
  731. });
  732. sTagName = sBody == '*' ? '' : sBody;
  733. /*
  734. match 함수 코드 만들어 내기
  735. */
  736. var oVars = {};
  737. for (var i = 0, oExpr; oExpr = aExprs[i]; i++) {
  738. var sKey = oExpr.key;
  739. if (!oVars[sKey]) aDefineCode.push(getDefineCode(sKey));
  740. /*
  741. 유사클래스 조건 검사가 뒤로 가도록 unshift 사용
  742. */
  743. aReturnCode.unshift(getReturnCode(oExpr));
  744. oVars[sKey] = true;
  745. }
  746. if (aDefineCode.length) oRet.defines = 'var ' + aDefineCode.join(',') + ';';
  747. if (aReturnCode.length) oRet.returns = aReturnCode.join('&&');
  748. oRet.quotID = sId ? wrapQuot(sId) : '';
  749. oRet.quotTAG = sTagName ? wrapQuot(bXMLDocument ? sTagName : sTagName.toUpperCase()) : '';
  750. if (bSupportByClassName) oRet.quotCLASS = sClassName ? wrapQuot(sClassName) : '';
  751. oRet.returnsID = sId ? 'oEl.id == ' + oRet.quotID + ' && ' : '';
  752. oRet.returnsTAG = sTagName && sTagName != '*' ? 'oEl.tagName == ' + oRet.quotTAG + ' && ' : '';
  753. return oRet;
  754. };
  755. /*
  756. 쿼리를 연산자 기준으로 잘라냄
  757. */
  758. var splitToParts = function(sQuery) {
  759. var aParts = [];
  760. var sRel = ' ';
  761. var sBody = sQuery.replace(/(.*?)\s*(!?[+>~ ]|!)\s*/g, function(_, sBody, sRelative) {
  762. if (sBody) aParts.push({ rel : sRel, body : sBody });
  763. sRel = sRelative.replace(/\s+$/g, '') || ' ';
  764. return '';
  765. });
  766. if (sBody) aParts.push({ rel : sRel, body : sBody });
  767. return aParts;
  768. };
  769. var isNth_dontShrink = function(oEl, sTagName, nMul, nAdd, sDirection) {
  770. var nIndex = 0;
  771. for (var oSib = oEl; oSib; oSib = oSib[sDirection]){
  772. if (oSib.nodeType == 1 && (!sTagName || sTagName == oSib.tagName))
  773. nIndex++;
  774. }
  775. return nIndex % nMul == nAdd;
  776. };
  777. /*
  778. 잘라낸 part 함수로 컴파일 하기
  779. */
  780. var compileParts = function(aParts) {
  781. var aPartExprs = [];
  782. /*
  783. 잘라낸 부분들 조건 만들기
  784. */
  785. for (var i = 0, oPart; oPart = aParts[i]; i++)
  786. aPartExprs.push(getExpression(oPart.body));
  787. //////////////////// BEGIN
  788. var sFunc = '';
  789. var sPushCode = 'aRet.push(oEl); if (oOptions.single) { bStop = true; }';
  790. for (var i = aParts.length - 1, oPart; oPart = aParts[i]; i--) {
  791. var oExpr = aPartExprs[i];
  792. var sPush = (debugOption.callback ? 'cost++;' : '') + oExpr.defines;
  793. var sReturn = 'if (bStop) {' + (i == 0 ? 'return aRet;' : 'return;') + '}';
  794. if (oExpr.returns == 'true') {
  795. sPush += (sFunc ? sFunc + '(oEl);' : sPushCode) + sReturn;
  796. }else{
  797. sPush += 'if (' + oExpr.returns + ') {' + (sFunc ? sFunc + '(oEl);' : sPushCode ) + sReturn + '}';
  798. }
  799. var sCheckTag = 'oEl.nodeType != 1';
  800. if (oExpr.quotTAG) sCheckTag = 'oEl.tagName != ' + oExpr.quotTAG;
  801. var sTmpFunc =
  802. '(function(oBase' +
  803. (i == 0 ? ', oOptions) { var bStop = false; var aRet = [];' : ') {');
  804. if (oExpr.nth) {
  805. sPush =
  806. 'if (isNth_dontShrink(oEl, ' +
  807. (oExpr.quotTAG ? oExpr.quotTAG : 'false') + ',' +
  808. oExpr.nth[0] + ',' +
  809. oExpr.nth[1] + ',' +
  810. '"' + (oExpr.nth[2] == 'nth-of-type' ? 'previousSibling' : 'nextSibling') + '")) {' + sPush + '}';
  811. }
  812. switch (oPart.rel) {
  813. case ' ':
  814. if (oExpr.quotID) {
  815. sTmpFunc +=
  816. 'var oEl = oDocument_dontShrink.getElementById(' + oExpr.quotID + ');' +
  817. 'var oCandi = oEl;' +
  818. 'for (; oCandi; oCandi = (oCandi.parentNode || oCandi._IE5_parentNode)) {' +
  819. 'if (oCandi == oBase) break;' +
  820. '}' +
  821. 'if (!oCandi || ' + sCheckTag + ') return aRet;' +
  822. sPush;
  823. } else {
  824. sTmpFunc +=
  825. 'var aCandi = getChilds_dontShrink(oBase, ' + (oExpr.quotTAG || '"*"') + ', ' + (oExpr.quotCLASS || 'null') + ');' +
  826. 'for (var i = 0, oEl; oEl = aCandi[i]; i++) {' +
  827. (oExpr.quotCLASS ? 'if (' + sCheckTag + ') continue;' : '') +
  828. sPush +
  829. '}';
  830. }
  831. break;
  832. case '>':
  833. if (oExpr.quotID) {
  834. sTmpFunc +=
  835. 'var oEl = oDocument_dontShrink.getElementById(' + oExpr.quotID + ');' +
  836. 'if ((oEl.parentNode || oEl._IE5_parentNode) != oBase || ' + sCheckTag + ') return aRet;' +
  837. sPush;
  838. } else {
  839. sTmpFunc +=
  840. 'for (var oEl = oBase.firstChild; oEl; oEl = oEl.nextSibling) {' +
  841. 'if (' + sCheckTag + ') { continue; }' +
  842. sPush +
  843. '}';
  844. }
  845. break;
  846. case '+':
  847. if (oExpr.quotID) {
  848. sTmpFunc +=
  849. 'var oEl = oDocument_dontShrink.getElementById(' + oExpr.quotID + ');' +
  850. 'var oPrev;' +
  851. 'for (oPrev = oEl.previousSibling; oPrev; oPrev = oPrev.previousSibling) { if (oPrev.nodeType == 1) break; }' +
  852. 'if (!oPrev || oPrev != oBase || ' + sCheckTag + ') return aRet;' +
  853. sPush;
  854. } else {
  855. sTmpFunc +=
  856. 'for (var oEl = oBase.nextSibling; oEl; oEl = oEl.nextSibling) { if (oEl.nodeType == 1) break; }' +
  857. 'if (!oEl || ' + sCheckTag + ') { return aRet; }' +
  858. sPush;
  859. }
  860. break;
  861. case '~':
  862. if (oExpr.quotID) {
  863. sTmpFunc +=
  864. 'var oEl = oDocument_dontShrink.getElementById(' + oExpr.quotID + ');' +
  865. 'var oCandi = oEl;' +
  866. 'for (; oCandi; oCandi = oCandi.previousSibling) { if (oCandi == oBase) break; }' +
  867. 'if (!oCandi || ' + sCheckTag + ') return aRet;' +
  868. sPush;
  869. } else {
  870. sTmpFunc +=
  871. 'for (var oEl = oBase.nextSibling; oEl; oEl = oEl.nextSibling) {' +
  872. 'if (' + sCheckTag + ') { continue; }' +
  873. 'if (!markElement_dontShrink(oEl, ' + i + ')) { break; }' +
  874. sPush +
  875. '}';
  876. }
  877. break;
  878. case '!' :
  879. if (oExpr.quotID) {
  880. sTmpFunc +=
  881. 'var oEl = oDocument_dontShrink.getElementById(' + oExpr.quotID + ');' +
  882. 'for (; oBase; oBase = (oBase.parentNode || oBase._IE5_parentNode)) { if (oBase == oEl) break; }' +
  883. 'if (!oBase || ' + sCheckTag + ') return aRet;' +
  884. sPush;
  885. } else {
  886. sTmpFunc +=
  887. 'for (var oEl = (oBase.parentNode || oBase._IE5_parentNode); oEl; oEl = (oEl.parentNode || oEl._IE5_parentNode)) {'+
  888. 'if (' + sCheckTag + ') { continue; }' +
  889. sPush +
  890. '}';
  891. }
  892. break;
  893. case '!>' :
  894. if (oExpr.quotID) {
  895. sTmpFunc +=
  896. 'var oEl = oDocument_dontShrink.getElementById(' + oExpr.quotID + ');' +
  897. 'var oRel = (oBase.parentNode || oBase._IE5_parentNode);' +
  898. 'if (!oRel || oEl != oRel || (' + sCheckTag + ')) return aRet;' +
  899. sPush;
  900. } else {
  901. sTmpFunc +=
  902. 'var oEl = (oBase.parentNode || oBase._IE5_parentNode);' +
  903. 'if (!oEl || ' + sCheckTag + ') { return aRet; }' +
  904. sPush;
  905. }
  906. break;
  907. case '!+' :
  908. if (oExpr.quotID) {
  909. sTmpFunc +=
  910. 'var oEl = oDocument_dontShrink.getElementById(' + oExpr.quotID + ');' +
  911. 'var oRel;' +
  912. 'for (oRel = oBase.previousSibling; oRel; oRel = oRel.previousSibling) { if (oRel.nodeType == 1) break; }' +
  913. 'if (!oRel || oEl != oRel || (' + sCheckTag + ')) return aRet;' +
  914. sPush;
  915. } else {
  916. sTmpFunc +=
  917. 'for (oEl = oBase.previousSibling; oEl; oEl = oEl.previousSibling) { if (oEl.nodeType == 1) break; }' +
  918. 'if (!oEl || ' + sCheckTag + ') { return aRet; }' +
  919. sPush;
  920. }
  921. break;
  922. case '!~' :
  923. if (oExpr.quotID) {
  924. sTmpFunc +=
  925. 'var oEl = oDocument_dontShrink.getElementById(' + oExpr.quotID + ');' +
  926. 'var oRel;' +
  927. 'for (oRel = oBase.previousSibling; oRel; oRel = oRel.previousSibling) { ' +
  928. 'if (oRel.nodeType != 1) { continue; }' +
  929. 'if (oRel == oEl) { break; }' +
  930. '}' +
  931. 'if (!oRel || (' + sCheckTag + ')) return aRet;' +
  932. sPush;
  933. } else {
  934. sTmpFunc +=
  935. 'for (oEl = oBase.previousSibling; oEl; oEl = oEl.previousSibling) {' +
  936. 'if (' + sCheckTag + ') { continue; }' +
  937. 'if (!markElement_dontShrink(oEl, ' + i + ')) { break; }' +
  938. sPush +
  939. '}';
  940. }
  941. break;
  942. }
  943. sTmpFunc +=
  944. (i == 0 ? 'return aRet;' : '') +
  945. '})';
  946. sFunc = sTmpFunc;
  947. }
  948. eval('var fpCompiled = ' + sFunc + ';');
  949. return fpCompiled;
  950. };
  951. /*
  952. 쿼리를 match 함수로 변환
  953. */
  954. var parseQuery = function(sQuery) {
  955. var sCacheKey = sQuery;
  956. var fpSelf = arguments.callee;
  957. var fpFunction = fpSelf._cache[sCacheKey];
  958. if (!fpFunction) {
  959. sQuery = backupKeys(sQuery);
  960. var aParts = splitToParts(sQuery);
  961. fpFunction = fpSelf._cache[sCacheKey] = compileParts(aParts);
  962. fpFunction.depth = aParts.length;
  963. }
  964. return fpFunction;
  965. };
  966. parseQuery._cache = {};
  967. /*
  968. test 쿼리를 match 함수로 변환
  969. */
  970. var parseTestQuery = function(sQuery) {
  971. var fpSelf = arguments.callee;
  972. var aSplitQuery = backupKeys(sQuery).split(/\s*,\s*/);
  973. var aResult = [];
  974. var nLen = aSplitQuery.length;
  975. var aFunc = [];
  976. for (var i = 0; i < nLen; i++) {
  977. aFunc.push((function(sQuery) {
  978. var sCacheKey = sQuery;
  979. var fpFunction = fpSelf._cache[sCacheKey];
  980. if (!fpFunction) {
  981. sQuery = backupKeys(sQuery);
  982. var oExpr = getExpression(sQuery);
  983. eval('fpFunction = function(oEl) { ' + oExpr.defines + 'return (' + oExpr.returnsID + oExpr.returnsTAG + oExpr.returns + '); };');
  984. }
  985. return fpFunction;
  986. })(restoreKeys(aSplitQuery[i])));
  987. }
  988. return aFunc;
  989. };
  990. parseTestQuery._cache = {};
  991. var distinct = function(aList) {
  992. var aDistinct = [];
  993. var oDummy = {};
  994. for (var i = 0, oEl; oEl = aList[i]; i++) {
  995. var nUID = getUID(oEl);
  996. if (oDummy[nUID]) continue;
  997. aDistinct.push(oEl);
  998. oDummy[nUID] = true;
  999. }
  1000. return aDistinct;
  1001. };
  1002. var markElement_dontShrink = function(oEl, nDepth) {
  1003. var nUID = getUID(oEl);
  1004. if (cssquery._marked[nDepth][nUID]) return false;
  1005. cssquery._marked[nDepth][nUID] = true;
  1006. return true;
  1007. };
  1008. var oResultCache = null;
  1009. var bUseResultCache = false;
  1010. var bExtremeMode = false;
  1011. var old_cssquery = function(sQuery, oParent, oOptions) {
  1012. if (typeof sQuery == 'object') {
  1013. var oResult = {};
  1014. for (var k in sQuery){
  1015. if(sQuery.hasOwnProperty(k))
  1016. oResult[k] = arguments.callee(sQuery[k], oParent, oOptions);
  1017. }
  1018. return oResult;
  1019. }
  1020. cost = 0;
  1021. var executeTime = new Date().getTime();
  1022. var aRet;
  1023. for (var r = 0, rp = debugOption.repeat; r < rp; r++) {
  1024. aRet = (function(sQuery, oParent, oOptions) {
  1025. if(oOptions){
  1026. if(!oOptions.oneTimeOffCache){
  1027. oOptions.oneTimeOffCache = false;
  1028. }
  1029. }else{
  1030. oOptions = {oneTimeOffCache:false};
  1031. }
  1032. cssquery.safeHTML(oOptions.oneTimeOffCache);
  1033. if (!oParent) oParent = document;
  1034. /*
  1035. ownerDocument 잡아주기
  1036. */
  1037. oDocument_dontShrink = oParent.ownerDocument || oParent.document || oParent;
  1038. /*
  1039. 브라우저 버젼이 IE5.5 이하
  1040. */
  1041. if (/\bMSIE\s([0-9]+(\.[0-9]+)*);/.test(navigator.userAgent) && parseFloat(RegExp.$1) < 6) {
  1042. try { oDocument_dontShrink.location; } catch(e) { oDocument_dontShrink = document; }
  1043. oDocument_dontShrink.firstChild = oDocument_dontShrink.getElementsByTagName('html')[0];
  1044. oDocument_dontShrink.firstChild._IE5_parentNode = oDocument_dontShrink;
  1045. }
  1046. /*
  1047. XMLDocument 인지 체크
  1048. */
  1049. bXMLDocument = (typeof XMLDocument != 'undefined') ? (oDocument_dontShrink.constructor === XMLDocument) : (!oDocument_dontShrink.location);
  1050. getUID = bXMLDocument ? getUID4XML : getUID4HTML;
  1051. clearKeys();
  1052. /*
  1053. 쿼리를 쉼표로 나누기
  1054. */
  1055. var aSplitQuery = backupKeys(sQuery).split(/\s*,\s*/);
  1056. var aResult = [];
  1057. var nLen = aSplitQuery.length;
  1058. for (var i = 0; i < nLen; i++)
  1059. aSplitQuery[i] = restoreKeys(aSplitQuery[i]);
  1060. /*
  1061. 쉼표로 나눠진 쿼리 루프
  1062. */
  1063. for (var i = 0; i < nLen; i++) {
  1064. var sSingleQuery = aSplitQuery[i];
  1065. var aSingleQueryResult = null;
  1066. var sResultCacheKey = sSingleQuery + (oOptions.single ? '_single' : '');
  1067. /*
  1068. 결과 캐쉬 뒤짐
  1069. */
  1070. var aCache = bUseResultCache ? oResultCache[sResultCacheKey] : null;
  1071. if (aCache) {
  1072. /*
  1073. 캐싱되어 있는게 있으면 parent 같은건지 검사한후 aSingleQueryResult 대입
  1074. */
  1075. for (var j = 0, oCache; oCache = aCache[j]; j++) {
  1076. if (oCache.parent == oParent) {
  1077. aSingleQueryResult = oCache.result;
  1078. break;
  1079. }
  1080. }
  1081. }
  1082. if (!aSingleQueryResult) {
  1083. var fpFunction = parseQuery(sSingleQuery);
  1084. // alert(fpFunction);
  1085. cssquery._marked = [];
  1086. for (var j = 0, nDepth = fpFunction.depth; j < nDepth; j++)
  1087. cssquery._marked.push({});
  1088. // console.log(fpFunction.toSource());
  1089. aSingleQueryResult = distinct(fpFunction(oParent, oOptions));
  1090. /*
  1091. 결과 캐쉬를 사용중이면 캐쉬에 저장
  1092. */
  1093. if (bUseResultCache&&!oOptions.oneTimeOffCache) {
  1094. if (!(oResultCache[sResultCacheKey] instanceof Array)) oResultCache[sResultCacheKey] = [];
  1095. oResultCache[sResultCacheKey].push({ parent : oParent, result : aSingleQueryResult });
  1096. }
  1097. }
  1098. aResult = aResult.concat(aSingleQueryResult);
  1099. }
  1100. unsetNodeIndexes();
  1101. return aResult;
  1102. })(sQuery, oParent, oOptions);
  1103. }
  1104. executeTime = new Date().getTime() - executeTime;
  1105. if (debugOption.callback) debugOption.callback(sQuery, cost, executeTime);
  1106. return aRet;
  1107. };
  1108. var cssquery;
  1109. if (document.querySelectorAll) {
  1110. function _isNonStandardQueryButNotException(sQuery){
  1111. return /\[\s*(?:checked|selected|disabled)/.test(sQuery)
  1112. }
  1113. function _commaRevise (sQuery,sChange) {
  1114. return sQuery.replace(/\,/gi,sChange);
  1115. }
  1116. var protoSlice = Array.prototype.slice;
  1117. var _toArray = function(aArray){
  1118. return protoSlice.apply(aArray);
  1119. }
  1120. try{
  1121. protoSlice.apply(document.documentElement.childNodes);
  1122. }catch(e){
  1123. _toArray = function(aArray){
  1124. var returnArray = [];
  1125. var leng = aArray.length;
  1126. for ( var i = 0; i < leng; i++ ) {
  1127. returnArray.push( aArray[i] );
  1128. }
  1129. return returnArray;
  1130. }
  1131. }
  1132. /**
  1133. */
  1134. cssquery = function(sQuery, oParent, oOptions){
  1135. oParent = oParent || document ;
  1136. try{
  1137. if (_isNonStandardQueryButNotException(sQuery)) {
  1138. throw Error("None Standard Query");
  1139. }else{
  1140. var sReviseQuery = sQuery;
  1141. var oReviseParent = oParent;
  1142. if (oParent.nodeType != 9) {
  1143. if(bExtremeMode){
  1144. if(!oParent.id) oParent.id = "p"+ new Date().getTime() + parseInt(Math.random() * 100000000,10);
  1145. }else{
  1146. throw Error("Parent Element has not ID.or It is not document.or None Extreme Mode.");
  1147. }
  1148. sReviseQuery = _commaRevise("#"+oParent.id+" "+sQuery,", #"+oParent.id);
  1149. oReviseParent = oParent.ownerDocument||oParent.document||document;
  1150. }
  1151. if (oOptions&&oOptions.single) {
  1152. return [oReviseParent.querySelector(sReviseQuery)];
  1153. }else{
  1154. return _toArray(oReviseParent.querySelectorAll(sReviseQuery));
  1155. }
  1156. }
  1157. }catch(e){
  1158. return old_cssquery(sQuery, oParent, oOptions);
  1159. }
  1160. }
  1161. }else{
  1162. cssquery = old_cssquery;
  1163. }
  1164. /**
  1165. * 특정 엘리먼트가 해당 CSS 셀렉터에 부합하는 엘리먼트인지 판단한다
  1166. * @remark CSS 셀렉터에 연결자는 사용할 없음에 유의한다.
  1167. * @param {Element} element 검사하고자 하는 엘리먼트
  1168. * @param {String} selector CSS 셀렉터
  1169. * @return {Boolean} 셀렉터 조건에 부합하면 true, 부합하지 않으면 false
  1170. * @example
  1171. // oEl 이 div 태그 또는 p 태그, 또는 align=center 인 엘리먼트인지
  1172. if (cssquery.test(oEl, 'div, p, [align=center]')) alert('해당 조건 만족');// oEl 이 div 태그 또는 p 태그, 또는 align=center 인 엘리먼트인지
  1173. if (cssquery.test(oEl, 'div, p, [align=center]')) alert('해당 조건 만족');
  1174. */
  1175. cssquery.test = function(oEl, sQuery) {
  1176. clearKeys();
  1177. var aFunc = parseTestQuery(sQuery);
  1178. for (var i = 0, nLen = aFunc.length; i < nLen; i++){
  1179. if (aFunc[i](oEl)) return true;
  1180. }
  1181. return false;
  1182. };
  1183. /**
  1184. * cssquery 결과 캐쉬를 사용할 것인지 지정하거나 확인한다.
  1185. * @remark 결과 캐쉬를 사용하면 동일한 셀렉터를 사용했을 경우 새로 탐색을 하지 않고 기존 탐색 결과를 그대로 반환하기 때문에 사용자가 변수 캐쉬에 신경쓰지 않고 편하고 빠르게 있는 장점이 있지만 결과의 신뢰성을 위해 DOM 변화가 없다는 것이 확실할때만 사용해야 한다.
  1186. * @param {Boolean} flag 사용할 인지 여부 (생략시 사용 여부만 반환)
  1187. * @return {Boolean} 결과 캐쉬를 사용하는지 여부
  1188. */
  1189. cssquery.useCache = function(bFlag) {
  1190. if (typeof bFlag != 'undefined') {
  1191. bUseResultCache = bFlag;
  1192. cssquery.clearCache();
  1193. }
  1194. return bUseResultCache;
  1195. };
  1196. /**
  1197. * 결과 캐쉬를 사용 중에 DOM 변화가 생기는 등의 이유로 캐쉬를 모두 비워주고 싶을때 사용한다.
  1198. * @return {Void} 반환값 없음
  1199. */
  1200. cssquery.clearCache = function() {
  1201. oResultCache = {};
  1202. };
  1203. /**
  1204. * CSS 셀렉터를 사용하여 DOM 에서 원하는 엘리먼트를 하나만 얻어낸다. 반환하는 값은 배열이 아닌 객체 또는 null 이다.
  1205. * @remark 결과를 하나만 얻어내면 이후의 모든 탐색 작업을 중단하기 때문에 결과가 하나라는 보장이 있을때 빠른 속도로 결과를 얻어올 있다.
  1206. * @param {String} selector CSS 셀렉터
  1207. * @param {Document | Element} el 탐색을 진행하는 기준이 되는 엘리먼트 또는 문서 (생략시 현재 문서의 document 객체)
  1208. * @param {Object} 오브젝트에 onTimeOffCache를 true로 하면 해당 쿼리는 cache를 사용하지 않는다.
  1209. * @return {Element} 선택된 엘리먼트
  1210. */
  1211. cssquery.getSingle = function(sQuery, oParent, oOptions) {
  1212. return cssquery(sQuery, oParent, { single : true ,oneTimeOffCache:oOptions?(!!oOptions.oneTimeOffCache):false})[0] || null;
  1213. };
  1214. /**
  1215. * XPath 문법을 사용하여 엘리먼트를 얻어온다.
  1216. * @remark 지원하는 문법이 무척 제한적으로 특수한 경우에서만 사용하는 것을 권장한다.
  1217. * @param {String} xpath XPath
  1218. * @param {Document | Element} el 탐색을 진행하는 기준이 되는 엘리먼트 또는 문서 (생략시 현재 문서의 document 객체)
  1219. * @return {Array} 선택된 엘리먼트 목록의 배열
  1220. */
  1221. cssquery.xpath = function(sXPath, oParent) {
  1222. var sXPath = sXPath.replace(/\/(\w+)(\[([0-9]+)\])?/g, function(_1, sTag, _2, sTh) {
  1223. sTh = sTh || '1';
  1224. return '>' + sTag + ':nth-of-type(' + sTh + ')';
  1225. });
  1226. return old_cssquery(sXPath, oParent);
  1227. };
  1228. /**
  1229. * cssquery 사용할 때의 성능을 측정하기 위한 방법을 제공하는 함수이다.
  1230. * @param {Function} callback 셀렉터 실행에 소요된 비용과 시간을 받아들이는 함수 (false 경우 debug 옵션을 )
  1231. * @param {Number} repeat 하나의 셀렉터를 반복하여 수행하도록 해서 인위적으로 실행 속도를 늦춤
  1232. * @remark callback 함수의 형태는 아래와 같습니다.
  1233. * callback : function({String}query, {Number}cost, {Number}executeTime)
  1234. * <dl>
  1235. * <dt>query</dt>
  1236. * <dd>실행에 사용된 셀렉터</dd>
  1237. * <dt>cost</dt>
  1238. * <dd>탐색에 사용된 비용 (루프 횟수)</dd>
  1239. * <dt>executeTime</dt>
  1240. * <dd>탐색에 소요된 시간</dd>
  1241. * </dl>
  1242. * @return {Void} 반환값 없음
  1243. * @example
  1244. cssquery.debug(function(sQuery, nCost, nExecuteTime) {
  1245. if (nCost > 5000)
  1246. console.warn('5000 이 넘는 비용이?! 체크해보자 -> ' + sQuery + '/' + nCost);
  1247. else if (nExecuteTime > 200)
  1248. console.warn('0.2초가 넘게 실행을?! 체크해보자 -> ' + sQuery + '/' + nExecuteTime);
  1249. }, 20);
  1250. ....
  1251. cssquery.debug(false);
  1252. */
  1253. cssquery.debug = function(fpCallback, nRepeat) {
  1254. debugOption.callback = fpCallback;
  1255. debugOption.repeat = nRepeat || 1;
  1256. };
  1257. /**
  1258. * IE 에서 innerHTML 쓸때 _cssquery_UID 나오지 않도록 하는 함수이다.
  1259. * true 설정하면 그때부터 탐색하는 노드에 대해서는 innerHTML _cssquery_UID 나오지 않도록 하지만 탐색속도는 다소 느려질 있다.
  1260. * @param {Boolean} flag true 셋팅하면 _cssquery_UID 나오지 않음
  1261. * @return {Boolean} _cssquery_UID 나오지 않는 상태이면 true 반환
  1262. */
  1263. cssquery.safeHTML = function(bFlag) {
  1264. var bIE = /MSIE/.test(window.navigator.userAgent);
  1265. if (arguments.length > 0)
  1266. safeHTML = bFlag && bIE;
  1267. return safeHTML || !bIE;
  1268. };
  1269. /**
  1270. * cssquery 버젼정보를 담고 있는 문자열이다.
  1271. */
  1272. cssquery.version = sVersion;
  1273. /**
  1274. * IE에서 validUID,cache를 사용했을때 메모리 닉이 발생하여 삭제하는 모듈 추가.
  1275. */
  1276. cssquery.release = function() {
  1277. if(/MSIE/.test(window.navigator.userAgent)){
  1278. delete validUID;
  1279. validUID = {};
  1280. if(bUseResultCache){
  1281. cssquery.clearCache();
  1282. }
  1283. }
  1284. };
  1285. /**
  1286. * cache가 삭제가 되는지 확인하기 위해 필요한 함수
  1287. * @ignore
  1288. */
  1289. cssquery._getCacheInfo = function(){
  1290. return {
  1291. uidCache : validUID,
  1292. eleCache : oResultCache
  1293. }
  1294. }
  1295. /**
  1296. * 테스트를 위해 필요한 함수
  1297. * @ignore
  1298. */
  1299. cssquery._resetUID = function(){
  1300. UID = 0
  1301. }
  1302. /**
  1303. * querySelector가 있는 브라우져에서 extreme을 실행시키면 querySelector을 사용할수 있는 커버리지가 높아져 전체적으로 속도가 빨리진다.
  1304. * 하지만 ID가 없는 엘리먼트를 기준 엘리먼트로 넣었을 기준 엘리먼트에 임의의 아이디가 들어간다.
  1305. * @param {Boolean} bExtreme true
  1306. */
  1307. cssquery.extreme = function(bExtreme){
  1308. if(arguments.length == 0){
  1309. bExtreme = true;
  1310. }
  1311. bExtremeMode = bExtreme;
  1312. }
  1313. return cssquery;
  1314. })();
  1315. /**
  1316. * @fileOverview $Agent의 생성자 메서드를 정의한 파일
  1317. */
  1318. /**
  1319. * Agent 객체를 반환한다. Agent 객체는 브라우저와 OS에 대한 정보를 가진다.
  1320. * @class Agent 객체는 운영체제, 브라우저를 비롯한 사용자 시스템의 정보를 가진다.
  1321. * @constructor
  1322. * @author Kim, Taegon
  1323. */
  1324. jindo.$Agent = function() {
  1325. var cl = arguments.callee;
  1326. var cc = cl._cached;
  1327. if (cc) return cc;
  1328. if (!(this instanceof cl)) return new cl;
  1329. if (!cc) cl._cached = this;
  1330. this._navigator = navigator;
  1331. }
  1332. /**
  1333. * navigator 메서드는 브라우저의 정보 객체를 리턴한다.
  1334. * @return {Object} 브라우저 정보를 저장하는 객체. <br>
  1335. * object는 브라우저 이름과 버전을 속성으로 가진다. 브라우저 이름은 영어 소문자로 표시하며, 사용자의 브라우저와 일치하는 브라우저 이름은 true를 가진다.
  1336. * @since 1.4.3 부터 mobile,msafari,mopera,mie 사용 가능.
  1337. * @since 1.4.5 부터 ipad에서 mobile은 false를 반환 한다.
  1338. * @example
  1339. oAgent = $Agent().navigator(); // 사용자가 파이어폭스 3를 사용한다고 가정한다.
  1340. oAgent.camino // false
  1341. oAgent.firefox // true
  1342. oAgent.konqueror // false
  1343. oAgent.mozilla //true
  1344. oAgent.netscape // false
  1345. oAgent.omniweb //false
  1346. oAgent.opera //false
  1347. oAgent.webkit /false
  1348. oAgent.safari //false
  1349. oAgent.ie //false
  1350. oAgent.chrome //false
  1351. oAgent.icab //false
  1352. oAgent.version //3
  1353. oAgent.nativeVersion //-1 (1.4.2부터 사용 가능, IE8에서 호환 모드 사용시 nativeVersion은 8로 나옴.)
  1354. oAgent.getName() // firefox
  1355. */
  1356. jindo.$Agent.prototype.navigator = function() {
  1357. var info = new Object;
  1358. var ver = -1;
  1359. var nativeVersion = -1;
  1360. var u = this._navigator.userAgent;
  1361. var v = this._navigator.vendor || "";
  1362. function f(s,h){ return ((h||"").indexOf(s) > -1) };
  1363. info.getName = function(){
  1364. var name = "";
  1365. for(x in info){
  1366. if(typeof info[x] == "boolean" && info[x]&&info.hasOwnProperty(x))
  1367. name = x;
  1368. }
  1369. return name;
  1370. }
  1371. info.webkit = f("WebKit",u);
  1372. info.opera = (typeof window.opera != "undefined") || f("Opera",u);
  1373. info.ie = !info.opera && f("MSIE",u);
  1374. info.chrome = info.webkit && f("Chrome",u);
  1375. info.safari = info.webkit && !info.chrome && f("Apple",v);
  1376. info.firefox = f("Firefox",u);
  1377. info.mozilla = f("Gecko",u) && !info.safari && !info.chrome && !info.firefox;
  1378. info.camino = f("Camino",v);
  1379. info.netscape = f("Netscape",u);
  1380. info.omniweb = f("OmniWeb",u);
  1381. info.icab = f("iCab",v);
  1382. info.konqueror = f("KDE",v);
  1383. info.mobile = (f("Mobile",u)||f("Android",u)||f("Nokia",u)||f("webOS",u)||f("Opera Mini",u)||f("BlackBerry",u)||(f("Windows",u)&&f("PPC",u))||f("Smartphone",u)||f("IEMobile",u))&&!f("iPad",u);
  1384. info.msafari = (!f("IEMobile",u) && f("Mobile",u))||(f("iPad",u)&&f("Safari",u));
  1385. info.mopera = f("Opera Mini",u);
  1386. info.mie = f("PPC",u)||f("Smartphone",u)||f("IEMobile",u);
  1387. try {
  1388. if (info.ie) {
  1389. ver = u.match(/(?:MSIE) ([0-9.]+)/)[1];
  1390. if (u.match(/(?:Trident)\/([0-9.]+)/)){
  1391. var nTridentNum = parseInt(RegExp.$1,10);
  1392. if(nTridentNum > 3){
  1393. nativeVersion = nTridentNum + 4;
  1394. }
  1395. }
  1396. } else if (info.safari||info.msafari) {
  1397. ver = parseFloat(u.match(/Safari\/([0-9.]+)/)[1]);
  1398. if (ver == 100) {
  1399. ver = 1.1;
  1400. } else {
  1401. if(u.match(/Version\/([0-9.]+)/)){
  1402. ver = RegExp.$1;
  1403. }else{
  1404. ver = [1.0,1.2,-1,1.3,2.0,3.0][Math.floor(ver/100)];
  1405. }
  1406. }
  1407. } else if(info.mopera){
  1408. ver = u.match(/(?:Opera\sMini)\/([0-9.]+)/)[1];
  1409. } else if (info.firefox||info.opera||info.omniweb) {
  1410. ver = u.match(/(?:Firefox|Opera|OmniWeb)\/([0-9.]+)/)[1];
  1411. } else if (info.mozilla) {
  1412. ver = u.match(/rv:([0-9.]+)/)[1];
  1413. } else if (info.icab) {
  1414. ver = u.match(/iCab[ \/]([0-9.]+)/)[1];
  1415. } else if (info.chrome) {
  1416. ver = u.match(/Chrome[ \/]([0-9.]+)/)[1];
  1417. }
  1418. info.version = parseFloat(ver);
  1419. info.nativeVersion = parseFloat(nativeVersion);
  1420. if (isNaN(info.version)) info.version = -1;
  1421. } catch(e) {
  1422. info.version = -1;
  1423. }
  1424. this.navigator = function() {
  1425. return info;
  1426. };
  1427. return info;
  1428. };
  1429. /**
  1430. * os 메서드는 운영체제에 대한 정보 객체를 리턴한다.
  1431. * @return {Object} 운영체제 정보 객체. 운영체제의 영문 이름을 속성으로 가지며, 사용자가 사용하는 운영체제와 동일한 이름의 속성은 true를 가진다.
  1432. * @since 1.4.3 부터 iphone,android,nokia,webos,blackberry,mwin 사용 가능.
  1433. * @since 1.4.5 부터 ipad 사용가능.
  1434. * @example
  1435. oOS = $Agent().os(); // 사용자의 운영체제가 Windows XP라고 가정한다.
  1436. oOS.linux // false
  1437. oOS.mac // false
  1438. oOS.vista // false
  1439. oOS.win // true
  1440. oOS.win2000 // false
  1441. oOS.winxp // true
  1442. oOS.xpsp2 // false
  1443. oOS.win7 // false
  1444. oOS.getName() // winxp
  1445. */
  1446. jindo.$Agent.prototype.os = function() {
  1447. var info = new Object;
  1448. var u = this._navigator.userAgent;
  1449. var p = this._navigator.platform;
  1450. var f = function(s,h){ return (h.indexOf(s) > -1) };
  1451. info.getName = function(){
  1452. var name = "";
  1453. for(x in info){
  1454. if(typeof info[x] == "boolean" && info[x]&&info.hasOwnProperty(x))
  1455. name = x;
  1456. }
  1457. return name;
  1458. }
  1459. info.win = f("Win",p)
  1460. info.mac = f("Mac",p);
  1461. info.linux = f("Linux",p);
  1462. info.win2000 = info.win && (f("NT 5.0",u) || f("2000",u));
  1463. info.winxp = info.win && f("NT 5.1",u);
  1464. info.xpsp2 = info.winxp && f("SV1",u);
  1465. info.vista = info.win && f("NT 6.0",u);
  1466. info.win7 = info.win && f("NT 6.1",u);
  1467. info.ipad = f("iPad",u);
  1468. info.iphone = f("iPhone",u) && !info.ipad;
  1469. info.android = f("Android",u);
  1470. info.nokia = f("Nokia",u);
  1471. info.webos = f("webOS",u);
  1472. info.blackberry = f("BlackBerry",u);
  1473. info.mwin = f("PPC",u)||f("Smartphone",u)||f("IEMobile",u);
  1474. this.os = function() {
  1475. return info;
  1476. };
  1477. return info;
  1478. };
  1479. /**
  1480. * flash 메서드는 플래시에 대한 정보 객체를 리턴한다.
  1481. * @return {Object} Flash 정보 객체. <br>
  1482. * object.installed는 플래시 플레이어 설치 여부를 boolean 값으로 가지고 object.version은 플래시 플레이어의 버전을 가진다. 플래시 버전을 탐지하지 못하면 flash.version은 -1 값을 가진다.
  1483. * @example
  1484. var oFlash = $Agent.flash();
  1485. oFlash.installed // 플래시 플레이어를 설치했다면 true
  1486. oFlash.version // 플래시 플레이어의 버전.
  1487. */
  1488. jindo.$Agent.prototype.flash = function() {
  1489. var info = new Object;
  1490. var p = this._navigator.plugins;
  1491. var m = this._navigator.mimeTypes;
  1492. var f = null;
  1493. info.installed = false;
  1494. info.version = -1;
  1495. if (typeof p != "undefined" && p.length) {
  1496. f = p["Shockwave Flash"];
  1497. if (f) {
  1498. info.installed = true;
  1499. if (f.description) {
  1500. info.version = parseFloat(f.description.match(/[0-9.]+/)[0]);
  1501. }
  1502. }
  1503. if (p["Shockwave Flash 2.0"]) {
  1504. info.installed = true;
  1505. info.version = 2;
  1506. }
  1507. } else if (typeof m != "undefined" && m.length) {
  1508. f = m["application/x-shockwave-flash"];
  1509. info.installed = (f && f.enabledPlugin);
  1510. } else {
  1511. for(var i=10; i > 1; i--) {
  1512. try {
  1513. f = new ActiveXObject("ShockwaveFlash.ShockwaveFlash."+i);
  1514. info.installed = true;
  1515. info.version = i;
  1516. break;
  1517. } catch(e) {}
  1518. }
  1519. }
  1520. this.flash = function() {
  1521. return info;
  1522. };
  1523. /*
  1524. 하위호환을 위해 일단 남겨둔다.
  1525. */
  1526. this.info = this.flash;
  1527. return info;
  1528. };
  1529. /**
  1530. * silverlight 메서드는 실버라이트(Silverlight) 대한 정보 객체를 리턴한다.
  1531. * @returns {Object} Silverlight 정보 객체. <br>
  1532. * object.installed은 실버라이트 플레이어 설치 여부를 boolean 값으로 가지고 object.version은 실버라이트 플레이어의 버전을 가진다. 플레이어의 버전을 탐지하지 못하면 object.version의 값은 -1 된다.
  1533. * @example
  1534. var oSilver = $Agent.silverlight();
  1535. oSilver.installed // Silverlight 플레이어를 설치했다면 true
  1536. oSilver.version // Silverlight 플레이어의 버전.
  1537. */
  1538. jindo.$Agent.prototype.silverlight = function() {
  1539. var info = new Object;
  1540. var p = this._navigator.plugins;
  1541. var s = null;
  1542. info.installed = false;
  1543. info.version = -1;
  1544. if (typeof p != "undefined" && p.length) {
  1545. s = p["Silverlight Plug-In"];
  1546. if (s) {
  1547. info.installed = true;
  1548. info.version = parseInt(s.description.split(".")[0],10);
  1549. if (s.description == "1.0.30226.2") info.version = 2;
  1550. }
  1551. } else {
  1552. try {
  1553. s = new ActiveXObject("AgControl.AgControl");
  1554. info.installed = true;
  1555. if(s.isVersionSupported("3.0")){
  1556. info.version = 3;
  1557. }else if (s.isVersionSupported("2.0")) {
  1558. info.version = 2;
  1559. } else if (s.isVersionSupported("1.0")) {
  1560. info.version = 1;
  1561. }
  1562. } catch(e) {}
  1563. }
  1564. this.silverlight = function() {
  1565. return info;
  1566. };
  1567. return info;
  1568. };
  1569. /**
  1570. * @fileOverview $A의 생성자 메서드를 정의한 파일
  1571. * @name array.js
  1572. */
  1573. /**
  1574. * $A 객체를 생성하여 반환한다.
  1575. * @extends core
  1576. * @class $A 클래스는 배열(Array) 래핑(wrapping)하여 배열을 다루기 위한 여러가지 메서드를 제공한다.<br>
  1577. * 여기서 래핑이란 자바스크립트의 함수를 감싸 본래 함수의 기능에 새로운 확장 속성을 추가하는 것을 말한다.
  1578. * @param {Array|$A} array 배열. 만약 매개 변수를 생략하면 배열을 가진 새로운 $A 객체를 리턴한다.
  1579. * @constructor
  1580. * @description [Lite]
  1581. * @author Kim, Taegon
  1582. *
  1583. * @example
  1584. var zoo = ["zebra", "giraffe", "bear", "monkey"];
  1585. var waZoo = $A(zoo); // ["zebra", "giraffe", "bear", "monkey"]를 래핑한 $A 객체를 생성하여 반환
  1586. */
  1587. jindo.$A = function(array) {
  1588. var cl = arguments.callee;
  1589. if (typeof array == "undefined" || array == null) array = [];
  1590. if (array instanceof cl) return array;
  1591. if (!(this instanceof cl)) return new cl(array);
  1592. this._array = []
  1593. if (array.constructor != String) {
  1594. this._array = [];
  1595. for(var i=0; i < array.length; i++) {
  1596. this._array[this._array.length] = array[i];
  1597. }
  1598. }
  1599. };
  1600. /**
  1601. * toString 메서드는 내부 배열을 문자열로 변환한다. 자바스크립트의 Array.toString 사용한다.
  1602. * @return {String} 내부 배열을 변환한 문자열.
  1603. * @description [Lite]
  1604. *
  1605. * @example
  1606. var zoo = ["zebra", "giraffe", "bear", "monkey"];
  1607. $A(zoo).toString();
  1608. // 결과 : zebra,giraffe,bear,monkey
  1609. */
  1610. jindo.$A.prototype.toString = function() {
  1611. return this._array.toString();
  1612. };
  1613. /**
  1614. * 인덱스로 배열의 원소 값을 조회한다.
  1615. * @param {Number} nIndex 조회할 배열의 인덱스. 인덱스는 0부터 시작한다.
  1616. * @return {Value} 배열에서의 해당 인덱스의 원소 .
  1617. * @description [Lite]
  1618. * @since 1.4.2 부터 지원
  1619. *
  1620. * @example
  1621. var zoo = ["zebra", "giraffe", "bear", "monkey"];
  1622. var waZoo = $A(zoo);
  1623. // 원소 값 조회
  1624. waZoo.get(1); // 결과 : giraffe
  1625. waZoo.get(3); // 결과 : monkey
  1626. */
  1627. jindo.$A.prototype.get = function(nIndex){
  1628. return this._array[nIndex];
  1629. };
  1630. /**
  1631. * 내부 배열의 크기를 지정하거나 리턴한다.
  1632. * @param {Number} [nLen] 지정할 배열의 크기.<br>
  1633. * nLen 기존 배열의 크기보다 크면 oValue 매개 변수의 값을 배열의 마지막에 덧붙인다.<br>
  1634. * nLen 기존 배열의 크기보다 작으면 nLen 번째 이후의 원소는 제거한다.
  1635. * @param {Value} [oValue] 새로운 원소를 추가할 사용할 초기값
  1636. * @return {Number|$A} 매개 변수를 모두 생략하면 현재 내부 배열의 크기를 리턴하고,<br>
  1637. * 매개 변수를 지정한 경우에는 내부 배열을 변경한 $A 객체를 리턴한다.
  1638. *
  1639. * @example
  1640. var zoo = ["zebra", "giraffe", "bear", "monkey"];
  1641. var birds = ["parrot", "sparrow", "dove"];
  1642. // 배열의 크기 조회
  1643. $A(zoo).length(); // 결과 : 4
  1644. // 배열의 크기 지정 (원소가 삭제되는 경우)
  1645. $A(zoo).length(2);
  1646. // 결과 : ["zebra", "giraffe"]
  1647. // 배열의 크기 지정 (원소가 추가되는 경우)
  1648. $A(zoo).length(6, "(Empty)");
  1649. // 결과 : ["zebra", "giraffe", "bear", "monkey", "(Empty)", "(Empty)"]
  1650. $A(zoo).length(5, birds);
  1651. // 결과 : ["zebra", "giraffe", "bear", "monkey", ["parrot", "sparrow", "dove"]]
  1652. */
  1653. jindo.$A.prototype.length = function(nLen, oValue) {
  1654. if (typeof nLen == "number") {
  1655. var l = this._array.length;
  1656. this._array.length = nLen;
  1657. if (typeof oValue != "undefined") {
  1658. for(var i=l; i < nLen; i++) {
  1659. this._array[i] = oValue;
  1660. }
  1661. }
  1662. return this;
  1663. } else {
  1664. return this._array.length;
  1665. }
  1666. };
  1667. /**
  1668. * 배열에서 특정 값을 검색한다.
  1669. * @param {Value} oValue 검색할
  1670. * @return {Boolean} 배열에서 매개 변수의 값과 동일한 원소를 찾으면 true를, 찾지 못하면 false를 리턴한다.
  1671. * @see $A#indexOf
  1672. * @description [Lite]
  1673. *
  1674. * @example
  1675. var arr = $A([1,2,3]);
  1676. // 값 검색
  1677. arr.has(3); // 결과 : true
  1678. arr.has(4); // 결과 : false
  1679. */
  1680. jindo.$A.prototype.has = function(oValue) {
  1681. return (this.indexOf(oValue) > -1);
  1682. };
  1683. /**
  1684. * 배열에서 특정 값을 검색하고 검색한 원소의 인덱스를 리턴한다.
  1685. * @param {Value} oValue 검색할
  1686. * @return {Number} 찾은 원소의 인덱스. 인덱스는 0 부터 시작한다. 매개 변수와 동일한 원소를 찾지 못하면 -1 리턴한다.
  1687. * @see $A#has
  1688. * @description [Lite]
  1689. *
  1690. * @example
  1691. var zoo = ["zebra", "giraffe", "bear"];
  1692. va r waZoo = $A(zoo);
  1693. // 값 검색 후 인덱스 리턴
  1694. waZoo.indexOf("giraffe"); // 1
  1695. waZoo.indexOf("monkey"); // -1
  1696. */
  1697. jindo.$A.prototype.indexOf = function(oValue) {
  1698. if (typeof this._array.indexOf != 'undefined') {
  1699. jindo.$A.prototype.indexOf = function(oValue) {
  1700. return this._array.indexOf(oValue);
  1701. }
  1702. }else{
  1703. jindo.$A.prototype.indexOf = function(oValue) {
  1704. for(var i=0; i < this._array.length; i++) {
  1705. if (this._array[i] == oValue) return i;
  1706. }
  1707. return -1;
  1708. }
  1709. }
  1710. return this.indexOf(oValue);
  1711. };
  1712. /**
  1713. * 내부의 원본 배열을 리턴한다.
  1714. * @return {Array} 배열
  1715. * @description [Lite]
  1716. *
  1717. * @example
  1718. var waNum = $A([1, 2, 3]);
  1719. waNum.$value(); // 원래의 배열인 [1, 2, 3]이 반환된다
  1720. */
  1721. jindo.$A.prototype.$value = function() {
  1722. return this._array;
  1723. };
  1724. /**
  1725. * 내부 배열에 하나 이상의 원소를 추가한다.
  1726. * @param {oValue1, ..., oValueN} oValueN 추가할 N 개의
  1727. * @return {Number} 하나 이상의 원소를 추가한 내부 배열의 크기
  1728. * @description [Lite]
  1729. *
  1730. * @example
  1731. var arr = $A([1,2,3]);
  1732. // 원소 추가
  1733. arr.push(4); // 결과 : 4 반환, 내부 배열은 [1,2,3,4]로 변경 됨
  1734. arr.push(5,6); // 결과 : 6 반환, 내부 배열은 [1,2,3,4,5,6]로 변경 됨
  1735. */
  1736. jindo.$A.prototype.push = function(oValue1/*, ...*/) {
  1737. return this._array.push.apply(this._array, Array.prototype.slice.apply(arguments));
  1738. };
  1739. /**
  1740. * 내부 배열의 마지막 원소를 삭제한다.
  1741. * @return {Value} 삭제한 원소
  1742. * @description [Lite]
  1743. *
  1744. * @example
  1745. var arr = $A([1,2,3,4,5]);
  1746. arr.pop(); // 결과 : 5 반환, 내부 배열은 [1,2,3,4]로 변경 됨
  1747. */
  1748. jindo.$A.prototype.pop = function() {
  1749. return this._array.pop();
  1750. };
  1751. /**
  1752. * 내부 배열의 모든 원소를 앞으로 칸씩 이동한다. 내부 배열의 번째 원소는 삭제된다.
  1753. * @return {Value} 삭제한 번째 원소.
  1754. * @see $A#pop
  1755. * @see $A#unshift
  1756. * @description [Lite]
  1757. * @example
  1758. var arr = $A(['Melon','Grape','Apple','Kiwi']);
  1759. arr.shift(); // 결과 : 'Melon' 반환, 내부 배열은 ["Grape", "Apple", "Kiwi"]로 변경 됨.
  1760. */
  1761. jindo.$A.prototype.shift = function() {
  1762. return this._array.shift();
  1763. };
  1764. /**
  1765. * 내부 배열의 앞에 하나 이상의 원소를 삽입한다.
  1766. * @param {oValue1, ..., oValueN} oValueN 삽입할 하나 이상의
  1767. * @return {Number} 원소를 추가한 후의 배열의 크기
  1768. * @description [Lite]
  1769. * @example
  1770. var arr = $A([4,5]);
  1771. arr.unshift('c'); // 결과 : 3 반환, 내부 배열은 ["c", 4, 5]로 변경 됨.
  1772. arr.unshift('a', 'b'); // 결과 : 5 반환, 내부 배열은 ["a", "b", "c", 4, 5]로 변경 됨.
  1773. */
  1774. jindo.$A.prototype.unshift = function(oValue1/*, ...*/) {
  1775. this._array.unshift.apply(this._array, Array.prototype.slice.apply(arguments));
  1776. return this._array.length;
  1777. };
  1778. /**
  1779. * 내부 배열의 모든 원소를 순회하면서 콜백 함수를 실행한다.
  1780. *
  1781. * @param {Function} fCallback 순회하면서 실행할 콜백 함수.<br>
  1782. * <br>
  1783. * 콜백 함수는 fCallback(value, index, array) 형식을 가진다. <br>
  1784. * value 배열이 가진 원소의 값을 가지고,<br>
  1785. * index 해당 원소의 인덱스를 가지고,<br>
  1786. * array 배열 자체를 가리킨다.
  1787. * @param {Object} [oThis] 콜백 함수가 객체의 메서드일 콜백 함수 내부에서 사용할 this
  1788. * @return {$A} $A 객체
  1789. * @import core.$A[Break, Continue]
  1790. * @see $A#map
  1791. * @see $A#filter
  1792. * @description [Lite]
  1793. *
  1794. * @example
  1795. var waZoo = $A(["zebra", "giraffe", "bear", "monkey"]);
  1796. waZoo.forEach(function(value, index, array) {
  1797. document.writeln((index+1) + ". " + value);
  1798. });
  1799. // 결과 :
  1800. // 1. zebra
  1801. // 2. giraffe
  1802. // 3. bear
  1803. // 4. monkey
  1804. * @example
  1805. var waArray = $A([1, 2, 3]);
  1806. waArray.forEach(function(value, index, array) {
  1807. array[index] += 10;
  1808. });
  1809. document.write(waArray.$value());
  1810. // 결과 : 11, 12, 13 (내부 배열에 10씩 더해짐)
  1811. */
  1812. jindo.$A.prototype.forEach = function(fCallback, oThis) {
  1813. if (typeof this._array.forEach == "function") {
  1814. jindo.$A.prototype.forEach = function(fCallback, oThis) {
  1815. var arr = this._array;
  1816. var errBreak = this.constructor.Break;
  1817. var errContinue = this.constructor.Continue;
  1818. function f(v,i,a) {
  1819. try {
  1820. fCallback.call(oThis, v, i, a);
  1821. } catch(e) {
  1822. if (!(e instanceof errContinue)) throw e;
  1823. }
  1824. };
  1825. try {
  1826. this._array.forEach(f);
  1827. } catch(e) {
  1828. if (!(e instanceof errBreak)) throw e;
  1829. }
  1830. return this;
  1831. }
  1832. }else{
  1833. jindo.$A.prototype.forEach = function(fCallback, oThis) {
  1834. var arr = this._array;
  1835. var errBreak = this.constructor.Break;
  1836. var errContinue = this.constructor.Continue;
  1837. function f(v,i,a) {
  1838. try {
  1839. fCallback.call(oThis, v, i, a);
  1840. } catch(e) {
  1841. if (!(e instanceof errContinue)) throw e;
  1842. }
  1843. };
  1844. for(var i=0; i < arr.length; i++) {
  1845. try {
  1846. f(arr[i], i, arr);
  1847. } catch(e) {
  1848. if (e instanceof errBreak) break;
  1849. throw e;
  1850. }
  1851. }
  1852. return this;
  1853. }
  1854. }
  1855. return this.forEach(fCallback, oThis);
  1856. };
  1857. /**
  1858. * 배열의 일부를 추출한다.
  1859. * @param {Number} nStart 잘라낼 부분의 시작 인덱스. 인덱스는 0부터 시작한다.
  1860. * @param {Number} nEnd 잘라낼 부분의 바로 인덱스
  1861. * @return {$A} 내부 배열의 일부를 추출한 새로운 $A 객체.<br>
  1862. * nStart 값이 0 보다 작거나 혹은 nStart 값이 nEnd 보다 크거나 같으면 배열을 가지는 $A 객체를 리턴한다.
  1863. * @description [Lite]
  1864. *
  1865. * @example
  1866. var arr = $A([12, 5, 8, 130, 44]);
  1867. var newArr = arr.slice(1,3);
  1868. // 잘라낸 배열인 [5, 8]를 래핑한 $A 객체를 리턴한다. (원래의 배열은 변화 없음)
  1869. * @example
  1870. var arr = $A([12, 5, 8, 130, 44]);
  1871. var newArr = arr.slice(3,3);
  1872. // []를 래핑한 $A 객체를 리턴한다.
  1873. */
  1874. jindo.$A.prototype.slice = function(nStart, nEnd) {
  1875. var a = this._array.slice.call(this._array, nStart, nEnd);
  1876. return jindo.$A(a);
  1877. };
  1878. /**
  1879. * 배열의 일부를 삭제한다.
  1880. * @param {Number} nIndex 삭제할 부분의 시작 인덱스. 인덱스는 0부터 시작한다.
  1881. * @param {Number} [nHowMany] 삭제할 원소의 개수.<br>
  1882. * 값과 oValueN 생략하면 nIndex 번째 원소부터 배열의 마지막 원소까지 삭제한다.<br>
  1883. * 값을 0 혹은 지정하지 않고 oValueN 값을 지정하면 nIndex 번째 위치에 oValueN 값이 추가된다.
  1884. * @param {Value1, ...,ValueN} [oValueN] 삭제한 배열에 추가할 하나 이상의 . nIndex 값의 인덱스부터 추가된다.
  1885. * @returns {$A} 삭제한 원소를 래핑하는 새로운 $A 객체
  1886. * @description [Lite]
  1887. *
  1888. * @example
  1889. var arr = $A(["angel", "clown", "mandarin", "surgeon"]);
  1890. var removed = arr.splice(2, 0, "drum");
  1891. // arr의 내부 배열은 ["angel", "clown", "drum", "mandarin", "surgeon"]로 인덱스 2에 drum이 추가 됨
  1892. // removed의 내부 배열은 []로 삭제된 원소가 없음
  1893. removed = arr.splice(3, 1);
  1894. // arr의 내부 배열은 ["angel", "clown", "drum", "surgeon"]로 mandarin이 삭제 됨
  1895. // removed의 내부 배열은 삭제된 원소 ["mandarin"]를 가짐
  1896. removed = arr.splice(2, 1, "trumpet", "parrot");
  1897. // arr의 내부 배열은 ["angel", "clown", "trumpet", "parrot", "surgeon"]로 drum이 삭제되고 새로운 원소가 추가 됨
  1898. // removed의 내부 배열은 삭제된 원소 ["drum"]을 가짐
  1899. removed = arr.splice(3);
  1900. // arr의 내부 배열은 ["angel", "clown", "trumpet"]로 인덱스 3부터 마지막 원소가 삭제되었음
  1901. // removed의 내부 배열은 삭제된 원소 ["parrot", "surgeon"]을 가짐
  1902. */
  1903. jindo.$A.prototype.splice = function(nIndex, nHowMany/*, oValue1,...*/) {
  1904. var a = this._array.splice.apply(this._array, Array.prototype.slice.apply(arguments));
  1905. return jindo.$A(a);
  1906. };
  1907. /**
  1908. * 배열의 원소를 무작위로 섞는다.
  1909. * @return {$A} 배열이 섞여진 $A 객체
  1910. * @description [Lite]
  1911. *
  1912. * @example
  1913. var dice = $A([1,2,3,4,5,6]);
  1914. dice.shuffle();
  1915. document.write("You get the number " + dice.get(0));
  1916. // 결과 : 1부터 6까지의 숫자 중 랜덤한 숫자
  1917. */
  1918. jindo.$A.prototype.shuffle = function() {
  1919. this._array.sort(function(a,b){ return Math.random()>Math.random()?1:-1 });
  1920. return this;
  1921. };
  1922. /**
  1923. * 배열 원소의 순서를 거꾸로 뒤집는다.
  1924. * @return {$A} 원소 순서를 뒤집은 $A 객체
  1925. * @description [Lite]
  1926. *
  1927. * @example
  1928. var arr = $A([1, 2, 3, 4, 5]);
  1929. arr.reverse(); // 결과 : [5, 4, 3, 2, 1]
  1930. */
  1931. jindo.$A.prototype.reverse = function() {
  1932. this._array.reverse();
  1933. return this;
  1934. };
  1935. /**
  1936. * 배열의 모든 원소를 제거하고, 배열로 만든다.
  1937. * @return {$A} 배열의 원소가 제거된 $A 객체
  1938. * @description [Lite]
  1939. *
  1940. * @example
  1941. var arr = $A([1, 2, 3]);
  1942. arr.empty(); // 결과 : []
  1943. */
  1944. jindo.$A.prototype.empty = function() {
  1945. return this.length(0);
  1946. };
  1947. /**
  1948. * Break 메서드는 forEach, filter, map 메서드의 순회 루프를 중단한다.
  1949. * @remark 내부적으로는 강제로 예외를 발생시키는 구조이므로, try ~ catch 영역에서 메소드를 실행하면 정상적으로 동작하지 않을 있다.
  1950. *
  1951. * @description [Lite]
  1952. * @see $A#Continue
  1953. * @see $A#forEach
  1954. * @see $A#filter
  1955. * @see $A#map
  1956. * @example
  1957. $A([1,2,3,4,5]).forEach(function(value,index,array) {
  1958. // 값이 4보다 크면 종료
  1959. if (value > 4) $A.Break();
  1960. ...
  1961. });
  1962. */
  1963. jindo.$A.Break = function() {
  1964. if (!(this instanceof arguments.callee)) throw new arguments.callee;
  1965. };
  1966. /**
  1967. * Continue 메서드는 forEach, filter, map 메서드의 순회 루프에서 나머지 명령을 실행하지 않고 다음 루프로 건너뛴다.
  1968. * @remark 내부적으로는 강제로 예외를 발생시키는 구조이므로, try ~ catch 영역에서 메소드를 실행하면 정상적으로 동작하지 않을 있다.
  1969. *
  1970. * @description [Lite]
  1971. * @see $A#Break
  1972. * @see $A#forEach
  1973. * @see $A#filter
  1974. * @see $A#map
  1975. * @example
  1976. $A([1,2,3,4,5]).forEach(function(value,index,array) {
  1977. // 값이 짝수면 처리를 하지 않음
  1978. if (value%2 == 0) $A.Continue();
  1979. ...
  1980. });
  1981. */
  1982. jindo.$A.Continue = function() {
  1983. if (!(this instanceof arguments.callee)) throw new arguments.callee;
  1984. };
  1985. /**
  1986. * @fileOverview $A의 확장 메서드를 정의한 파일
  1987. * @name array.extend.js
  1988. */
  1989. /**
  1990. * 배열의 모든 원소를 순회하면서 콜백 함수를 실행한다.<br>
  1991. * 콜백 함수의 실행 결과를 배열의 원소에 설정한다.
  1992. *
  1993. * @param {Function} fCallback 순회하면서 실행할 콜백 함수.<br>
  1994. * <br>
  1995. * 콜백 함수는 fCallback(value, index, array) 형식을 가진다. <br>
  1996. * value 배열이 가진 원소의 값을 가지고,<br>
  1997. * index 해당 원소의 인덱스를 가지고,<br>
  1998. * array 배열 자체를 가리킨다.<br>
  1999. * <br>
  2000. * 콜백 함수에서 리턴하는 값을 원소의 값으로 설정한다.
  2001. *
  2002. * @param {Object} [oThis] 콜백 함수가 객체의 메서드일 콜백 함수 내부에서 사용할 this
  2003. * @return {$A} 콜백 함수의 수행 결과를 반영한 $A 객체
  2004. * @see $A#forEach
  2005. * @see $A#filter
  2006. *
  2007. * @example
  2008. var waZoo = $A(["zebra", "giraffe", "bear", "monkey"]);
  2009. waZoo.map(function(value, index, array) {
  2010. return (index+1) + ". " + value;
  2011. });
  2012. // 결과 : [1. zebra, 2. giraffe, 3. bear, 4. monkey]
  2013. * @example
  2014. var waArray = $A([1, 2, 3]);
  2015. waArray.map(function(value, index, array) {
  2016. return value + 10;
  2017. });
  2018. document.write(waArray.$value());
  2019. // 결과 : 11, 12, 13 (내부 배열에 10씩 더해짐)
  2020. */
  2021. jindo.$A.prototype.map = function(fCallback, oThis) {
  2022. if (typeof this._array.map == "function") {
  2023. jindo.$A.prototype.map = function(fCallback, oThis) {
  2024. var arr = this._array;
  2025. var errBreak = this.constructor.Break;
  2026. var errContinue = this.constructor.Continue;
  2027. function f(v,i,a) {
  2028. try {
  2029. return fCallback.call(oThis, v, i, a);
  2030. } catch(e) {
  2031. if (e instanceof errContinue){
  2032. return v;
  2033. } else{
  2034. throw e;
  2035. }
  2036. }
  2037. };
  2038. try {
  2039. this._array = this._array.map(f);
  2040. } catch(e) {
  2041. if(!(e instanceof errBreak)) throw e;
  2042. }
  2043. return this;
  2044. }
  2045. }else{
  2046. jindo.$A.prototype.map = function(fCallback, oThis) {
  2047. var arr = this._array;
  2048. var returnArr = [];
  2049. var errBreak = this.constructor.Break;
  2050. var errContinue = this.constructor.Continue;
  2051. function f(v,i,a) {
  2052. try {
  2053. return fCallback.call(oThis, v, i, a);
  2054. } catch(e) {
  2055. if (e instanceof errContinue){
  2056. return v;
  2057. } else{
  2058. throw e;
  2059. }
  2060. }
  2061. };
  2062. for(var i=0; i < this._array.length; i++) {
  2063. try {
  2064. returnArr[i] = f(arr[i], i, arr);
  2065. } catch(e) {
  2066. if (e instanceof errBreak){
  2067. return this;
  2068. }else{
  2069. throw e;
  2070. }
  2071. }
  2072. }
  2073. this._array = returnArr;
  2074. return this;
  2075. }
  2076. }
  2077. return this.map(fCallback, oThis);
  2078. };
  2079. /**
  2080. * 배열의 모든 원소를 순회하면서 콜백 함수를 실행한다. 실행이 끝나면 filter 메서드는 콜박 함수를 만족하는 원소로 이루어진 새로운 $A 객체를 반환한다.
  2081. * @param {Function} fCallback 순회하면서 실행할 콜백 함수.<br>
  2082. * <br>
  2083. * 콜백 함수는 fCallback(value, index, array) 형식으로 작성해야 한다. 여기서
  2084. * value 배열이 가진 원소의 , index 해당 원소의 인덱스, array 원본 배열이다.<br>
  2085. * <br>
  2086. * 콜백 함수는 Boolean 리턴해야한다. 만약 리턴 값이 true 원소는 새로운 배열의 원소가 된다.
  2087. *
  2088. * @param {Object} oThis 콜백 함수가 객체의 메서드일 콜백 함수 내부에서 사용할 this
  2089. * @return {$A} 콜백 함수의 리턴 값이 true 원소로 이루어진 새로운 $A 객체
  2090. * @see $A#forEach
  2091. * @see $A#map
  2092. *
  2093. * @example
  2094. var arr = $A([1,2,3,4,5]);
  2095. // 필터링 함수
  2096. function filterFunc(value, index, array) {
  2097. if (value > 2) {
  2098. return true;
  2099. } else {
  2100. return false;
  2101. }
  2102. }
  2103. var newArr = arr.filter(filterFunc);
  2104. document.write(arr.$value()); // 결과 : [1,2,3,4,5]
  2105. document.write(newArr.$value()); // 결과 : [3,4,5]
  2106. */
  2107. jindo.$A.prototype.filter = function(fCallback, oThis) {
  2108. if (typeof this._array.filter != "undefined") {
  2109. jindo.$A.prototype.filter = function(fCallback, oThis) {
  2110. return jindo.$A(this._array.filter(fCallback, oThis));
  2111. }
  2112. }else{
  2113. jindo.$A.prototype.filter = function(fCallback, oThis) {
  2114. var ar = [];
  2115. this.forEach(function(v,i,a) {
  2116. if (fCallback.call(oThis, v, i, a) === true) {
  2117. ar[ar.length] = v;
  2118. }
  2119. });
  2120. return jindo.$A(ar);
  2121. }
  2122. }
  2123. return this.filter(fCallback, oThis);
  2124. };
  2125. /**
  2126. * 배열의 모든 원소를 순회하면서 콜백 함수를 실행한다. 동시에 배열의 모든 원소가 콜백 함수를 만족하는지(콜백 함수가 true를 리턴하는지) 검사한다. <br>
  2127. * 만약 모든 원소가 콜백 함수를 만족하면 every 메서드는 true를 리턴한다.
  2128. *
  2129. * @param {Function} fCallback 순회하면서 실행할 콜백 함수.<br>
  2130. * <br>
  2131. * 콜백 함수는 fCallback(value, index, array) 형식으로 작성해야 한다. 여기서
  2132. * value 배열이 가진 원소의 , index 해당 원소의 인덱스, array 원본 배열이다.<br>
  2133. * <br>
  2134. * 콜백 함수는 Boolean 리턴해야한다.<br>
  2135. *
  2136. * @param {Object} oThis 콜백 함수가 객체의 메서드일 콜백 함수 내부에서 사용할 this
  2137. * @return {Boolean} 콜백 함수의 리턴 값이 모두 true 이면 true , 그렇지 않으면 false 리턴한다.
  2138. * @see $A#some
  2139. *
  2140. * @example
  2141. function isBigEnough(value, index, array) {
  2142. return (value >= 10);
  2143. }
  2144. var try1 = $A([12, 5, 8, 130, 44]).every(isBigEnough); // 결과 : false
  2145. var try2 = $A([12, 54, 18, 130, 44]).every(isBigEnough); // 결과 : true
  2146. */
  2147. jindo.$A.prototype.every = function(fCallback, oThis) {
  2148. if (typeof this._array.every != "undefined"){
  2149. jindo.$A.prototype.every = function(fCallback, oThis) {
  2150. return this._array.every(fCallback, oThis);
  2151. }
  2152. }else{
  2153. jindo.$A.prototype.every = function(fCallback, oThis) {
  2154. var result = true;
  2155. this.forEach(function(v, i, a) {
  2156. if (fCallback.call(oThis, v, i, a) === false) {
  2157. result = false;
  2158. jindo.$A.Break();
  2159. }
  2160. });
  2161. return result;
  2162. }
  2163. }
  2164. return this.every(fCallback, oThis);
  2165. };
  2166. /**
  2167. * 배열의 모든 원소를 순회하면서 콜백 함수를 실행한다.<br>
  2168. * 콜백 함수를 만족하는 원소가 있는지 검사한다.
  2169. *
  2170. * @param {Function} fCallback 순회하면서 실행할 콜백 함수.<br>
  2171. * <br>
  2172. * 콜백 함수는 fCallback(value, index, array) 형식으로 작성해야 한다. 여기서
  2173. * value 배열이 가진 원소, index 해당 원소의 인덱스, array 원본 배열이다.<br>
  2174. * <br>
  2175. * 콜백 함수는 Boolean 리턴해야한다.<br>
  2176. *
  2177. * @param {Object} oThis 콜백 함수가 객체의 메서드일 콜백 함수 내부에서 사용할 this
  2178. * @return {Boolean} 콜백 함수의 리턴 값이 true 원소가 있으면 true , 하나도 없으면 false 리턴한다.
  2179. * @see $A#every
  2180. *
  2181. * @example
  2182. function twoDigitNumber(value, index, array) {
  2183. return (value >= 10 && value < 100);
  2184. }
  2185. var try1 = $A([12, 5, 8, 130, 44]).some(twoDigitNumber); // 결과 : true
  2186. var try2 = $A([1, 5, 8, 130, 4]).some(twoDigitNumber); // 결과 : false
  2187. */
  2188. jindo.$A.prototype.some = function(fCallback, oThis) {
  2189. if (typeof this._array.some != "undefined"){
  2190. jindo.$A.prototype.some = function(fCallback, oThis) {
  2191. return this._array.some(fCallback, oThis);
  2192. }
  2193. }else{
  2194. jindo.$A.prototype.some = function(fCallback, oThis) {
  2195. var result = false;
  2196. this.forEach(function(v, i, a) {
  2197. if (fCallback.call(oThis, v, i, a) === true) {
  2198. result = true;
  2199. jindo.$A.Break();
  2200. }
  2201. });
  2202. return result;
  2203. }
  2204. }
  2205. return this.some(fCallback, oThis);
  2206. };
  2207. /**
  2208. * 배열에서 매개 변수와 같은 값을 제외하여 새로운 $A 객체를 만든다.
  2209. *
  2210. * @param {Value, ..., ValueN} oValueN 배열에서 제외할
  2211. * @return {$A} 배열에서 특정 값을 제외한 새로운 $A 객체
  2212. *
  2213. * @example
  2214. var arr = $A([12, 5, 8, 130, 44]);
  2215. var newArr1 = arr.refuse(12);
  2216. document.write(arr); // 결과 : [12, 5, 8, 130, 44]
  2217. document.write(newArr1); // 결과 : [5, 8, 130, 44]
  2218. var newArr2 = newArr1.refuse(8, 44, 130);
  2219. document.write(newArr1); // 결과 : [5, 8, 130, 44]
  2220. document.write(newArr2); // 결과 : [5]
  2221. */
  2222. jindo.$A.prototype.refuse = function(oValue1/*, ...*/) {
  2223. var a = jindo.$A(Array.prototype.slice.apply(arguments));
  2224. return this.filter(function(v,i) { return !a.has(v) });
  2225. };
  2226. /**
  2227. * 배열에서 중복되는 원소를 삭제한다.
  2228. *
  2229. * @return {$A} 중복되는 원소를 제거한 $A 객체
  2230. *
  2231. * @example
  2232. var arr = $A([10, 3, 76, 5, 4, 3]);
  2233. arr.unique(); // 결과 : [10, 3, 76, 5, 4]
  2234. */
  2235. jindo.$A.prototype.unique = function() {
  2236. var a = this._array, b = [], l = a.length;
  2237. var i, j;
  2238. /*
  2239. 중복되는 원소 제거
  2240. */
  2241. for(i = 0; i < l; i++) {
  2242. for(j = 0; j < b.length; j++) {
  2243. if (a[i] == b[j]) break;
  2244. }
  2245. if (j >= b.length) b[j] = a[i];
  2246. }
  2247. this._array = b;
  2248. return this;
  2249. };
  2250. /**
  2251. * @fileOverview $Ajax의 생성자 메서드를 정의한 파일
  2252. * @name Ajax.js
  2253. */
  2254. /**
  2255. * $Ajax는 서버와 브라우저 사이의 비동기 통신, Ajax 통신을 지원한다. $Ajax는 XHR(XMLHTTPRequest) 사용한 기본적인 방식과 함께 다른 호스트(Host) 사이의 통신을 위한 여러 방식을 제공한다.
  2256. * $Ajax 객체의 기본적인 초기화 방식은 다음과 같다.
  2257. * <textarea name="code" class="js:nocontrols">
  2258. * var oAjax = new $Ajax('server.php', {
  2259. type : 'xhr',
  2260. method : 'get', // GET 방식으로 통신
  2261. onload : function(res){ // 요청이 완료되면 실행될 콜백 함수
  2262. $('list').innerHTML = res.text();
  2263. },
  2264. timeout : 3, // 3초 이내에 요청이 완료되지 않으면 ontimeout 실행 (생략 시 0)
  2265. ontimeout : function(){ // 타임 아웃이 발생하면 실행될 콜백 함수, 생략 시 타임 아웃이 되면 아무 처리도 하지 않음
  2266. alert("Timeout!");
  2267. },
  2268. async : true // 비동기로 호출하는 경우, 생략하면 true
  2269. });
  2270. oAjax.request();
  2271. }
  2272. * </textarea>
  2273. *
  2274. * @extends core
  2275. * @class $Ajax 클래스는 다양한 개발 환경에서 Ajax 요청과 응답을 쉽게 구현하기 위한 메서드를 제공한다.<br>
  2276. *
  2277. * $Ajax를 초기화할 사용하는 매개 변수는 다음과 같다.
  2278. *
  2279. * @param {String} url Ajax 요청을 보낼 서버 URL.<br>
  2280. * @param {Object} option $Ajax 에서 사용하는 콜백 함수, 통신 방식 등과 같은 다양한 정보를 정의한다.<br>
  2281. * <br>
  2282. * option 객체의 프로퍼티와 사용법은 아래에서 설명한다.<br>
  2283. <table>
  2284. <thead style="background-color:#D2E0E6;">
  2285. <th>프로퍼티 </th>
  2286. <th>타입</th>
  2287. <th>설명</th>
  2288. </thead>
  2289. <tbody>
  2290. <tr>
  2291. <td style="font-weight:bold;">type</td>
  2292. <td>String</td>
  2293. <td>
  2294. Ajax 구현 방식. 생략 기본 값은 "xhr"
  2295. <ul>
  2296. <li><strong>xhr</strong>
  2297. 브라우저에 내장된 XMLHttpRequest 객체를 이용하여 Ajax 요청을 처리한다.<br>
  2298. 응답으로는 text, xml, json 방식 모두 사용이 가능하며, 요청 실패 HTTP 응답코드를 통해 원인 파악이 가능하다.<br>
  2299. , Cross-Domain 에서는 사용할 없다.
  2300. </li>
  2301. <li><strong>iframe</strong>
  2302. iframe 프록시로 사용하여 Ajax 요청을 처리한다. Cross-Domain 에서 사용한다.<br>
  2303. 로컬(요청 하는 ) 원격(요청 받는 ) 모두 프록시용 HTML 파일을 만들어<br>
  2304. iframe 에서 원격 프록시에 요청하면, 원격 프록시에서 원격 도메인의 페이지에 XHR Ajax 요청을 한다.<br>
  2305. 응답을 받은 원격 프록시에서 로컬 프록시로 응답을 전달하면 로컬 프록시에서 최종적으로 콜백 함수(onload) 호출하여 처리된다.<br>
  2306. <ul type="disc">
  2307. <li>원격 프록시 파일 : ajax_remote_callback.html</li>
  2308. <li>로컬 프록시 파일 : ajax_local_callback.html</li>
  2309. </ul>
  2310. IE 에서는 "딱.딱." 하는 페이지 이동음이 들릴 수도 있다 (요청당 2).
  2311. </li>
  2312. <li><strong>jsonp</strong>
  2313. JSON &lt;script&gt; 태그를 사용하여 사용하여 Ajax 요청을 처리한다. Cross-Domain 에서 사용한다.<br>
  2314. &lt;script&gt; 태그를 동적으로 생성하여, 요청할 원격 페이지를 스크립트에 삽입하여 GET 방식으로 요청을 전송한다.<br>
  2315. 요청 시에 콜백 함수를 매개 변수로 넘기면, 원격 페이지에서 전달받은 콜백 함수명으로 아래와 같이 응답을 보낸다.<br>
  2316. <ul type="disc"><li>function_name(...결과 ...)</li></ul>
  2317. 응답은 콜백 함수(onload)에서 처리된다.<br>
  2318. GET 방식만 가능하므로, 전송 데이터 길이는 URL 허용하는 길이로 제한된다.
  2319. </li>
  2320. <li><strong>flash</strong>
  2321. 플래시 객체를 사용하여 Ajax 요청을 처리한다. Cross-Domain 에서 사용한다.<br>
  2322. 서버의 루트에 crossdomain.xml 존재해야 하며 접근 권한을 설정해야 사용할 있다.<br>
  2323. 모든 통신은 플래시 객체를 통하여 주고 받으며 Ajax 호출을 하기 전에 반드시 플래시 객체를 초기화해야 한다.<br>
  2324. $Ajax.SWFRequest.write 메서드 사용하여 초기화하며 해당 메서드는 &lt;body&gt; 태그 내에 작성한다.
  2325. </li>
  2326. <li><strong>get/post/put/delete</strong> : xhr .</li>
  2327. </ul>
  2328. </td>
  2329. </tr>
  2330. <tr>
  2331. <td style="font-weight:bold;">method</td>
  2332. <td>String</td>
  2333. <td>
  2334. HTTP 통신 방법
  2335. <ul>
  2336. <li><strong>post</strong> : .</li>
  2337. <li><strong>get</strong> : type "jsonp" "get" .</li>
  2338. <li><strong>put</strong> : 1.4.2 </li>
  2339. <li><strong>delete</strong> : 1.4.2 </li>
  2340. </ul>
  2341. </td>
  2342. </tr>
  2343. <tr>
  2344. <td style="font-weight:bold;">timeout</td>
  2345. <td>Number</td>
  2346. <td>
  2347. 요청 타임아웃 시간. 생략 0 (단위는 ).<br>
  2348. 타임아웃 시간 내에 요청이 완료되지 않으면 중지시킨다.<br>
  2349. 비동기 호출인 경우에만 사용 가능하다.
  2350. </td>
  2351. </tr>
  2352. <tr>
  2353. <td style="font-weight:bold;">onload</td>
  2354. <td>Function</td>
  2355. <td>
  2356. 요청이 완료되면 실행할 콜백 함수. 반드시 지정해야 한다.<br>
  2357. 매개 변수로 응답 객체인 $Ajax.Response 객체가 전달 된다.
  2358. </td>
  2359. </tr>
  2360. <tr>
  2361. <td style="font-weight:bold;">onerror</td>
  2362. <td>Function</td>
  2363. <td>
  2364. 요청이 실패하면 실행할 콜백 함수.<br>
  2365. 생략하면 에러가 발생해도 onload 실행한다.
  2366. </td>
  2367. </tr>
  2368. <tr>
  2369. <td style="font-weight:bold;">ontimeout</td>
  2370. <td>Function</td>
  2371. <td>
  2372. 타임아웃이 되었을 실행할 콜백 함수.<br>
  2373. 생략하면 타임아웃 발생 후에 아무런 처리를 하지 않는다.
  2374. </td>
  2375. </tr>
  2376. <tr>
  2377. <td style="font-weight:bold;">proxy</td>
  2378. <td>String</td>
  2379. <td>
  2380. 로컬 프록시 파일(ajax_local_callback.html) 경로.<br>
  2381. type "iframe" 사용하며 반드시 지정해야 한다.
  2382. </td>
  2383. </tr>
  2384. <tr>
  2385. <td style="font-weight:bold;">jsonp_charset</td>
  2386. <td>String</td>
  2387. <td>
  2388. 요청 사용할 &lt;script&gt; 인코딩 방식.<br>
  2389. type "jsonp" 사용한다. 생략하면 "utf-8" 기본값이다. (0.4.2 부터 지원)
  2390. </td>
  2391. </tr>
  2392. <tr>
  2393. <td style="font-weight:bold;">callbackid</td>
  2394. <td>String</td>
  2395. <td>
  2396. 콜백 함수 이름에 사용할 아이디 .<br>
  2397. type "jsonp" 사용한다. (1.3.0 부터 지원)<br>
  2398. 생략하면 자동으로 랜덤한 아이디 값을 생성하여 사용한다.
  2399. <br>
  2400. jsonp 방식에서 Ajax 요청 , 콜백 함수 이름에 랜덤한 아이디 값을 덧붙여 만든 콜백 함수 이름을 서버로 전달한다.<br>
  2401. 랜덤한 값을 아이디로 사용하여 넘기므로 요청 URL이 매번 새롭게 생성되어 캐쉬 서버가 아닌 서버로 직접 데이터를 요청하게 된다.<br>
  2402. 아이디 값을 지정하면 랜덤한 아이디 값으로 콜백 함수 이름을 생성하지 않으므로<br>
  2403. 캐쉬 서버를 사용하여 그에 대한 히트율을 높이고자 아이디를 지정하여 사용할 있다.
  2404. </td>
  2405. </tr>
  2406. <tr>
  2407. <td style="font-weight:bold;">callbackname</td>
  2408. <td>String</td>
  2409. <td>
  2410. 콜백 함수 이름을 가지는 매개변수 이름.<br>
  2411. type "jsonp" 사용한다. 기본 값은 "_callback" 이다. (1.3.8 부터 지원)
  2412. </td>
  2413. </tr>
  2414. <tr>
  2415. <td style="font-weight:bold;">sendheader</td>
  2416. <td>Boolean</td>
  2417. <td>
  2418. 요청 헤더를 전송할지 여부.<br>
  2419. type "flash" 사용하며, 서버에서 접근 권한을 설정하는 crossdomain.xml <br>
  2420. allow-header 없는 경우에 false 설정해야 한다.<br>
  2421. 플래시 9에서는 allow-header가 false인 경우 get만 ajax가 되면 post는 ajax가 안된다.<br>
  2422. 플래시 10에서는 allow-header가 false인 경우 get,post 둘다 ajax가 안된다.<br>
  2423. 그래서 allow-header가 설정되어 있지 않다면 반드시 false로 셋팅해야 한다.<br>
  2424. 기본 값은 true 이다. (1.3.4부터 지원)
  2425. </td>
  2426. </tr>
  2427. <tr>
  2428. <td style="font-weight:bold;">async</td>
  2429. <td>Boolean</td>
  2430. <td>
  2431. 비동기 호출 여부.<br>
  2432. type "xhr" 때만 유효하다. 기본 값은 true 이다. (1.3.7부터 지원)
  2433. </td>
  2434. </tr>
  2435. <tr>
  2436. <td style="font-weight:bold;">decode</td>
  2437. <td>Boolean</td>
  2438. <td>
  2439. type "flash" 사용하며, 요청한 데이터 안에 utf-8 아닌 다른 인코딩이 되어 있을때 false 지정한다.<br>
  2440. 기본 값은 true 이다. (1.4.0부터 지원)
  2441. </td>
  2442. </tr>
  2443. <tr>
  2444. <td style="font-weight:bold;">postBody</td>
  2445. <td>Boolean</td>
  2446. <td>
  2447. 요청 서버로 전달할 데이터를 Body 영역에 전달할 지의 여부.<br>
  2448. type "xhr" 이고 method "get" 아니어야 유효하며 REST 환경에서 사용된다.<br>
  2449. 기본값은 false 이다. (1.4.2부터 지원)
  2450. </td>
  2451. </tr>
  2452. </tbody>
  2453. </table>
  2454. * @constructor
  2455. * @description [Lite]
  2456. * @see <a href="http://dev.naver.com/projects/jindo/wiki/cross%20domain%20ajax">Cross Domain Ajax 이해</a>
  2457. * @author Kim, Taegon
  2458. *
  2459. * @example
  2460. // 'Get List' 버튼 클릭 시, 서버에서 데이터를 받아와 리스트를 구성하는 예제
  2461. // (1) 서버 페이지와 서비스 페이지가 같은 도메인에 있는 경우 - xhr
  2462. // [client.html]
  2463. <!DOCTYPE html>
  2464. <html>
  2465. <head>
  2466. <title>Ajax Sample</title>
  2467. <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
  2468. <script type="text/javascript" language="javascript" src="lib/jindo.all.js"></script>
  2469. <script type="text/javascript" language="javascript">
  2470. function getList() {
  2471. var oAjax = new $Ajax('server.php', {
  2472. type : 'xhr',
  2473. method : 'get', // GET 방식으로 통신
  2474. onload : function(res){ // 요청이 완료되면 실행될 콜백 함수
  2475. $('list').innerHTML = res.text();
  2476. },
  2477. timeout : 3, // 3초 이내에 요청이 완료되지 않으면 ontimeout 실행 (생략 시 0)
  2478. ontimeout : function(){ // 타임 아웃이 발생하면 실행될 콜백 함수, 생략 시 타임 아웃이 되면 아무 처리도 하지 않음
  2479. alert("Timeout!");
  2480. },
  2481. async : true // 비동기로 호출하는 경우, 생략하면 true
  2482. });
  2483. oAjax.request();
  2484. }
  2485. </script>
  2486. </head>
  2487. <body>
  2488. <button onclick="getList(); return false;">Get List</button>
  2489. <ul id="list">
  2490. </ul>
  2491. </body>
  2492. </html>
  2493. // [server.php]
  2494. <?php
  2495. echo "<li>첫번째</li><li>두번째</li><li>세번째</li>";
  2496. ?>
  2497. * @example
  2498. // 'Get List' 버튼 클릭 시, 서버에서 데이터를 받아와 리스트를 구성하는 예제
  2499. // (2) 서버 페이지와 서비스 페이지가 같은 도메인에 있는 경우 - iframe
  2500. // [http://local.com/some/client.html]
  2501. <!DOCTYPE html>
  2502. <html>
  2503. <head>
  2504. <title>Ajax Sample</title>
  2505. <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
  2506. <script type="text/javascript" language="javascript" src="lib/jindo.all.js"></script>
  2507. <script type="text/javascript" language="javascript">
  2508. function getList() {
  2509. var oAjax = new $Ajax('http://server.com/some/some.php', {
  2510. type : 'iframe',
  2511. method : 'get', // GET 방식으로 통신
  2512. // POST로 지정하면 원격 프록시 파일에서 some.php 로 요청 시에 POST 방식으로 처리
  2513. onload : function(res){ // 요청이 완료되면 실행될 콜백 함수
  2514. $('list').innerHTML = res.text();
  2515. },
  2516. // 로컬 프록시 파일의 경로.
  2517. // 반드시 정확한 경로를 지정해야 하며, 로컬 도메인의 경로라면 어디에 두어도 상관 없음
  2518. // (※ 원격 프록시 파일은 반드시 원격 도메인 서버의 도메인 루트 상에 두어야 함)
  2519. proxy : 'http://local.naver.com/some/ajax_local_callback.html'
  2520. });
  2521. oAjax.request();
  2522. }
  2523. </script>
  2524. </head>
  2525. <body>
  2526. <button onclick="getList(); return false;">Get List</button>
  2527. <ul id="list">
  2528. </ul>
  2529. </body>
  2530. </html>
  2531. // [http://server.com/some/some.php]
  2532. <?php
  2533. echo "<li>첫번째</li><li>두번째</li><li>세번째</li>";
  2534. ?>
  2535. * @example
  2536. // 'Get List' 버튼 클릭 시, 서버에서 데이터를 받아와 리스트를 구성하는 예제
  2537. // (3) 서버 페이지와 서비스 페이지가 같은 도메인에 있는 경우 - jsonp
  2538. // [http://local.com/some/client.html]
  2539. <!DOCTYPE html>
  2540. <html>
  2541. <head>
  2542. <title>Ajax Sample</title>
  2543. <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
  2544. <script type="text/javascript" language="javascript" src="lib/jindo.all.js"></script>
  2545. <script type="text/javascript" language="javascript">
  2546. function getList(){
  2547. var oAjax = new $Ajax('http://server.com/some/some.php', {
  2548. type: 'jsonp',
  2549. method: 'get', // type 이 jsonp 이면 get 으로 지정하지 않아도 자동으로 get 으로 처리함 (생략가능)
  2550. jsonp_charset: 'utf-8', // 요청 시 사용할 <script> 인코딩 방식 (생략 시 utf-8)
  2551. onload: function(res){ // 요청이 완료되면 실행될 콜백 함수
  2552. var response = res.json();
  2553. var welList = $Element('list').empty();
  2554. for (var i = 0, nLen = response.length; i < nLen; i++) {
  2555. welList.append($("<li>" + response[i] + "</li>"));
  2556. }
  2557. },
  2558. callbackid: '12345', // 콜백 함수 이름에 사용할 아이디 값 (생략가능)
  2559. callbackname: 'ajax_callback_fn' // 서버에서 사용할 콜백 함수이름을 가지는 매개 변수 이름 (생략 시 '_callback')
  2560. });
  2561. oAjax.request();
  2562. }
  2563. </script>
  2564. </head>
  2565. <body>
  2566. <button onclick="getList(); return false;">Get List</button>
  2567. <ul id="list">
  2568. </ul>
  2569. </body>
  2570. </html>
  2571. // [http://server.com/some/some.php]
  2572. <?php
  2573. $callbackName = $_GET['ajax_callback_fn'];
  2574. echo $callbackName."(['첫번째','두번째','세번째'])";
  2575. ?>
  2576. * @example
  2577. // 'Get List' 버튼 클릭 시, 서버에서 데이터를 받아와 리스트를 구성하는 예제
  2578. // (4) 서버 페이지와 서비스 페이지가 같은 도메인에 있는 경우 - flash
  2579. // [http://local.com/some/client.html]
  2580. <!DOCTYPE html>
  2581. <html>
  2582. <head>
  2583. <title>Ajax Sample</title>
  2584. <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
  2585. <script type="text/javascript" language="javascript" src="lib/jindo.all.js"></script>
  2586. <script type="text/javascript" language="javascript">
  2587. function getList(){
  2588. var oAjax = new $Ajax('http://server.com/some/some.php', {
  2589. type : 'flash',
  2590. method : 'get', // GET 방식으로 통신
  2591. sendheader : false, // 요청 헤더를 전송할지 여부. (생략 시 true)
  2592. decode : true, // 요청한 데이터 안에 utf-8 이 아닌 다른 인코딩이 되어 있을때 false. (생략 시 true)
  2593. onload : function(res){ // 요청이 완료되면 실행될 콜백 함수
  2594. $('list').innerHTML = res.text();
  2595. },
  2596. });
  2597. oAjax.request();
  2598. }
  2599. </script>
  2600. </head>
  2601. <body>
  2602. <script type="text/javascript">
  2603. $Ajax.SWFRequest.write("swf/ajax.swf"); // Ajax 호출을 하기 전에 반드시 플래시 객체를 초기화
  2604. </script>
  2605. <button onclick="getList(); return false;">Get List</button>
  2606. <ul id="list">
  2607. </ul>
  2608. </body>
  2609. </html>
  2610. // [http://server.com/some/some.php]
  2611. <?php
  2612. echo "<li>첫번째</li><li>두번째</li><li>세번째</li>";
  2613. ?>
  2614. */
  2615. jindo.$Ajax = function (url, option) {
  2616. var cl = arguments.callee;
  2617. if (!(this instanceof cl)) return new cl(url, option);
  2618. function _getXHR() {
  2619. if (window.XMLHttpRequest) {
  2620. return new XMLHttpRequest();
  2621. } else if (ActiveXObject) {
  2622. try {
  2623. return new ActiveXObject('MSXML2.XMLHTTP');
  2624. }catch(e) {
  2625. return new ActiveXObject('Microsoft.XMLHTTP');
  2626. }
  2627. return null;
  2628. }
  2629. }
  2630. var loc = location.toString();
  2631. var domain = '';
  2632. try { domain = loc.match(/^https?:\/\/([a-z0-9_\-\.]+)/i)[1]; } catch(e) {}
  2633. this._status = 0;
  2634. this._url = url;
  2635. this._options = new Object;
  2636. this._headers = new Object;
  2637. this._options = {
  2638. type :"xhr",
  2639. method :"post",
  2640. proxy :"",
  2641. timeout:0,
  2642. onload :function(req){},
  2643. onerror :null,
  2644. ontimeout:function(req){},
  2645. jsonp_charset : "utf-8",
  2646. callbackid : "",
  2647. callbackname : "",
  2648. sendheader : true,
  2649. async : true,
  2650. decode :true,
  2651. postBody :false
  2652. };
  2653. this.option(option);
  2654. /*
  2655. 테스트를 위해 우선 적용가능한 설정 객체가 존재하면 적용
  2656. */
  2657. if(jindo.$Ajax.CONFIG){
  2658. this.option(jindo.$Ajax.CONFIG);
  2659. }
  2660. var _opt = this._options;
  2661. _opt.type = _opt.type.toLowerCase();
  2662. _opt.method = _opt.method.toLowerCase();
  2663. if (typeof window.__jindo2_callback == "undefined") {
  2664. window.__jindo2_callback = new Array();
  2665. }
  2666. switch (_opt.type) {
  2667. case "put":
  2668. case "delete":
  2669. case "get":
  2670. case "post":
  2671. _opt.method = _opt.type;
  2672. _opt.type = "xhr";
  2673. case "xhr":
  2674. this._request = _getXHR();
  2675. break;
  2676. case "flash":
  2677. if(!jindo.$Ajax.SWFRequest) throw Error('Require jindo.$Ajax.SWFRequest');
  2678. this._request = new jindo.$Ajax.SWFRequest(jindo.$Fn(this.option,this).bind());
  2679. break;
  2680. case "jsonp":
  2681. if(!jindo.$Ajax.JSONPRequest) throw Error('Require jindo.$Ajax.JSONPRequest');
  2682. _opt.method = "get";
  2683. this._request = new jindo.$Ajax.JSONPRequest(jindo.$Fn(this.option,this).bind());
  2684. break;
  2685. case "iframe":
  2686. if(!jindo.$Ajax.FrameRequest) throw Error('Require jindo.$Ajax.FrameRequest');
  2687. this._request = new jindo.$Ajax.FrameRequest(jindo.$Fn(this.option,this).bind());
  2688. break;
  2689. }
  2690. };
  2691. /**
  2692. * @ignore
  2693. */
  2694. jindo.$Ajax.prototype._onload = (function(isIE) {
  2695. if(isIE){
  2696. return function(){
  2697. var bSuccess = this._request.readyState == 4 && this._request.status == 200;
  2698. var oResult;
  2699. if (this._request.readyState == 4) {
  2700. try {
  2701. if (this._request.status != 200 && typeof this._options.onerror == 'function'){
  2702. if(!this._request.status == 0){
  2703. this._options.onerror(jindo.$Ajax.Response(this._request));
  2704. }
  2705. }else{
  2706. if(!this._is_abort){
  2707. oResult = this._options.onload(jindo.$Ajax.Response(this._request));
  2708. }
  2709. }
  2710. }finally{
  2711. if(typeof this._oncompleted == 'function'){
  2712. this._oncompleted(bSuccess, oResult);
  2713. }
  2714. if (this._options.type == "xhr" ){
  2715. this.abort();
  2716. try { delete this._request.onload; } catch(e) { this._request.onload =undefined;}
  2717. }
  2718. delete this._request.onreadystatechange;
  2719. }
  2720. }
  2721. }
  2722. }else{
  2723. return function(){
  2724. var bSuccess = this._request.readyState == 4 && this._request.status == 200;
  2725. var oResult;
  2726. if (this._request.readyState == 4) {
  2727. try {
  2728. if (this._request.status != 200 && typeof this._options.onerror == 'function'){
  2729. this._options.onerror(jindo.$Ajax.Response(this._request));
  2730. }else{
  2731. oResult = this._options.onload(jindo.$Ajax.Response(this._request));
  2732. }
  2733. }finally{
  2734. this._status--;
  2735. if(typeof this._oncompleted == 'function'){
  2736. this._oncompleted(bSuccess, oResult);
  2737. }
  2738. }
  2739. }
  2740. }
  2741. }
  2742. })(/MSIE/.test(window.navigator.userAgent));
  2743. /**
  2744. * request 메서드는 Ajax 요청을 서버에 전송한다.<br>
  2745. * 요청에 사용할 매개 변수는 $Ajax 생성자에서 설정하거나 option 메서드에서 변경할 있다.<br>
  2746. *
  2747. * @remark 요청 타입(type) "flash" 이면 메소드를 실행하기 전에 body 태그 내부에서 $Ajax.SWFRequest.write() 명령어를 반드시 실행해야 한다.
  2748. *
  2749. * @param {Object} oData 서버로 전송할 데이터.
  2750. * @return {$Ajax} $Ajax 객체
  2751. * @description [Lite]
  2752. * @example
  2753. *
  2754. *
  2755. var ajax = $Ajax("http://www.remote.com", {
  2756. onload : function(res) {
  2757. // onload 핸들러
  2758. }
  2759. });
  2760. ajax.request( {key1:"value1", key2:"value2"} ); // 서버에 전송할 데이터를 매개변수로 넘긴다.
  2761. */
  2762. jindo.$Ajax.prototype.request = function(oData) {
  2763. this._status++;
  2764. var t = this;
  2765. var req = this._request;
  2766. var opt = this._options;
  2767. var data, v,a = [], data = "";
  2768. var _timer = null;
  2769. var url = this._url;
  2770. this._is_abort = false;
  2771. if( opt.postBody && opt.type.toUpperCase()=="XHR" && opt.method.toUpperCase()!="GET"){
  2772. if(typeof oData == 'string'){
  2773. data = oData;
  2774. }else{
  2775. data = jindo.$Json(oData).toString();
  2776. }
  2777. }else if (typeof oData == "undefined" || !oData) {
  2778. data = null;
  2779. } else {
  2780. for(var k in oData) {
  2781. if(oData.hasOwnProperty(k)){
  2782. v = oData[k];
  2783. if (typeof v == "function") v = v();
  2784. if (v instanceof Array || v instanceof jindo.$A) {
  2785. jindo.$A(v).forEach(function(value,index,array) {
  2786. a[a.length] = k+"="+encodeURIComponent(value);
  2787. });
  2788. } else {
  2789. a[a.length] = k+"="+encodeURIComponent(v);
  2790. }
  2791. }
  2792. }
  2793. data = a.join("&");
  2794. }
  2795. /*
  2796. XHR GET 방식 요청인 경우 URL에 파라미터 추가
  2797. */
  2798. if(data && opt.type.toUpperCase()=="XHR" && opt.method.toUpperCase()=="GET"){
  2799. if(url.indexOf('?')==-1){
  2800. url += "?";
  2801. } else {
  2802. url += "&";
  2803. }
  2804. url += data;
  2805. data = null;
  2806. }
  2807. req.open(opt.method.toUpperCase(), url, opt.async);
  2808. if(opt.type.toUpperCase()=="XHR"&&opt.method.toUpperCase()=="GET"&&/MSIE/.test(window.navigator.userAgent)){
  2809. /*
  2810. xhr인 경우 IE에서는 GET으로 보낼 브라우져에서 자체 cache하여 cache을 안되게 수정.
  2811. */
  2812. req.setRequestHeader("If-Modified-Since", "Thu, 1 Jan 1970 00:00:00 GMT");
  2813. }
  2814. if (opt.sendheader) {
  2815. if(!this._headers["Content-Type"]){
  2816. req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
  2817. }
  2818. req.setRequestHeader("charset", "utf-8");
  2819. for (var x in this._headers) {
  2820. if(this._headers.hasOwnProperty(x)){
  2821. if (typeof this._headers[x] == "function")
  2822. continue;
  2823. req.setRequestHeader(x, String(this._headers[x]));
  2824. }
  2825. }
  2826. }
  2827. var navi = navigator.userAgent;
  2828. if(req.addEventListener&&!(navi.indexOf("Opera") > -1)&&!(navi.indexOf("MSIE") > -1)){
  2829. /*
  2830. * opera 10.60에서 XMLHttpRequest에 addEventListener기 추가되었지만 정상적으로 동작하지 않아 opera는 무조건 dom1방식으로 지원함.
  2831. * IE9에서도 opera와 같은 문제가 있음.
  2832. */
  2833. if(this._loadFunc){ req.removeEventListener("load", this._loadFunc, false); }
  2834. this._loadFunc = function(rq){
  2835. clearTimeout(_timer);
  2836. _timer = undefined;
  2837. t._onload(rq);
  2838. }
  2839. req.addEventListener("load", this._loadFunc, false);
  2840. }else{
  2841. if (typeof req.onload != "undefined") {
  2842. req.onload = function(rq){
  2843. if(req.readyState == 4 && !t._is_abort){
  2844. clearTimeout(_timer);
  2845. _timer = undefined;
  2846. t._onload(rq);
  2847. }
  2848. };
  2849. } else {
  2850. /*
  2851. * IE6에서는 onreadystatechange가 동기적으로 실행되어 timeout이벤트가 발생안됨.
  2852. * 그래서 interval로 체크하여 timeout이벤트가 정상적으로 발생되도록 수정. 비동기 방식일때만
  2853. */
  2854. if(window.navigator.userAgent.match(/(?:MSIE) ([0-9.]+)/)[1]==6&&opt.async){
  2855. var onreadystatechange = function(rq){
  2856. if(req.readyState == 4 && !t._is_abort){
  2857. if(_timer){
  2858. clearTimeout(_timer);
  2859. _timer = undefined;
  2860. }
  2861. t._onload(rq);
  2862. clearInterval(t._interval);
  2863. t._interval = undefined;
  2864. }
  2865. };
  2866. this._interval = setInterval(onreadystatechange,300);
  2867. }else{
  2868. req.onreadystatechange = function(rq){
  2869. if(req.readyState == 4){
  2870. clearTimeout(_timer);
  2871. _timer = undefined;
  2872. t._onload(rq);
  2873. }
  2874. };
  2875. }
  2876. }
  2877. }
  2878. if (opt.timeout > 0) {
  2879. // if(this._interval)clearInterval(this._interval);
  2880. if(this._timer) clearTimeout(this._timer);
  2881. _timer = setTimeout(function(){
  2882. t._is_abort = true;
  2883. if(t._interval){
  2884. clearInterval(t._interval);
  2885. t._interval = undefined;
  2886. }
  2887. try{ req.abort(); }catch(e){};
  2888. opt.ontimeout(req);
  2889. if(typeof t._oncompleted == 'function') t._oncompleted(false);
  2890. }, opt.timeout * 1000 );
  2891. this._timer = _timer;
  2892. }
  2893. /*
  2894. * test을 하기 위한 url
  2895. */
  2896. this._test_url = url;
  2897. req.send(data);
  2898. return this;
  2899. };
  2900. /**
  2901. * isIdle 메서드는 Ajax 객체가 현재 요청 대기 상태인지 확인한다.
  2902. * @return {Boolean} 현재 대기 중이면 true , 그렇지 않으면 false를 리턴한다.
  2903. * @since 1.3.5 부터 사용 가능
  2904. * @description [Lite]
  2905. * @example
  2906. var ajax = $Ajax("http://www.remote.com",{
  2907. onload : function(res){
  2908. // onload 핸들러
  2909. }
  2910. });
  2911. if(ajax.isIdle()) ajax.request();
  2912. */
  2913. jindo.$Ajax.prototype.isIdle = function(){
  2914. return this._status==0;
  2915. }
  2916. /**
  2917. * abort 메서드는 서버로 전송한 Ajax 요청을 취소한다. Ajax 요청의 응답 시간이 길거나 강제로 Ajax 요청을 취소할 경우 사용한다.
  2918. * @return {$Ajax} 전송을 취소한 $Ajax 객체
  2919. * @description [Lite]
  2920. * @example
  2921. var ajax = $Ajax("http://www.remote.com", {
  2922. timeout : 3,
  2923. ontimeout : function() {
  2924. stopRequest();
  2925. }
  2926. onload : function(res) {
  2927. // onload 핸들러
  2928. }
  2929. }).request( {key1:"value1", key2:"value2"} );
  2930. function stopRequest() {
  2931. ajax.abort();
  2932. }
  2933. */
  2934. jindo.$Ajax.prototype.abort = function() {
  2935. try {
  2936. if(this._interval) clearInterval(this._interval);
  2937. if(this._timer) clearTimeout(this._timer);
  2938. this._interval = undefined;
  2939. this._timer = undefined;
  2940. this._is_abort = true;
  2941. this._request.abort();
  2942. }finally{
  2943. this._status--;
  2944. }
  2945. return this;
  2946. };
  2947. /**
  2948. * option 메서드는 Ajax 요청에서 사용한 정보를 가져오거나 혹은 설정한다.<br>
  2949. * 설정하려면 이름과 값을, 혹은 이름과 값을 원소로 가지는 하나의 객체를 매개 변수로 사용한다.<br>
  2950. * 이름과 값을 원소로 가지는 객체를 사용하면 이상의 정보를 번에 설정할 있다.
  2951. *
  2952. * @param {String | Object} name <br>
  2953. * 매개 변수의 타입은 문자열 혹은 객체를 사용한다.<br>
  2954. * <br>
  2955. * 문자열을 매개 변수로 사용하면 다음과 같이 동작한다..<br>
  2956. * 1. value 매개 변수를 생략하면 이름에 해당하는 $Ajax의 속성 값을 리턴한다.<br>
  2957. * 2. value 매개 변수를 설정하면 이름에 해당하는 $Ajax의 속성에 value를 값으로 설정한다.<br>
  2958. * <br>
  2959. * 객체인 경우에는 속성 이름으로 정보를 찾아 속성의 값으로 설정한다. 객체에 이상의 속성을 지정하면 여러 속성 값을 번에 설정할 있다.
  2960. * @param {String} [value] 새로 설정할 정보의 . name 매개 변수가 문자열인 경우에만 사용된다.
  2961. * @return {String|$Ajax} 정보의 값을 가져올 때는 문자열을, 값을 설정할 때는 $Ajax 객체를 리턴한다.
  2962. * @description [Lite]
  2963. * @example
  2964. var ajax = $Ajax("http://www.remote.com", {
  2965. type : "xhr",
  2966. method : "get",
  2967. onload : function(res) {
  2968. // onload 핸들러
  2969. }
  2970. });
  2971. var request_type = ajax.option("type"); // type 인 xhr 을 리턴한다.
  2972. ajax.option("method", "post"); // method 를 post 로 설정한다.
  2973. ajax.option( { timeout : 0, onload : handler_func } ); // timeout 을 으로, onload 를 handler_func 로 설정한다.
  2974. */
  2975. jindo.$Ajax.prototype.option = function(name, value) {
  2976. if (typeof name == "undefined") return "";
  2977. if (typeof name == "string") {
  2978. if (typeof value == "undefined") return this._options[name];
  2979. this._options[name] = value;
  2980. return this;
  2981. }
  2982. try {
  2983. for(var x in name){
  2984. if(name.hasOwnProperty(x))
  2985. this._options[x] = name[x]
  2986. }
  2987. } catch(e) {};
  2988. return this;
  2989. };
  2990. /**
  2991. * header 메서드는 Ajax 요청에서 사용할 HTTP 요청 헤더를 가져오거나 설정한다.<br>
  2992. * 헤더를 설정하려면 헤더의 이름과 값을 각각 매개 변수로 사용하거나, 헤더의 이름과 값을 원소로 가지는 객체를 매개 변수로 사용한다. 만약 여러 개의 속성을 가진 객체를 사용하면 이상의 헤더를 번에 설정할 있다.<br>
  2993. * 헤더에서 특정 속성의 값을 가져오려면 속성의 이름을 매개 변수로 사용한다.
  2994. *
  2995. * @param {String|Object} name <br>
  2996. * 매개 변수의 타입은 문자열 혹은 객체를 사용한다.<br>
  2997. * <br>
  2998. * 문자열을 매개 변수로 사용하면 다음과 같이 동작한다. <br>
  2999. * 1. value 매개 변수를 생략하면 HTTP 요청 헤더에서 문자열과 일치하는 속성값을 찾는다.<br>
  3000. * 2. value 매개 변수를 설정하면 HTTP 요청 헤더에서 문자열과 일치하는 속성에 value를 값으로 설정한다.<br>
  3001. * <br>
  3002. * 객체인 경우에는 속성 이름으로 정보를 찾아 속성의 값으로 설정한다. 객체에 이상의 속성을 지정하면 HTTP 요청 헤더에서 여러 속성 값을 번에 설정할 있다.
  3003. * @param {Value} [value] 설정할 헤더 . name 매개 변수가 문자열인 경우에만 사용된다.
  3004. * @return {String|$Ajax} 정보의 값을 가져올 때는 문자열을, 값을 설정할 때는 $Ajax 객체를 리턴한다.
  3005. * @description [Lite]
  3006. * @example
  3007. var customheader = ajax.header("myHeader"); // HTTP 요청 헤더에서 myHeader 의 값
  3008. ajax.header( "myHeader", "someValue" ); // HTTP 요청 헤더의 myHeader 를 someValue 로 설정한다.
  3009. ajax.header( { anotherHeader : "someValue2" } ); // HTTP 요청 헤더의 anotherHeader 를 someValue2 로 설정한다.
  3010. */
  3011. jindo.$Ajax.prototype.header = function(name, value) {
  3012. if (typeof name == "undefined") return "";
  3013. if (typeof name == "string") {
  3014. if (typeof value == "undefined") return this._headers[name];
  3015. this._headers[name] = value;
  3016. return this;
  3017. }
  3018. try {
  3019. for (var x in name) {
  3020. if (name.hasOwnProperty(x))
  3021. this._headers[x] = name[x]
  3022. }
  3023. } catch(e) {};
  3024. return this;
  3025. };
  3026. /**
  3027. * Ajax 응답 객체를 래핑하여 응답을 가져오는데 유용한 메서드를 제공한다.
  3028. * @class $Ajax.Response 객체를 생성하여 리턴한다.<br>
  3029. * $Ajax 객체에서 request 요청 처리 완료 , 생성되며 $Ajax 생성 시에 설정한 onload 콜백 함수의 매개 변수로 전달된다.
  3030. * @constructor
  3031. * @param {Object} req 요청 객체
  3032. * @description [Lite]
  3033. */
  3034. jindo.$Ajax.Response = function(req) {
  3035. if (this === jindo.$Ajax) return new jindo.$Ajax.Response(req);
  3036. this._response = req;
  3037. };
  3038. /**
  3039. * 응답을 XML 객체로 리턴한다.
  3040. * @return {Object} 응답 XML 객체. XHR의 responseXML 유사하다.
  3041. * @description [Lite]
  3042. *
  3043. * @example
  3044. // some.xml
  3045. <?xml version="1.0" encoding="utf-8"?>
  3046. <data>
  3047. <li>첫번째</li>
  3048. <li>두번째</li>
  3049. <li>세번째</li>
  3050. </data>
  3051. // client.html
  3052. var oAjax = new $Ajax('some.xml', {
  3053. type : 'xhr',
  3054. method : 'get',
  3055. onload : function(res){
  3056. var elData = cssquery.getSingle('data', res.xml()); // 응답을 XML 객체로 리턴한다
  3057. $('list').innerHTML = elData.firstChild.nodeValue;
  3058. },
  3059. }).request();
  3060. */
  3061. jindo.$Ajax.Response.prototype.xml = function() {
  3062. return this._response.responseXML;
  3063. };
  3064. /**
  3065. * 응답을 문자열로 리턴한다.
  3066. * @return {String} 응답 문자열. XHR의 responseText 유사하다.
  3067. * @description [Lite]
  3068. *
  3069. * @example
  3070. // some.php
  3071. <?php
  3072. echo "<li>첫번째</li><li>두번째</li><li>세번째</li>";
  3073. ?>
  3074. // client.html
  3075. var oAjax = new $Ajax('some.xml', {
  3076. type : 'xhr',
  3077. method : 'get',
  3078. onload : function(res){
  3079. $('list').innerHTML = res.text(); // 응답을 문자열로 리턴한다
  3080. },
  3081. }).request();
  3082. */
  3083. jindo.$Ajax.Response.prototype.text = function() {
  3084. return this._response.responseText;
  3085. };
  3086. /**
  3087. * HTTP 응답 코드를 리턴한다.
  3088. * @return {Number} 응답 코드. http 응답 코드표를 참고한다.
  3089. * @description [Lite]
  3090. *
  3091. * @example
  3092. var oAjax = new $Ajax('some.php', {
  3093. type : 'xhr',
  3094. method : 'get',
  3095. onload : function(res){
  3096. if(res.status() == 200){ // HTTP 응답 코드를 확인한다.
  3097. $('list').innerHTML = res.text();
  3098. }
  3099. },
  3100. }).request();
  3101. */
  3102. jindo.$Ajax.Response.prototype.status = function() {
  3103. return this._response.status;
  3104. };
  3105. /**
  3106. * 응답의 readyState 리턴한다.
  3107. * @return {Number} readyState.
  3108. * @description [Lite]
  3109. *
  3110. * @example
  3111. var oAjax = new $Ajax('some.php', {
  3112. type : 'xhr',
  3113. method : 'get',
  3114. onload : function(res){
  3115. if(res.readyState() == 4){ // 응답의 readyState 를 확인한다.
  3116. $('list').innerHTML = res.text();
  3117. }
  3118. },
  3119. }).request();
  3120. */
  3121. jindo.$Ajax.Response.prototype.readyState = function() {
  3122. return this._response.readyState;
  3123. };
  3124. /**
  3125. * 응답을 JSON 객체로 리턴한다.
  3126. * @return {Object} 응답 JSON 객체. <br>
  3127. * 응답 문자열을 자동으로 JSON 객체로 변환하여 리턴한다. 변환 과정에서 오류가 발생하면 객체를 리턴한다.
  3128. * @description [Lite]
  3129. *
  3130. * @example
  3131. // some.php
  3132. <?php
  3133. echo "['첫번째', '두번째', '세번째']";
  3134. ?>
  3135. // client.html
  3136. var oAjax = new $Ajax('some.php', {
  3137. type : 'xhr',
  3138. method : 'get',
  3139. onload : function(res){
  3140. var welList = $Element('list').empty();
  3141. var jsonData = res.json(); // 응답을 JSON 객체로 리턴한다
  3142. for(var i = 0, nLen = jsonData.length; i < nLen; i++){
  3143. welList.append($("<li>" + jsonData[i] + "</li>"));
  3144. }
  3145. },
  3146. }).request();
  3147. */
  3148. jindo.$Ajax.Response.prototype.json = function() {
  3149. if (this._response.responseJSON) {
  3150. return this._response.responseJSON;
  3151. } else if (this._response.responseText) {
  3152. try {
  3153. return eval("("+this._response.responseText+")");
  3154. } catch(e) {
  3155. return {};
  3156. }
  3157. }
  3158. return {};
  3159. };
  3160. /**
  3161. * 응답 헤더를 가져온다. 매개 변수를 전달하지 않으면 헤더 전체를 리턴한다.
  3162. * @param {String} name 가져올 응답 헤더의 이름
  3163. * @return {String|Object} 매개 변수가 있을 때는 해당하는 헤더 값을, 그렇지 않으면 헤더 전체를 리턴한다.
  3164. * @description [Lite]
  3165. *
  3166. * @example
  3167. var oAjax = new $Ajax('some.php', {
  3168. type : 'xhr',
  3169. method : 'get',
  3170. onload : function(res){
  3171. res.header(); // 응답 헤더 전체를 리턴한다.
  3172. res.header("Content-Length") // 응답 헤더에서 "Content-Length" 의 값을 리턴한다.
  3173. },
  3174. }).request();
  3175. */
  3176. jindo.$Ajax.Response.prototype.header = function(name) {
  3177. if (typeof name == "string") return this._response.getResponseHeader(name);
  3178. return this._response.getAllResponseHeaders();
  3179. };
  3180. /**
  3181. * @fileOverview $Ajax의 확장 메서드를 정의한 파일
  3182. * @name Ajax.extend.js
  3183. */
  3184. /**
  3185. * Ajax 요청 타입 별로 요청 객체를 생성하기 위한 상위 객체로 사용한다.
  3186. * @class Ajax 요청 객체의 기본 객체이다.
  3187. */
  3188. jindo.$Ajax.RequestBase = jindo.$Class({
  3189. _respHeaderString : "",
  3190. callbackid:"",
  3191. callbackname:"",
  3192. responseXML : null,
  3193. responseJSON : null,
  3194. responseText : "",
  3195. status : 404,
  3196. readyState : 0,
  3197. $init : function(fpOption){},
  3198. onload : function(){},
  3199. abort : function(){},
  3200. open : function(){},
  3201. send : function(){},
  3202. setRequestHeader : function(sName, sValue) {
  3203. this._headers[sName] = sValue;
  3204. },
  3205. getResponseHeader : function(sName) {
  3206. return this._respHeaders[sName] || "";
  3207. },
  3208. getAllResponseHeaders : function() {
  3209. return this._respHeaderString;
  3210. },
  3211. _getCallbackInfo : function() {
  3212. var id = "";
  3213. if(this.option("callbackid")!="") {
  3214. var idx = 0;
  3215. do {
  3216. id = "_" + this.option("callbackid") + "_"+idx;
  3217. idx++;
  3218. } while (window.__jindo2_callback[id]);
  3219. }else{
  3220. do {
  3221. id = "_" + Math.floor(Math.random() * 10000);
  3222. } while (window.__jindo2_callback[id]);
  3223. }
  3224. if(this.option("callbackname") == ""){
  3225. this.option("callbackname","_callback");
  3226. }
  3227. return {callbackname:this.option("callbackname"),id:id,name:"window.__jindo2_callback."+id};
  3228. }
  3229. });
  3230. /**
  3231. * $Ajax.JSONPRequest 객체를 생성하여 리턴한다.
  3232. * @extends $Ajax.RequestBase
  3233. * @class Ajax 요청 타입(type) jsonp 요청 객체를 생성하며, jindo.$Ajax 생성자에서 요청 객체 생성 사용한다.
  3234. */
  3235. jindo.$Ajax.JSONPRequest = jindo.$Class({
  3236. _headers : {},
  3237. _respHeaders : {},
  3238. _script : null,
  3239. _onerror : null,
  3240. $init : function(fpOption){
  3241. this.option = fpOption;
  3242. },
  3243. _callback : function(data) {
  3244. if (this._onerror) {
  3245. clearTimeout(this._onerror);
  3246. this._onerror = null;
  3247. }
  3248. var self = this;
  3249. this.responseJSON = data;
  3250. this.onload(this);
  3251. setTimeout(function(){ self.abort() }, 10);
  3252. },
  3253. abort : function() {
  3254. if (this._script) {
  3255. try {
  3256. this._script.parentNode.removeChild(this._script);
  3257. }catch(e){
  3258. };
  3259. }
  3260. },
  3261. open : function(method, url) {
  3262. this.responseJSON = null;
  3263. this._url = url;
  3264. },
  3265. send : function(data) {
  3266. var t = this;
  3267. var info = this._getCallbackInfo();
  3268. var head = document.getElementsByTagName("head")[0];
  3269. this._script = jindo.$("<script>");
  3270. this._script.type = "text/javascript";
  3271. this._script.charset = this.option("jsonp_charset");
  3272. if (head) {
  3273. head.appendChild(this._script);
  3274. } else if (document.body) {
  3275. document.body.appendChild(this._script);
  3276. }
  3277. window.__jindo2_callback[info.id] = function(data){
  3278. try {
  3279. t.readyState = 4;
  3280. t.status = 200;
  3281. t._callback(data);
  3282. } finally {
  3283. delete window.__jindo2_callback[info.id];
  3284. }
  3285. };
  3286. var agent = jindo.$Agent(navigator);
  3287. if (agent.navigator().ie || agent.navigator().opera) {
  3288. this._script.onreadystatechange = function(){
  3289. if (this.readyState == 'loaded'){
  3290. if (!t.responseJSON) {
  3291. t.readyState = 4;
  3292. t.status = 500;
  3293. t._onerror = setTimeout(function(){t._callback(null);}, 200);
  3294. }
  3295. this.onreadystatechange = null;
  3296. }
  3297. };
  3298. } else {
  3299. this._script.onload = function(){
  3300. if (!t.responseJSON) {
  3301. t.readyState = 4;
  3302. t.status = 500;
  3303. t._onerror = setTimeout(function(){t._callback(null);}, 200);
  3304. }
  3305. this.onload = null;
  3306. this.onerror = null;
  3307. };
  3308. this._script.onerror = function(){
  3309. if (!t.responseJSON) {
  3310. t.readyState = 4;
  3311. t.status = 404;
  3312. t._onerror = setTimeout(function(){t._callback(null);}, 200);
  3313. }
  3314. this.onerror = null;
  3315. this.onload = null;
  3316. };
  3317. }
  3318. var delimiter = "&";
  3319. if(this._url.indexOf('?')==-1){
  3320. delimiter = "?";
  3321. }
  3322. if (data) {
  3323. data = "&" + data;
  3324. }else{
  3325. data = "";
  3326. }
  3327. //test url for spec.
  3328. this._test_url = this._url+delimiter+info.callbackname+"="+info.name+data;
  3329. this._script.src = this._url+delimiter+info.callbackname+"="+info.name+data;
  3330. }
  3331. }).extend(jindo.$Ajax.RequestBase);
  3332. /**
  3333. * $Ajax.SWFRequest 객체를 생성하여 리턴한다.
  3334. * @extends $Ajax.RequestBase
  3335. * @class Ajax 요청 타입(type) flash 요청 객체를 생성하며, jindo.$Ajax 생성자에서 요청 객체 생성 사용한다.
  3336. */
  3337. jindo.$Ajax.SWFRequest = jindo.$Class({
  3338. $init : function(fpOption){
  3339. this.option = fpOption;
  3340. },
  3341. _headers : {},
  3342. _respHeaders : {},
  3343. _getFlashObj : function(){
  3344. var navi = jindo.$Agent(window.navigator).navigator();
  3345. var obj;
  3346. if (navi.ie&&navi.version==9) {
  3347. obj = document.getElementById(jindo.$Ajax.SWFRequest._tmpId);
  3348. }else{
  3349. obj = window.document[jindo.$Ajax.SWFRequest._tmpId];
  3350. }
  3351. return(this._getFlashObj = function(){
  3352. return obj;
  3353. })();
  3354. },
  3355. _callback : function(status, data, headers){
  3356. this.readyState = 4;
  3357. /*
  3358. 하위 호환을 위해 status가 boolean 값인 경우도 처리
  3359. */
  3360. if( (typeof status).toLowerCase() == 'number'){
  3361. this.status = status;
  3362. }else{
  3363. if(status==true) this.status=200;
  3364. }
  3365. if (this.status==200) {
  3366. if (typeof data == "string") {
  3367. try {
  3368. this.responseText = this.option("decode")?decodeURIComponent(data):data;
  3369. if(!this.responseText || this.responseText=="") {
  3370. this.responseText = data;
  3371. }
  3372. } catch(e) {
  3373. /*
  3374. 데이터 안에 utf-8 아닌 다른 인코딩일때 디코딩을 안하고 바로 text에 저장.
  3375. */
  3376. if(e.name == "URIError"){
  3377. this.responseText = data;
  3378. if(!this.responseText || this.responseText=="") {
  3379. this.responseText = data;
  3380. }
  3381. }
  3382. }
  3383. }
  3384. /*
  3385. 콜백코드는 넣었지만, 아직 SWF에서 응답헤더 지원 안함
  3386. */
  3387. if(typeof headers == "object"){
  3388. this._respHeaders = headers;
  3389. }
  3390. }
  3391. this.onload(this);
  3392. },
  3393. open : function(method, url) {
  3394. var re = /https?:\/\/([a-z0-9_\-\.]+)/i;
  3395. this._url = url;
  3396. this._method = method;
  3397. },
  3398. send : function(data) {
  3399. this.responseXML = false;
  3400. this.responseText = "";
  3401. var t = this;
  3402. var dat = {};
  3403. var info = this._getCallbackInfo();
  3404. var swf = this._getFlashObj()
  3405. function f(arg) {
  3406. switch(typeof arg){
  3407. case "string":
  3408. return '"'+arg.replace(/\"/g, '\\"')+'"';
  3409. break;
  3410. case "number":
  3411. return arg;
  3412. break;
  3413. case "object":
  3414. var ret = "", arr = [];
  3415. if (arg instanceof Array) {
  3416. for(var i=0; i < arg.length; i++) {
  3417. arr[i] = f(arg[i]);
  3418. }
  3419. ret = "["+arr.join(",")+"]";
  3420. } else {
  3421. for(var x in arg) {
  3422. if(arg.hasOwnProperty(x)){
  3423. arr[arr.length] = f(x)+":"+f(arg[x]);
  3424. }
  3425. }
  3426. ret = "{"+arr.join(",")+"}";
  3427. }
  3428. return ret;
  3429. default:
  3430. return '""';
  3431. }
  3432. }
  3433. data = (data || "").split("&");
  3434. for(var i=0; i < data.length; i++) {
  3435. pos = data[i].indexOf("=");
  3436. key = data[i].substring(0,pos);
  3437. val = data[i].substring(pos+1);
  3438. dat[key] = decodeURIComponent(val);
  3439. }
  3440. this._current_callback_id = info.id
  3441. window.__jindo2_callback[info.id] = function(success, data){
  3442. try {
  3443. t._callback(success, data);
  3444. } finally {
  3445. delete window.__jindo2_callback[info.id];
  3446. }
  3447. };
  3448. var oData = {
  3449. url : this._url,
  3450. type : this._method,
  3451. data : dat,
  3452. charset : "UTF-8",
  3453. callback : info.name,
  3454. header_json : this._headers
  3455. };
  3456. swf.requestViaFlash(f(oData));
  3457. },
  3458. abort : function(){
  3459. if(this._current_callback_id){
  3460. window.__jindo2_callback[this._current_callback_id] = function(){
  3461. delete window.__jindo2_callback[info.id];
  3462. }
  3463. }
  3464. }
  3465. }).extend(jindo.$Ajax.RequestBase);
  3466. /**
  3467. * Ajax 요청 타입(type) flash , request 메소드가 호출되기 전에 반드시 실행해야 한다.<br>
  3468. * <br>
  3469. * 요청 타입이 flash 이면 모든 통신은 플래시 객체를 통하여 주고 받으며 Ajax 호출을 하기 전에 반드시 플래시 객체를 초기화해야한다.<br>
  3470. * $Ajax.SWFRequest.write 메서드를 호출하면 통신을 위한 플래시 객체를 문서 내에 추가한다.
  3471. *
  3472. * @param {String} [swf_path] 통신을 담당할 플래시 파일의 경로. 생략하면 기본 값은 "./ajax.swf" 이다.
  3473. *
  3474. * @remark 해당 메서드는 <body> 태그 내에 작성되어야 한다.
  3475. * @remark 반드시 실행해야 한다. 이상 실행해도 문제가 발생한다.
  3476. *
  3477. * @see $Ajax#request
  3478. */
  3479. jindo.$Ajax.SWFRequest.write = function(swf_path) {
  3480. if(typeof swf_path == "undefined") swf_path = "./ajax.swf";
  3481. jindo.$Ajax.SWFRequest._tmpId = 'tmpSwf'+(new Date()).getMilliseconds()+Math.floor(Math.random()*100000);
  3482. var activeCallback = "jindo.$Ajax.SWFRequest.loaded";
  3483. jindo.$Ajax._checkFlashLoad();
  3484. document.write('<div style="position:absolute;top:-1000px;left:-1000px"><object id="'+jindo.$Ajax.SWFRequest._tmpId+'" width="1" height="1" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0"><param name="movie" value="'+swf_path+'"><param name = "FlashVars" value = "activeCallback='+activeCallback+'" /><param name = "allowScriptAccess" value = "always" /><embed name="'+jindo.$Ajax.SWFRequest._tmpId+'" src="'+swf_path+'" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" width="1" height="1" allowScriptAccess="always" swLiveConnect="true" FlashVars="activeCallback='+activeCallback+'"></embed></object></div>');
  3485. };
  3486. /**
  3487. * @ignore
  3488. */
  3489. jindo.$Ajax._checkFlashLoad = function(){
  3490. jindo.$Ajax._checkFlashKey = setTimeout(function(){
  3491. // throw new Error("Check your flash file!. Unload flash on a page.");
  3492. // [SMARTEDITORSUS-334] Flash 를 지원하지 않는 환경(ex. iOS)에서 경고창을 띄우지 않도록 임시적으로 주석 처리함
  3493. // alert("Check your flash file!. Unload flash on a page.");
  3494. },5000);
  3495. jindo.$Ajax._checkFlashLoad = function(){}
  3496. }
  3497. /**
  3498. * flash가 로딩 되었는지 확인 하는 변수.
  3499. */
  3500. jindo.$Ajax.SWFRequest.activeFlash = false;
  3501. /**
  3502. * flash에서 로딩 실행 시키는 함수.
  3503. * @ignore
  3504. */
  3505. jindo.$Ajax.SWFRequest.loaded = function(){
  3506. clearTimeout(jindo.$Ajax._checkFlashKey);
  3507. jindo.$Ajax.SWFRequest.activeFlash = true;
  3508. }
  3509. /**
  3510. * $Ajax.FrameRequest 객체를 생성하여 리턴한다.
  3511. * @extends $Ajax.RequestBase
  3512. * @class Ajax 요청 타입(type) iframe 요청 객체를 생성하며, jindo.$Ajax 생성자에서 요청 객체 생성 사용한다.
  3513. */
  3514. jindo.$Ajax.FrameRequest = jindo.$Class({
  3515. _headers : {},
  3516. _respHeaders : {},
  3517. _frame : null,
  3518. _domain : "",
  3519. $init : function(fpOption){
  3520. this.option = fpOption;
  3521. },
  3522. _callback : function(id, data, header) {
  3523. var self = this;
  3524. this.readyState = 4;
  3525. this.status = 200;
  3526. this.responseText = data;
  3527. this._respHeaderString = header;
  3528. header.replace(/^([\w\-]+)\s*:\s*(.+)$/m, function($0,$1,$2) {
  3529. self._respHeaders[$1] = $2;
  3530. });
  3531. this.onload(this);
  3532. setTimeout(function(){ self.abort() }, 10);
  3533. },
  3534. abort : function() {
  3535. if (this._frame) {
  3536. try {
  3537. this._frame.parentNode.removeChild(this._frame);
  3538. } catch(e) {
  3539. }
  3540. }
  3541. },
  3542. open : function(method, url) {
  3543. var re = /https?:\/\/([a-z0-9_\-\.]+)/i;
  3544. var dom = document.location.toString().match(re);
  3545. this._method = method;
  3546. this._url = url;
  3547. this._remote = String(url).match(/(https?:\/\/[a-z0-9_\-\.]+)(:[0-9]+)?/i)[0];
  3548. this._frame = null;
  3549. this._domain = (dom[1] != document.domain)?document.domain:"";
  3550. },
  3551. send : function(data) {
  3552. this.responseXML = "";
  3553. this.responseText = "";
  3554. var t = this;
  3555. var re = /https?:\/\/([a-z0-9_\-\.]+)/i;
  3556. var info = this._getCallbackInfo();
  3557. var url;
  3558. var _aStr = [];
  3559. _aStr.push(this._remote+"/ajax_remote_callback.html?method="+this._method);
  3560. var header = new Array;
  3561. window.__jindo2_callback[info.id] = function(id, data, header){
  3562. try {
  3563. t._callback(id, data, header);
  3564. } finally {
  3565. delete window.__jindo2_callback[info.id];
  3566. }
  3567. };
  3568. for(var x in this._headers) {
  3569. if(this._headers.hasOwnProperty(x)){
  3570. header[header.length] = "'"+x+"':'"+this._headers[x]+"'";
  3571. }
  3572. }
  3573. header = "{"+header.join(",")+"}";
  3574. _aStr.push("&id="+info.id);
  3575. _aStr.push("&header="+encodeURIComponent(header));
  3576. _aStr.push("&proxy="+encodeURIComponent(this.option("proxy")));
  3577. _aStr.push("&domain="+this._domain);
  3578. _aStr.push("&url="+encodeURIComponent(this._url.replace(re, "")));
  3579. _aStr.push("#"+encodeURIComponent(data));
  3580. var fr = this._frame = jindo.$("<iframe>");
  3581. fr.style.position = "absolute";
  3582. fr.style.visibility = "hidden";
  3583. fr.style.width = "1px";
  3584. fr.style.height = "1px";
  3585. var body = document.body || document.documentElement;
  3586. if (body.firstChild){
  3587. body.insertBefore(fr, body.firstChild);
  3588. }else{
  3589. body.appendChild(fr);
  3590. }
  3591. fr.src = _aStr.join("");
  3592. }
  3593. }).extend(jindo.$Ajax.RequestBase);
  3594. /**
  3595. * $Ajax 객체를 순서대로 호출할 있는 기능을 제공한다.
  3596. * @class $Ajax.Queue는 Ajax 요청을 큐에 담아 큐에 들어온 순서대로 처리한다.
  3597. * @param {Object} option $Ajax.Queue 에서 서버에 요청할 사용하는 다양한 정보를 정의한다.
  3598. <ul>
  3599. <li>
  3600. async : 비동기/동기 요청 여부를 설정한다. 비동기인 경우 true 이며, 기본 값은 false 이다.
  3601. </li>
  3602. <li>
  3603. useResultAsParam : 이전에 처리된 요청의 결과를 다음 요청에 매개 변수로 넘길지 여부를 설정한다. 요청 결과를 넘기면 true 이며, 기본 값은 false 이다.
  3604. </li>
  3605. <li>
  3606. stopOnFailure : 이전 요청이 실패하는 경우 다음 요청을 멈출지 여부를 설정한다. 멈춘다면 true 이며, 기본 값은 false 이다.
  3607. </li>
  3608. </ul>
  3609. * @constructor
  3610. * @since 1.3.7
  3611. *
  3612. * @example
  3613. // $Ajax 요청 큐를 생성한다.
  3614. var oAjaxQueue = new $Ajax.Queue({
  3615. useResultAsParam : true
  3616. });
  3617. */
  3618. jindo.$Ajax.Queue = function (option) {
  3619. var cl = arguments.callee;
  3620. if (!(this instanceof cl)){ return new cl(option);}
  3621. this._options = {
  3622. async : false,
  3623. useResultAsParam : false,
  3624. stopOnFailure : false
  3625. };
  3626. this.option(option);
  3627. this._queue = [];
  3628. }
  3629. /**
  3630. * $Ajax.Queue 옵션을 가져오거나 설정한다.
  3631. * @param {Object} name 옵션의 이름
  3632. * @param {Object} [value] 옵션의 . 옵션을 설정하는 경우에는 값을 지정한다.
  3633. * @return {Value | $Ajax.Queue} 값을 가져오는 경우 해당 값을, 설정하는 경우 $Ajax.Queue 객체를 리턴한다.
  3634. * @example
  3635. var oAjaxQueue = new $Ajax.Queue({
  3636. useResultAsParam : true
  3637. });
  3638. oAjaxQueue.option("useResultAsParam"); // useResultAsParam 옵션 값인 true 를 리턴한다.
  3639. oAjaxQueue.option("async", true); // async 옵션을 true 로 설정한다.
  3640. */
  3641. jindo.$Ajax.Queue.prototype.option = function(name, value) {
  3642. if (typeof name == "undefined"){ return "";}
  3643. if (typeof name == "string") {
  3644. if (typeof value == "undefined"){ return this._options[name];}
  3645. this._options[name] = value;
  3646. return this;
  3647. }
  3648. try {
  3649. for(var x in name) {
  3650. if(name.hasOwnProperty(x))
  3651. this._options[x] = name[x]
  3652. }
  3653. } catch(e) {
  3654. };
  3655. return this;
  3656. };
  3657. /**
  3658. * Ajax 요청 큐에 요청을 추가한다.
  3659. * @param {$Ajax} 추가할 $Ajax 객체
  3660. * @param {Object} 요청 전송할 매개 변수 객체
  3661. *
  3662. * @example
  3663. var oAjax1 = new $Ajax('ajax_test.php',{
  3664. onload : function(res){
  3665. // onload 핸들러
  3666. }
  3667. });
  3668. var oAjax2 = new $Ajax('ajax_test.php',{
  3669. onload : function(res){
  3670. // onload 핸들러
  3671. }
  3672. });
  3673. var oAjax3 = new $Ajax('ajax_test.php',{
  3674. onload : function(res){
  3675. // onload 핸들러
  3676. }
  3677. });
  3678. var oAjaxQueue = new $Ajax.Queue({
  3679. async : true,
  3680. useResultAsParam : true,
  3681. stopOnFailure : false
  3682. });
  3683. // Ajax 요청 큐에 추가한다.
  3684. oAjaxQueue.add(oAjax1,{seq:1});
  3685. oAjaxQueue.add(oAjax2,{seq:2,foo:99});
  3686. oAjaxQueue.add(oAjax3,{seq:3});
  3687. oAjaxQueue.request();
  3688. */
  3689. jindo.$Ajax.Queue.prototype.add = function (oAjax, oParam) {
  3690. this._queue.push({obj:oAjax, param:oParam});
  3691. }
  3692. /**
  3693. * Ajax Queue를 요청한다.
  3694. *
  3695. * @example
  3696. var oAjaxQueue = new $Ajax.Queue({
  3697. useResultAsParam : true
  3698. });
  3699. oAjaxQueue.add(oAjax1,{seq:1});
  3700. oAjaxQueue.add(oAjax2,{seq:2,foo:99});
  3701. oAjaxQueue.add(oAjax3,{seq:3});
  3702. // 서버에 Ajax 요청을 보낸다.
  3703. oAjaxQueue.request();
  3704. */
  3705. jindo.$Ajax.Queue.prototype.request = function () {
  3706. if(this.option('async')){
  3707. this._requestAsync();
  3708. } else {
  3709. this._requestSync(0);
  3710. }
  3711. }
  3712. jindo.$Ajax.Queue.prototype._requestSync = function (nIdx, oParam) {
  3713. var t = this;
  3714. if (this._queue.length > nIdx+1) {
  3715. this._queue[nIdx].obj._oncompleted = function(bSuccess, oResult){
  3716. if(!t.option('stopOnFailure') || bSuccess) t._requestSync(nIdx + 1, oResult);
  3717. };
  3718. }
  3719. var _oParam = this._queue[nIdx].param||{};
  3720. if(this.option('useResultAsParam') && oParam){
  3721. try { for(var x in oParam) if(typeof _oParam[x] == 'undefined' && oParam.hasOwnProperty(x)) _oParam[x] = oParam[x] } catch(e) {};
  3722. }
  3723. this._queue[nIdx].obj.request(_oParam);
  3724. }
  3725. jindo.$Ajax.Queue.prototype._requestAsync = function () {
  3726. for( var i=0; i<this._queue.length; i++)
  3727. this._queue[i].obj.request(this._queue[i].param);
  3728. }
  3729. /**
  3730. * @fileOverview $H의 생성자 메서드를 정의한 파일
  3731. * @name hash.js
  3732. */
  3733. /**
  3734. * $H 해시 객체를 리턴한다
  3735. * @class $H 클래스는 키와 값을 원소로 가지는 열거형 배열인 해시를 구현하고, 해시를 다루기 위한 여러 가지 위한 메서드를 제공한다.
  3736. * @param {Object} hashObject 해시로 만들 객체.
  3737. * @return {$H} 해시 객체
  3738. * @constructor
  3739. * @example
  3740. var h = $H({one:"first", two:"second", three:"third"})
  3741. * @author Kim, Taegon
  3742. */
  3743. jindo.$H = function(hashObject) {
  3744. var cl = arguments.callee;
  3745. if (typeof hashObject == "undefined") hashObject = new Object;
  3746. if (hashObject instanceof cl) return hashObject;
  3747. if (!(this instanceof cl)) return new cl(hashObject);
  3748. this._table = {};
  3749. for(var k in hashObject) {
  3750. if(hashObject.hasOwnProperty(k)){
  3751. this._table[k] = hashObject[k];
  3752. }
  3753. }
  3754. };
  3755. /**
  3756. * $value 메서드는 해싱 대상인 객체를 반환한다.
  3757. * @return {Object} 해싱 대상 객체
  3758. */
  3759. jindo.$H.prototype.$value = function() {
  3760. return this._table;
  3761. };
  3762. /**
  3763. * $ 메서드는 키와 값을 설정하거나 키에 해당하는 값을 반환한다.
  3764. * @param {String} key
  3765. * @param {void} [value]
  3766. * @return {void|$H} 키에 해당하는 혹은 $H 객체
  3767. * @example
  3768. * var hash = $H({one:"first", two:"second"});
  3769. *
  3770. * // 값을 설정할 때
  3771. * hash.$("three", "third");
  3772. *
  3773. * // hash => {one:"first", two:"second", three:"third"}
  3774. *
  3775. * // 값을 반환할 때
  3776. * var three = hash.$("three");
  3777. *
  3778. * // three => "third"
  3779. */
  3780. jindo.$H.prototype.$ = function(key, value) {
  3781. if (typeof value == "undefined") {
  3782. return this._table[key];
  3783. }
  3784. this._table[key] = value;
  3785. return this;
  3786. };
  3787. /**
  3788. * length 메서드는 해시 객체의 크기를 반환한다.
  3789. * @return {Number} 해시의 크기
  3790. */
  3791. jindo.$H.prototype.length = function() {
  3792. var i = 0;
  3793. for(var k in this._table) {
  3794. if(this._table.hasOwnProperty(k)){
  3795. if (typeof Object.prototype[k] != "undeifned" && Object.prototype[k] === this._table[k]) continue;
  3796. i++;
  3797. }
  3798. }
  3799. return i;
  3800. };
  3801. /**
  3802. * forEach 메서드는 해시 객체의 키와 값을 인수로 지정한 콜백 함수를 실행한다.
  3803. * @param {Function} callback 실행할 콜백 함수
  3804. * @param {Object} thisObject 콜백 함수의 this
  3805. * @example
  3806. function printIt(value, key) {
  3807. document.write(key+" => "+value+" <br>");
  3808. }
  3809. $H({one:"first", two:"second", three:"third"}).forEach(printIt);
  3810. */
  3811. jindo.$H.prototype.forEach = function(callback, thisObject) {
  3812. var t = this._table;
  3813. var h = this.constructor;
  3814. for(var k in t) {
  3815. if (t.hasOwnProperty(k)) {
  3816. if (!t.propertyIsEnumerable(k)) continue;
  3817. try {
  3818. callback.call(thisObject, t[k], k, t);
  3819. } catch(e) {
  3820. if (e instanceof h.Break) break;
  3821. if (e instanceof h.Continue) continue;
  3822. throw e;
  3823. }
  3824. }
  3825. }
  3826. return this;
  3827. };
  3828. /**
  3829. * filter 메서드는 해시 객체에서 필터 콜백 함수를 만족하는 원소를 수집한다. 수집한 원소는 새로운 $H 객체의 원소가 된다.
  3830. * 콜백함수는 Boolean 값을 반환해야 한다.
  3831. * @param {Function} callback 필터 콜백 함수
  3832. * @param {Object} thisObject 콜백 함수의 this
  3833. * @return {$H} 수집한 원소로 새로 만든 해시 객체
  3834. * @remark 필터 콜백 함수의 결과가 true인 원소만 수집한다. 콜백 함수는 형식은 예제를 참고한다.
  3835. * @example
  3836. function callback(value, key, object) {
  3837. // value 해시의 값
  3838. // key 해시의 고유한 키 혹은 이름
  3839. // object JavaScript Core Object 객체
  3840. }
  3841. */
  3842. jindo.$H.prototype.filter = function(callback, thisObject) {
  3843. var h = jindo.$H();
  3844. this.forEach(function(v,k,o) {
  3845. if(callback.call(thisObject, v, k, o) === true) {
  3846. h.add(k,v);
  3847. }
  3848. });
  3849. return h;
  3850. };
  3851. /**
  3852. * map 메서드는 해시 객체의 원소를 인수로 콜백 함수를 실행하고, 함수의 리턴 값을 해당 원소의 값으로 지정한다.
  3853. * @param {Function} callback 콜백 함수
  3854. * @param {Object} thisObject 콜백 함수의 this
  3855. * @return {$H} 값을 변경한 해시 객체
  3856. * @remark 콜백 함수는 형식은 예제를 참고한다.
  3857. * @example
  3858. function callback(value, key, object ) {
  3859. // value 해시의 값
  3860. // key 해시의 고유한 키 혹은 이름
  3861. // object JavaScript Core Object 객체
  3862. var r = key+"_"+value;
  3863. document.writeln (r + "<br />");
  3864. return r;
  3865. }
  3866. $H({one:"first", two:"second", three:"third"}).map(callback);
  3867. */
  3868. jindo.$H.prototype.map = function(callback, thisObject) {
  3869. var t = this._table;
  3870. this.forEach(function(v,k,o) {
  3871. t[k] = callback.call(thisObject, v, k, o);
  3872. });
  3873. return this;
  3874. };
  3875. /**
  3876. * 해시 테이블에 값을 추가한다.
  3877. * @param {String} key 추가한 값을 위한
  3878. * @param {String} value 해시 테이블에 추가할
  3879. * @return {$H} 값을 추가한 해시 객체
  3880. */
  3881. jindo.$H.prototype.add = function(key, value) {
  3882. //if (this.hasKey(key)) return null;
  3883. this._table[key] = value;
  3884. return this;
  3885. };
  3886. /**
  3887. * remove 메서드는 해시 테이블의 원소를 제거한다.
  3888. * @param {String} key 제거할 원소의
  3889. * @return {void} 제거한
  3890. * @example
  3891. var h = $H({one:"first", two:"second", three:"third"});
  3892. h.remove ("two");
  3893. // h의 해시 테이블은 {one:"first", three:"third"}
  3894. */
  3895. jindo.$H.prototype.remove = function(key) {
  3896. if (typeof this._table[key] == "undefined") return null;
  3897. var val = this._table[key];
  3898. delete this._table[key];
  3899. return val;
  3900. };
  3901. /**
  3902. * search 메서드는 해시 테이블에서 인수로 지정한 값을 찾는다.
  3903. * @param {String} value 검색할
  3904. * @returns {String | Boolean} 값을 찾았다면 값에 대한 . 값을 찾지 못했다면 false.
  3905. * @example
  3906. var h = $H({one:"first", two:"second", three:"third"});
  3907. h.search ("second");
  3908. // two
  3909. h.search ("fist");
  3910. // false
  3911. */
  3912. jindo.$H.prototype.search = function(value) {
  3913. var result = false;
  3914. this.forEach(function(v,k,o) {
  3915. if (v === value) {
  3916. result = k;
  3917. jindo.$H.Break();
  3918. }
  3919. });
  3920. return result;
  3921. };
  3922. /**
  3923. * hasKey 메서드는 해시 테이블에 인수로 지정한 키가 있는지 찾는다.
  3924. * @param {String} key 해시 테이블에서 검색할
  3925. * @return {Boolean} 키의 존재 여부
  3926. * @example
  3927. var h = $H({one:"first", two:"second", three:"third"});
  3928. h.hasKey("four"); // false
  3929. h.hasKey("one"); // true
  3930. */
  3931. jindo.$H.prototype.hasKey = function(key) {
  3932. var result = false;
  3933. return (typeof this._table[key] != "undefined");
  3934. };
  3935. /**
  3936. * hasValue 메서드는 해시 테이블에 인수로 지정한 값이 있는지 확인한다.
  3937. * @param {String} value 해시 테이블에서 검색할
  3938. * @return {Boolean} 값의 존재 여부
  3939. */
  3940. jindo.$H.prototype.hasValue = function(value) {
  3941. return (this.search(value) !== false);
  3942. };
  3943. /**
  3944. * sort 메서드는 값을 기준으로 원소를 오름차순 정렬한다.
  3945. * @return {$H} 원소를 정렬한 해시 객체.
  3946. * @see $H#ksort
  3947. * @example
  3948. var h = $H({one:"하나", two:"둘", three:"셋"});
  3949. h.sort ();
  3950. // {two:"둘", three:"셋", one:"하나"}
  3951. */
  3952. jindo.$H.prototype.sort = function() {
  3953. var o = new Object;
  3954. var a = this.values();
  3955. var k = false;
  3956. a.sort();
  3957. for(var i=0; i < a.length; i++) {
  3958. k = this.search(a[i]);
  3959. o[k] = a[i];
  3960. delete this._table[k];
  3961. }
  3962. this._table = o;
  3963. return this;
  3964. };
  3965. /**
  3966. * ksort 메서드는 키를 기준으로 원소를 오름차순 정렬한다.
  3967. * @return {$H} 원소를 정렬한 해시 객체
  3968. * @see $H#sort
  3969. * @example
  3970. var h = $H({one:"하나", two:"둘", three:"셋"});
  3971. h.sort ();
  3972. // h => {one:"하나", three:"셋", two:"둘"}
  3973. */
  3974. jindo.$H.prototype.ksort = function() {
  3975. var o = new Object;
  3976. var a = this.keys();
  3977. a.sort();
  3978. for(var i=0; i < a.length; i++) {
  3979. o[a[i]] = this._table[a[i]];
  3980. }
  3981. this._table = o;
  3982. return this;
  3983. };
  3984. /**
  3985. * keys 메서드는 해시 키의 배열을 반환한다.
  3986. * @return {Array} 해시 키의 배열
  3987. * @example
  3988. var h = $H({one:"first", two:"second", three:"third"});
  3989. h.keys ();
  3990. // ["one", "two", "three"]
  3991. * @see $H#values
  3992. */
  3993. jindo.$H.prototype.keys = function() {
  3994. var keys = new Array;
  3995. for(var k in this._table) {
  3996. if(this._table.hasOwnProperty(k))
  3997. keys.push(k);
  3998. }
  3999. return keys;
  4000. };
  4001. /**
  4002. * values 메서드는 해시 값의 배열을 반환한다.
  4003. * @return {Array} 해시 값의 배열
  4004. * @example
  4005. var h = $H({one:"first", two:"second", three:"third"});
  4006. h.values();
  4007. // ["first", "second", "third"]
  4008. * @see $H#keys
  4009. */
  4010. jindo.$H.prototype.values = function() {
  4011. var values = [];
  4012. for(var k in this._table) {
  4013. if(this._table.hasOwnProperty(k))
  4014. values[values.length] = this._table[k];
  4015. }
  4016. return values;
  4017. };
  4018. /**
  4019. * toQueryString은 해시 객체를 쿼리 스트링 형태로 만든다.
  4020. * @return {String}
  4021. * @example
  4022. var h = $H({one:"first", two:"second", three:"third"});
  4023. h.toQueryString();
  4024. // "one=first&two=second&three=third"
  4025. */
  4026. jindo.$H.prototype.toQueryString = function() {
  4027. var buf = [], val = null, idx = 0;
  4028. for(var k in this._table) {
  4029. if (this._table.hasOwnProperty(k)) {
  4030. if (typeof(val = this._table[k]) == "object" && val.constructor == Array) {
  4031. for(i=0; i < val.length; i++) {
  4032. buf[buf.length] = encodeURIComponent(k)+"[]="+encodeURIComponent(val[i]+"");
  4033. }
  4034. } else {
  4035. buf[buf.length] = encodeURIComponent(k)+"="+encodeURIComponent(this._table[k]+"");
  4036. }
  4037. }
  4038. }
  4039. return buf.join("&");
  4040. };
  4041. /**
  4042. * empty는 해시 객체를 객체로 만든다.
  4043. * @return {$H} 비워진 해시 객체
  4044. * @example
  4045. var hash = $H({a:1, b:2, c:3});
  4046. // hash => {a:1, b:2, c:3}
  4047. hash.empty();
  4048. // hash => {}
  4049. */
  4050. jindo.$H.prototype.empty = function() {
  4051. var keys = this.keys();
  4052. for(var i=0; i < keys.length; i++) {
  4053. delete this._table[keys[i]];
  4054. }
  4055. return this;
  4056. };
  4057. /**
  4058. * Break 메서드는 반복문의 실행을 중단할 사용한다.
  4059. * @remark forEach, filter, map와 같은 루프를 중단한다. 강제로 exception을 발생시키므로 try ~ catch 영역에서 메소드를 실행하면 정상적으로 동작하지 않을 있다.
  4060. * @example
  4061. $H({a:1, b:2, c:3}).forEach(function(v,k,o) {
  4062. ...
  4063. if (k == "b") $H.Break();
  4064. ...
  4065. });
  4066. * @see $H.Continue
  4067. */
  4068. jindo.$H.Break = function() {
  4069. if (!(this instanceof arguments.callee)) throw new arguments.callee;
  4070. };
  4071. /**
  4072. * Continue 메서드는 루프를 실행하다 다음 단계로 넘어갈 사용한다.
  4073. * @remark forEach, filter, map와 같은 루프 실행 도중에 현재 루프를 중단하고 다음으로 넘어간다. 강제로 exception을 발생시키므로 try ~ catch 영역에서 메소드를 실행하면 정상적으로 동작하지 않을 있다.
  4074. * @example
  4075. $H({a:1, b:2, c:3}).forEach(function(v,k,o) {
  4076. ...
  4077. if (v % 2 == 0) $H.Continue();
  4078. ...
  4079. });
  4080. * @see $H.Break
  4081. */
  4082. jindo.$H.Continue = function() {
  4083. if (!(this instanceof arguments.callee)) throw new arguments.callee;
  4084. };
  4085. /**
  4086. * @fileOverview $Json의 생성자 메서드를 정의한 파일
  4087. * @name json.js
  4088. */
  4089. /**
  4090. * $Json 객체를 리턴한다.
  4091. * @class $Json 객체는 자바스크립트에서 JSON(JavaScript Object Notation) 다루기 위한 다양한 메서드를 제공한다.
  4092. * @param {Object | String} sObject 객체, 혹은 JSON으로 인코딩 가능한 문자열.
  4093. * @return {$Json} 인수를 인코딩한 $Json 객체.
  4094. * @remark XML 형태의 문자열을 사용하여 $Json 객체를 생성하려면 $Json#fromXML 메서드를 사용한다.
  4095. * @example
  4096. var oStr = $Json ('{ zoo: "myFirstZoo", tiger: 3, zebra: 2}');
  4097. var d = {name : 'nhn', location: 'Bundang-gu'}
  4098. var oObj = $Json (d);
  4099. * @constructor
  4100. * @author Kim, Taegon
  4101. */
  4102. jindo.$Json = function (sObject) {
  4103. var cl = arguments.callee;
  4104. if (typeof sObject == "undefined") sObject = {};
  4105. if (sObject instanceof cl) return sObject;
  4106. if (!(this instanceof cl)) return new cl(sObject);
  4107. if (typeof sObject == "string") {
  4108. this._object = jindo.$Json._oldMakeJSON(sObject);
  4109. }else{
  4110. this._object = sObject;
  4111. }
  4112. }
  4113. /*
  4114. native json의 parse의 성능이 보다 좋지 못해 native json은 사용하지 않음.
  4115. jindo.$Json._makeJson = function(sObject){
  4116. if (window.JSON&&window.JSON.parse) {
  4117. jindo.$Json._makeJson = function(sObject){
  4118. if (typeof sObject == "string") {
  4119. try{
  4120. return JSON.parse(sObject);
  4121. }catch(e){
  4122. return jindo.$Json._oldMakeJSON(sObject);
  4123. }
  4124. }
  4125. return sObject;
  4126. }
  4127. }else{
  4128. jindo.$Json._makeJson = function(sObject){
  4129. if (typeof sObject == "string") {
  4130. return jindo.$Json._oldMakeJSON(sObject);
  4131. }
  4132. return sObject;
  4133. }
  4134. }
  4135. return jindo.$Json._makeJson(sObject);
  4136. }
  4137. */
  4138. jindo.$Json._oldMakeJSON = function(sObject){
  4139. try {
  4140. if(/^(?:\s*)[\{\[]/.test(sObject)){
  4141. sObject = eval("("+sObject+")");
  4142. }else{
  4143. sObject = sObject;
  4144. }
  4145. } catch(e) {
  4146. sObject = {};
  4147. }
  4148. return sObject;
  4149. }
  4150. /**
  4151. * fromXML 메서드는 XML 형태의 문자열을 $Json 객체로 인코딩한다.
  4152. * @param {String} sXML $Json 객체로 인코딩할 XML 형태의 문자열
  4153. * @returns {$Json} $Json 객체
  4154. * @remark 속성과 CDATA를 가지는 태그는 CDATA를 '$cdata' 속성과 값으로 인코딩한다.
  4155. * @example
  4156. var j1 = $Json.fromXML('<data>only string</data>');
  4157. // 결과 :
  4158. // {"data":"only string"}
  4159. var j2 = $Json.fromXML('<data><id>Faqh%$</id><str attr="123">string value</str></data>');
  4160. // 결과:
  4161. // {"data":{"id":"Faqh%$","str":{"attr":"123","$cdata":"string value"}}}
  4162. */
  4163. jindo.$Json.fromXML = function(sXML) {
  4164. var o = {};
  4165. var re = /\s*<(\/?[\w:\-]+)((?:\s+[\w:\-]+\s*=\s*(?:"(?:\\"|[^"])*"|'(?:\\'|[^'])*'))*)\s*((?:\/>)|(?:><\/\1>|\s*))|\s*<!\[CDATA\[([\w\W]*?)\]\]>\s*|\s*>?([^<]*)/ig;
  4166. var re2= /^[0-9]+(?:\.[0-9]+)?$/;
  4167. var ec = {"&amp;":"&","&nbsp;":" ","&quot;":"\"","&lt;":"<","&gt;":">"};
  4168. var fg = {tags:["/"],stack:[o]};
  4169. var es = function(s){
  4170. if (typeof s == "undefined") return "";
  4171. return s.replace(/&[a-z]+;/g, function(m){ return (typeof ec[m] == "string")?ec[m]:m; })
  4172. };
  4173. var at = function(s,c){s.replace(/([\w\:\-]+)\s*=\s*(?:"((?:\\"|[^"])*)"|'((?:\\'|[^'])*)')/g, function($0,$1,$2,$3){c[$1] = es(($2?$2.replace(/\\"/g,'"'):undefined)||($3?$3.replace(/\\'/g,"'"):undefined));}) };
  4174. var em = function(o){
  4175. for(var x in o){
  4176. if (o.hasOwnProperty(x)) {
  4177. if(Object.prototype[x])
  4178. continue;
  4179. return false;
  4180. }
  4181. };
  4182. return true
  4183. };
  4184. /*
  4185. $0 : 전체
  4186. $1 : 태그명
  4187. $2 : 속성문자열
  4188. $3 : 닫는태그
  4189. $4 : CDATA바디값
  4190. $5 : 그냥 바디값
  4191. */
  4192. var cb = function($0,$1,$2,$3,$4,$5) {
  4193. var cur, cdata = "";
  4194. var idx = fg.stack.length - 1;
  4195. if (typeof $1 == "string" && $1) {
  4196. if ($1.substr(0,1) != "/") {
  4197. var has_attr = (typeof $2 == "string" && $2);
  4198. var closed = (typeof $3 == "string" && $3);
  4199. var newobj = (!has_attr && closed)?"":{};
  4200. cur = fg.stack[idx];
  4201. if (typeof cur[$1] == "undefined") {
  4202. cur[$1] = newobj;
  4203. cur = fg.stack[idx+1] = cur[$1];
  4204. } else if (cur[$1] instanceof Array) {
  4205. var len = cur[$1].length;
  4206. cur[$1][len] = newobj;
  4207. cur = fg.stack[idx+1] = cur[$1][len];
  4208. } else {
  4209. cur[$1] = [cur[$1], newobj];
  4210. cur = fg.stack[idx+1] = cur[$1][1];
  4211. }
  4212. if (has_attr) at($2,cur);
  4213. fg.tags[idx+1] = $1;
  4214. if (closed) {
  4215. fg.tags.length--;
  4216. fg.stack.length--;
  4217. }
  4218. } else {
  4219. fg.tags.length--;
  4220. fg.stack.length--;
  4221. }
  4222. } else if (typeof $4 == "string" && $4) {
  4223. cdata = $4;
  4224. } else if (typeof $5 == "string" && $5) {
  4225. cdata = es($5);
  4226. }
  4227. if (cdata.replace(/^\s+/g, "").length > 0) {
  4228. var par = fg.stack[idx-1];
  4229. var tag = fg.tags[idx];
  4230. if (re2.test(cdata)) {
  4231. cdata = parseFloat(cdata);
  4232. }else if (cdata == "true"){
  4233. cdata = true;
  4234. }else if(cdata == "false"){
  4235. cdata = false;
  4236. }
  4237. if(typeof par =='undefined') return;
  4238. if (par[tag] instanceof Array) {
  4239. var o = par[tag];
  4240. if (typeof o[o.length-1] == "object" && !em(o[o.length-1])) {
  4241. o[o.length-1].$cdata = cdata;
  4242. o[o.length-1].toString = function(){ return cdata; }
  4243. } else {
  4244. o[o.length-1] = cdata;
  4245. }
  4246. } else {
  4247. if (typeof par[tag] == "object" && !em(par[tag])) {
  4248. par[tag].$cdata = cdata;
  4249. par[tag].toString = function(){ return cdata; }
  4250. } else {
  4251. par[tag] = cdata;
  4252. }
  4253. }
  4254. }
  4255. };
  4256. sXML = sXML.replace(/<(\?|\!-)[^>]*>/g, "");
  4257. sXML.replace(re, cb);
  4258. return jindo.$Json(o);
  4259. };
  4260. /**
  4261. * get 메서드는 path에 해당하는 $Json 객체의 값을 리턴한다.
  4262. * @param {String} sPath path 문자열
  4263. * @return {Array} 지정된 path에 해당하는 value를 원소로 가지는 배열
  4264. * @example
  4265. var j = $Json.fromXML('<data><id>Faqh%$</id><str attr="123">string value</str></data>');
  4266. var r = j.get ("/data/id");
  4267. // 결과 :
  4268. // [Faqh%$]
  4269. */
  4270. jindo.$Json.prototype.get = function(sPath) {
  4271. var o = this._object;
  4272. var p = sPath.split("/");
  4273. var re = /^([\w:\-]+)\[([0-9]+)\]$/;
  4274. var stack = [[o]], cur = stack[0];
  4275. var len = p.length, c_len, idx, buf, j, e;
  4276. for(var i=0; i < len; i++) {
  4277. if (p[i] == "." || p[i] == "") continue;
  4278. if (p[i] == "..") {
  4279. stack.length--;
  4280. } else {
  4281. buf = [];
  4282. idx = -1;
  4283. c_len = cur.length;
  4284. if (c_len == 0) return [];
  4285. if (re.test(p[i])) idx = +RegExp.$2;
  4286. for(j=0; j < c_len; j++) {
  4287. e = cur[j][p[i]];
  4288. if (typeof e == "undefined") continue;
  4289. if (e instanceof Array) {
  4290. if (idx > -1) {
  4291. if (idx < e.length) buf[buf.length] = e[idx];
  4292. } else {
  4293. buf = buf.concat(e);
  4294. }
  4295. } else if (idx == -1) {
  4296. buf[buf.length] = e;
  4297. }
  4298. }
  4299. stack[stack.length] = buf;
  4300. }
  4301. cur = stack[stack.length-1];
  4302. }
  4303. return cur;
  4304. };
  4305. /**
  4306. * toString 메서드는 $Json 객체를 JSON 문자열로 리턴한다.
  4307. * @return {String} JSON 문자열
  4308. * @example
  4309. var j = $Json({foo:1, bar: 31});
  4310. document.write (j.toString());
  4311. document.write (j);
  4312. // 결과 :
  4313. // {"bar":31,"foo":1}{"bar":31,"foo":1}
  4314. */
  4315. jindo.$Json.prototype.toString = function() {
  4316. if (window.JSON&&window.JSON.stringify) {
  4317. jindo.$Json.prototype.toString = function() {
  4318. try{
  4319. return window.JSON.stringify(this._object);
  4320. }catch(e){
  4321. return jindo.$Json._oldToString(this._object);
  4322. }
  4323. }
  4324. }else{
  4325. jindo.$Json.prototype.toString = function() {
  4326. return jindo.$Json._oldToString(this._object);
  4327. }
  4328. }
  4329. return this.toString();
  4330. };
  4331. jindo.$Json._oldToString = function(oObj){
  4332. var func = {
  4333. $ : function($) {
  4334. if (typeof $ == "object" && $ == null) return 'null';
  4335. if (typeof $ == "undefined") return '""';
  4336. if (typeof $ == "boolean") return $?"true":"false";
  4337. if (typeof $ == "string") return this.s($);
  4338. if (typeof $ == "number") return $;
  4339. if ($ instanceof Array) return this.a($);
  4340. if ($ instanceof Object) return this.o($);
  4341. },
  4342. s : function(s) {
  4343. var e = {'"':'\\"',"\\":"\\\\","\n":"\\n","\r":"\\r","\t":"\\t"};
  4344. var c = function(m){ return (typeof e[m] != "undefined")?e[m]:m };
  4345. return '"'+s.replace(/[\\"'\n\r\t]/g, c)+'"';
  4346. },
  4347. a : function(a) {
  4348. // a = a.sort();
  4349. var s = "[",c = "",n=a.length;
  4350. for(var i=0; i < n; i++) {
  4351. if (typeof a[i] == "function") continue;
  4352. s += c+this.$(a[i]);
  4353. if (!c) c = ",";
  4354. }
  4355. return s+"]";
  4356. },
  4357. o : function(o) {
  4358. o = jindo.$H(o).ksort().$value();
  4359. var s = "{",c = "";
  4360. for(var x in o) {
  4361. if (o.hasOwnProperty(x)) {
  4362. if (typeof o[x] == "function") continue;
  4363. s += c+this.s(x)+":"+this.$(o[x]);
  4364. if (!c) c = ",";
  4365. }
  4366. }
  4367. return s+"}";
  4368. }
  4369. }
  4370. return func.$(oObj);
  4371. }
  4372. /**
  4373. * toXML 메서드는 $Json 객체를 XML 형태의 문자열로 리턴한다.
  4374. * @return {String} XML 형태의 문자열
  4375. * @example
  4376. var json = $Json({foo:1, bar: 31});
  4377. json.toXML();
  4378. // 결과 :
  4379. // <foo>1</foo><bar>31</bar>
  4380. */
  4381. jindo.$Json.prototype.toXML = function() {
  4382. var f = function($,tag) {
  4383. var t = function(s,at) { return "<"+tag+(at||"")+">"+s+"</"+tag+">" };
  4384. switch (typeof $) {
  4385. case "undefined":
  4386. case "null":
  4387. return t("");
  4388. case "number":
  4389. return t($);
  4390. case "string":
  4391. if ($.indexOf("<") < 0){
  4392. return t($.replace(/&/g,"&amp;"));
  4393. }else{
  4394. return t("<![CDATA["+$+"]]>");
  4395. }
  4396. case "boolean":
  4397. return t(String($));
  4398. case "object":
  4399. var ret = "";
  4400. if ($ instanceof Array) {
  4401. var len = $.length;
  4402. for(var i=0; i < len; i++) { ret += f($[i],tag); };
  4403. } else {
  4404. var at = "";
  4405. for(var x in $) {
  4406. if ($.hasOwnProperty(x)) {
  4407. if (x == "$cdata" || typeof $[x] == "function") continue;
  4408. ret += f($[x], x);
  4409. }
  4410. }
  4411. if (tag) ret = t(ret, at);
  4412. }
  4413. return ret;
  4414. }
  4415. };
  4416. return f(this._object, "");
  4417. };
  4418. /**
  4419. * toObject 메서드는 $Json 객체 원래의 JSON 데이터 객체를 리턴한다.
  4420. * @return {Object} 원래의 데이터 객체
  4421. * @example
  4422. var json = $Json({foo:1, bar: 31});
  4423. json.toObject();
  4424. // 결과 :
  4425. // {foo: 1, bar: 31}
  4426. */
  4427. jindo.$Json.prototype.toObject = function() {
  4428. return this._object;
  4429. };
  4430. /**
  4431. * compare 메서드는 json객체 끼리 값이 같은지 비교를 한다. (1.4.4부터 사용가능.)
  4432. * @return {Boolean} 불린값.
  4433. * @example
  4434. $Json({foo:1, bar: 31}).compare({foo:1, bar: 31});
  4435. // 결과 :
  4436. // true
  4437. $Json({foo:1, bar: 31}).compare({foo:1, bar: 1});
  4438. // 결과 :
  4439. // false
  4440. */
  4441. jindo.$Json.prototype.compare = function(oData){
  4442. return jindo.$Json._oldToString(this._object).toString() == jindo.$Json._oldToString(jindo.$Json(oData).$value()).toString();
  4443. }
  4444. /**
  4445. * $value 메서드는 $Json.toObject의 별칭(Alias)이다.
  4446. * @return {Object} 원래의 데이터 객체
  4447. */
  4448. jindo.$Json.prototype.$value = jindo.$Json.prototype.toObject;
  4449. /**
  4450. * @fileOverview $Cookie의 생성자 메서드를 정의한 파일
  4451. * @name cookie.js
  4452. */
  4453. /**
  4454. * $Cookie 객체를 생성한다.
  4455. * @class $Cookie 클래스는 쿠키(Cookie) 추가, 수정, 혹은 삭제하거나 쿠키의 값을 가져온다.
  4456. * @constructor
  4457. * @return {$Cookie} 생성된 $Cookie 객체
  4458. * @author Kim, Taegon
  4459. * @example
  4460. var cookie = $Cookie();
  4461. */
  4462. jindo.$Cookie = function() {
  4463. var cl = arguments.callee;
  4464. var cached = cl._cached;
  4465. if (cl._cached) return cl._cached;
  4466. if (!(this instanceof cl)) return new cl;
  4467. if (typeof cl._cached == "undefined") cl._cached = this;
  4468. };
  4469. /**
  4470. * keys 메서드는 쿠키 이름을 원소로 가지는 배열을 리턴한다.
  4471. * @return {Array} 쿠키 이름을 원소로 가지는 배열
  4472. * @example
  4473. var cookie = $Cookie();
  4474. cookie.set("session_id1", "value1", 1);
  4475. cookie.set("session_id2", "value2", 1);
  4476. cookie.set("session_id3", "value3", 1);
  4477. document.write (cookie.keys ());
  4478. *
  4479. * // 결과 :
  4480. * // session_id1, session_id2, session_id3
  4481. */
  4482. jindo.$Cookie.prototype.keys = function() {
  4483. var ca = document.cookie.split(";");
  4484. var re = /^\s+|\s+$/g;
  4485. var a = new Array;
  4486. for(var i=0; i < ca.length; i++) {
  4487. a[a.length] = ca[i].substr(0,ca[i].indexOf("=")).replace(re, "");
  4488. }
  4489. return a;
  4490. };
  4491. /**
  4492. * get 메서드는 쿠키 이름에 해당하는 쿠키 값을 가져온다. 값이 존재하지 않는다면 null을 리턴한다.
  4493. * @param {String} sName 쿠키 이름
  4494. * @return {String} 쿠키
  4495. * @example
  4496. var cookie = $Cookie();
  4497. cookie.set("session_id1", "value1", 1);
  4498. document.write (cookie.get ("session_id1"));
  4499. *
  4500. * // 결과 :
  4501. * // value1
  4502. *
  4503. document.write (cookie.get ("session_id0"));
  4504. *
  4505. * // 결과 :
  4506. * // null
  4507. */
  4508. jindo.$Cookie.prototype.get = function(sName) {
  4509. var ca = document.cookie.split(/\s*;\s*/);
  4510. var re = new RegExp("^(\\s*"+sName+"\\s*=)");
  4511. for(var i=0; i < ca.length; i++) {
  4512. if (re.test(ca[i])) return unescape(ca[i].substr(RegExp.$1.length));
  4513. }
  4514. return null;
  4515. };
  4516. /**
  4517. * set 메서드는 쿠키 값을 설정한다.
  4518. * @param {String} sName 쿠키 이름
  4519. * @param {String} sValue 쿠키
  4520. * @param {Number} [nDays] 쿠키 유효 시간. 유효 시간은 일단위로 설정한다. 유효시간을 생략했다면 쿠키는 브라우저가 종료되면 없어진다.
  4521. * @param {String} [sDomain] 쿠키 도메인
  4522. * @param {String} [sPath] 쿠키 경로
  4523. * @return {$Cookie} $Cookie 객체
  4524. * @example
  4525. var cookie = $Cookie();
  4526. cookie.set("session_id1", "value1", 1);
  4527. cookie.set("session_id2", "value2", 1);
  4528. cookie.set("session_id3", "value3", 1);
  4529. */
  4530. jindo.$Cookie.prototype.set = function(sName, sValue, nDays, sDomain, sPath) {
  4531. var sExpire = "";
  4532. if (typeof nDays == "number") {
  4533. sExpire = ";expires="+(new Date((new Date()).getTime()+nDays*1000*60*60*24)).toGMTString();
  4534. }
  4535. if (typeof sDomain == "undefined") sDomain = "";
  4536. if (typeof sPath == "undefined") sPath = "/";
  4537. document.cookie = sName+"="+escape(sValue)+sExpire+"; path="+sPath+(sDomain?"; domain="+sDomain:"");
  4538. return this;
  4539. };
  4540. /**
  4541. * remove 메서드는 쿠키 이름에 설정된 쿠키 값을 제거한다.
  4542. * @param {String} sName 쿠키 이름
  4543. * @param {String} sDomain 쿠키 도메인
  4544. * @param {String} sPath 쿠키 경로
  4545. * @return {$Cookie} $Cookie 객체
  4546. * @example
  4547. var cookie = $Cookie();
  4548. cookie.set("session_id1", "value1", 1);
  4549. document.write (cookie.get ("session_id1"));
  4550. *
  4551. * // 결과 :
  4552. * // value1
  4553. *
  4554. cookie.remove("session_id1");
  4555. document.write (cookie.get ("session_id1"));
  4556. *
  4557. * // 결과 :
  4558. * // null
  4559. */
  4560. jindo.$Cookie.prototype.remove = function(sName, sDomain, sPath) {
  4561. if (this.get(sName) != null) this.set(sName, "", -1, sDomain, sPath);
  4562. return this;
  4563. };
  4564. /**
  4565. * @fileOverview $Element의 생성자 메서드를 정의한 파일
  4566. * @name element.js
  4567. */
  4568. /**
  4569. * $Element 객체를 생성하여 반환한다.
  4570. * @class $Element 클래스는 HTML 엘리먼트를 래핑(wrapping)하며, 엘리먼트를 다루기 위한 메서드를 제공한다.<br>
  4571. * 래핑이란 자바스크립트의 함수를 한번 감싸 본래 함수의 기능은 그대로 유지하면서 확장된 기능을 속성 형태로 제공하는 것을 말한다.
  4572. * @constructor
  4573. * @description [Lite]
  4574. * @author Kim, Taegon
  4575. *
  4576. * @param {String | HTML Element | $Element} el
  4577. * <br>
  4578. * $Element 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  4579. * <br>
  4580. * 매개 변수가 문자열이면 가지 방식으로 동작한다.<br>
  4581. * 만일 "&lt;tagName&gt;" 같은 형식의 문자열이면 tagName을 가지는 객체를 생성한다.<br>
  4582. * 이외의 경우 문자열을 id 하는 HTML 엘리먼트를 사용하여 $Element 생성한다.<br>
  4583. * <br>
  4584. * 매개 변수가 HTML 엘리먼트이면 HTML 엘리먼트를 래핑하여 $Element 생성한다.<br>
  4585. * <br>
  4586. * 매개 변수가 $Element 이면 전달된 매개 변수를 그대로 반환하며 undefined 혹은 null 경우에는 null 반환한다.
  4587. * @return {$Element} 생성된 $Element 객체
  4588. *
  4589. * @example
  4590. var element = $Element($("box")); // HTML 엘리먼트를 매개 변수로 지정
  4591. var element = $Element("box"); // HTML 엘리먼트의 id를 매개 변수로 지정
  4592. var element = $Element("<DIV>"); // 태그를 매개 변수로 지정, DIV 엘리먼트를 생성하여 래핑함
  4593. */
  4594. jindo.$Element = function(el) {
  4595. var cl = arguments.callee;
  4596. if (el && el instanceof cl) return el;
  4597. if (el===null || typeof el == "undefined"){
  4598. return null;
  4599. }else{
  4600. el = jindo.$(el);
  4601. if (el === null) {
  4602. return null;
  4603. };
  4604. }
  4605. if (!(this instanceof cl)) return new cl(el);
  4606. this._element = (typeof el == "string") ? jindo.$(el) : el;
  4607. var tag = this._element.tagName;
  4608. // tagname
  4609. this.tag = (typeof tag!='undefined')?tag.toLowerCase():'';
  4610. }
  4611. /**
  4612. * agent의 dependency를 없애기 위해 별로도 설정.
  4613. * @ignore
  4614. **/
  4615. var _j_ag = navigator.userAgent;
  4616. var IS_IE = _j_ag.indexOf("MSIE") > -1;
  4617. var IS_FF = _j_ag.indexOf("Firefox") > -1;
  4618. var IS_OP = _j_ag.indexOf("Opera") > -1;
  4619. var IS_SF = _j_ag.indexOf("Apple") > -1;
  4620. var IS_CH = _j_ag.indexOf("Chrome") > -1;
  4621. /**
  4622. * $value 메서드는 원래의 HTML 엘리먼트를 반환한다.
  4623. * @return {HTML Element} 래핑된 원래의 엘리먼트
  4624. * @description [Lite]
  4625. *
  4626. * @example
  4627. var element = $Element("sample_div");
  4628. element.$value(); // 원래의 엘리먼트가 반환된다
  4629. */
  4630. jindo.$Element.prototype.$value = function() {
  4631. return this._element;
  4632. };
  4633. /**
  4634. * HTML 엘리먼트의 display 속성을 확인하거나 display 속성을 설정하기 위해 사용한다.
  4635. *
  4636. * @param {Boolean} [bVisible] 화면에 보여줄지의 여부<br>
  4637. * 매개 변수를 생략하면 HTML 엘리먼트의 현재 display 속성을 확인하여 true/false로 반환한다.(none 이면 false)<br>
  4638. * 매개 변수가 true인 경우에는 display 속성을 설정하고 false인 경우에는 display 속성을 none 으로 변경한다.
  4639. * @param {String} [sDisplay] display 속성 <br>
  4640. * bVisible 매개 변수가 true 이면 display 속성을 전달된 매개 변수로 설정한다.
  4641. * @return {$Element} display 속성을 변경한 $Element 객체
  4642. *
  4643. * @description [Lite]
  4644. * @since 1.1.2부터 설정 기능을 사용할 있다.
  4645. * @since 1.4.5부터 bVisible 매개 변수의 값이 true 경우 sDisplay 매개 변수의 값으로 display 속성을 설정할 있다.
  4646. * @see $Element#show
  4647. * @see $Element#hide
  4648. * @see $Element#toggle
  4649. *
  4650. * @example
  4651. <div id="sample_div" style="display:none">Hello world</div>
  4652. // 조회
  4653. $Element("sample_div").visible(); // false
  4654. * @example
  4655. // 화면에 보이도록 설정
  4656. $Element("sample_div").visible(true, 'block');
  4657. //Before
  4658. <div id="sample_div" style="display:none">Hello world</div>
  4659. //After
  4660. <div id="sample_div" style="display:block">Hello world</div>
  4661. */
  4662. jindo.$Element.prototype.visible = function(bVisible, sDisplay) {
  4663. if (typeof bVisible != "undefined") {
  4664. this[bVisible?"show":"hide"](sDisplay);
  4665. return this;
  4666. }
  4667. return (this.css("display") != "none");
  4668. };
  4669. /**
  4670. * HTML 엘리먼트가 화면에 보이도록 display 속성을 변경한다.
  4671. * @param {String} [sDisplay] 변경할 display 속성 <br>
  4672. * 매개 변수를 생략하면 태그별로 미리 지정된 디폴트 속성 값으로 설정한다.<br>
  4673. * 미리 지정된 디폴트 속성 값이 없으면 "inline" 으로 설정한다.
  4674. * @return {$Element} display 속성을 변경한 $Element 객체
  4675. * @description [Lite]
  4676. * @see $Element#hide
  4677. * @see $Element#toggle
  4678. * @see $Element#visible
  4679. * @since 1.4.5부터 sDisplay 값으로 display 속성 지정이 가능하다.
  4680. *
  4681. * @example
  4682. // 화면에 보이도록 설정
  4683. $Element("sample_div").show();
  4684. //Before
  4685. <div id="sample_div" style="display:none">Hello world</div>
  4686. //After
  4687. <div id="sample_div" style="display:block">Hello world</div>
  4688. */
  4689. jindo.$Element.prototype.show = function(sDisplay) {
  4690. var s = this._element.style;
  4691. var b = "block";
  4692. var c = { p:b,div:b,form:b,h1:b,h2:b,h3:b,h4:b,ol:b,ul:b,fieldset:b,td:"table-cell",th:"table-cell",
  4693. li:"list-item",table:"table",thead:"table-header-group",tbody:"table-row-group",tfoot:"table-footer-group",
  4694. tr:"table-row",col:"table-column",colgroup:"table-column-group",caption:"table-caption",dl:b,dt:b,dd:b};
  4695. try {
  4696. if (sDisplay) {
  4697. s.display = sDisplay;
  4698. }else{
  4699. var type = c[this.tag];
  4700. s.display = type || "inline";
  4701. }
  4702. } catch(e) {
  4703. /*
  4704. IE에서 sDisplay값이 비정상적일때 block로 셋팅한다.
  4705. */
  4706. s.display = "block";
  4707. }
  4708. return this;
  4709. };
  4710. /**
  4711. * HTML 엘리먼트가 화면에 보이지 않도록 display 속성을 none 으로 변경한다.
  4712. * @returns {$Element} display 속성을 변경한 $Element 객체
  4713. * @description [Lite]
  4714. * @see $Element#show
  4715. * @see $Element#toggle
  4716. * @see $Element#visible
  4717. *
  4718. * @example
  4719. // 화면에 보이지 않도록 설정
  4720. $Element("sample_div").hide();
  4721. //Before
  4722. <div id="sample_div" style="display:block">Hello world</div>
  4723. //After
  4724. <div id="sample_div" style="display:none">Hello world</div>
  4725. */
  4726. jindo.$Element.prototype.hide = function() {
  4727. this._element.style.display = "none";
  4728. return this;
  4729. };
  4730. /**
  4731. * HTML 엘리먼트의 display 속성을 변경하여 엘리먼트를 화면에 보이거나, 보이지 않게 한다.
  4732. * @param {String} [sDisplay] 보이도록 변경할 사용되는 display 속성
  4733. * @returns {$Element} display 속성을 변경한 $Element 객체
  4734. * @description [Lite]
  4735. * @see $Element#show
  4736. * @see $Element#hide
  4737. * @see $Element#visible
  4738. * @since 1.4.5부터 보이도록 설정할 sDisplay 값으로 display 속성 지정이 가능하다.
  4739. * @example
  4740. // 화면에 보이거나, 보이지 않도록 처리
  4741. $Element("sample_div1").toggle();
  4742. $Element("sample_div2").toggle();
  4743. //Before
  4744. <div id="sample_div1" style="display:block">Hello</div>
  4745. <div id="sample_div2" style="display:none">Good Bye</div>
  4746. //After
  4747. <div id="sample_div1" style="display:none">Hello</div>
  4748. <div id="sample_div2" style="display:block">Good Bye</div>
  4749. */
  4750. jindo.$Element.prototype.toggle = function(sDisplay) {
  4751. this[this.visible()?"hide":"show"](sDisplay);
  4752. return this;
  4753. };
  4754. /**
  4755. * HTML 엘리먼트의 투명도 값을 가져오거나 설정한다.
  4756. * @param {Number} [value] 설정할 투명도 <br>
  4757. * 투명도 값은 0 ~ 1 사이의 실수 값으로 지정한다.<br>
  4758. * 매개 변수의 값이 0보다 작으면 0, 1보다 크면 1 설정한다.
  4759. * @return {Number} HTML 엘리먼트의 투명도
  4760. * @description [Lite]
  4761. *
  4762. * @example
  4763. <div id="sample" style="background-color:#2B81AF; width:20px; height:20px;"></div>
  4764. // 조회
  4765. $Element("sample").opacity(); // 1
  4766. * @example
  4767. // 투명도 값 설정
  4768. $Element("sample").opacity(0.4);
  4769. //Before
  4770. <div style="background-color: rgb(43, 129, 175); width: 20px; height: 20px;" id="sample"></div>
  4771. //After
  4772. <div style="background-color: rgb(43, 129, 175); width: 20px; height: 20px; opacity: 0.4;" id="sample"></div>
  4773. */
  4774. jindo.$Element.prototype.opacity = function(value) {
  4775. var v,e = this._element,b = (this._getCss(e,"display") != "none");
  4776. value = parseFloat(value);
  4777. /*
  4778. IE에서 layout을 가지고 있지 않으면 opacity가 적용되지 않음.
  4779. */
  4780. e.style.zoom = 1;
  4781. if (!isNaN(value)) {
  4782. value = Math.max(Math.min(value,1),0);
  4783. if (typeof e.filters != "undefined") {
  4784. value = Math.ceil(value*100);
  4785. if (typeof e.filters != 'unknown' && typeof e.filters.alpha != "undefined") {
  4786. e.filters.alpha.opacity = value;
  4787. } else {
  4788. e.style.filter = (e.style.filter + " alpha(opacity=" + value + ")");
  4789. }
  4790. } else {
  4791. e.style.opacity = value;
  4792. }
  4793. return value;
  4794. }
  4795. if (typeof e.filters != "undefined") {
  4796. v = (typeof e.filters.alpha == "undefined")?(b?100:0):e.filters.alpha.opacity;
  4797. v = v / 100;
  4798. } else {
  4799. v = parseFloat(e.style.opacity);
  4800. if (isNaN(v)) v = b?1:0;
  4801. }
  4802. return v;
  4803. };
  4804. /**
  4805. * HTML 엘리먼트의 CSS 속성 값을 가져오거나 설정한다.
  4806. * @remark CSS 속성은 Camel 표기법을 사용한다. 따라서 border-width-bottom은 borderWidthBottom으로 정의한다.
  4807. * @remark float 속성은 Javascript의 예약어로 사용하므로 css 메서드에서는 float 대신 cssFloat를 사용한다. (Internet Explorer에서는 styleFloat를, 외의 브라우저에서는 cssFloat를 사용한다.)
  4808. * @param {String | Object | $H} sName CSS 속성명 혹은 하나 이상의 CSS 속성과 값을 가지는 객체.<br>
  4809. * css 메서드는 문자열, Object, 혹은 $H 매개 변수로 지정할 있다.<br>
  4810. * <br>
  4811. * 매개 변수가 문자열이면 조회 혹은 수정할 속성 명으로 아래 가지 방식으로 동작한다.<br>
  4812. * 번째 매개 변수인 sValue 매개 변수를 생략하면 CSS 속성의 값을 가져온다.<br>
  4813. * 번째 매개 변수인 sValue 매개 변수에 값이 있으면 CSS 속성의 값을 sValue 값으로 설정한다.<br>
  4814. * <br>
  4815. * Object 혹은 $H 객체를 사용하면 이상의 CSS 속성을 한꺼번에 설정할 있다.<br>
  4816. * 객체의 프로퍼티 이름으로 CSS 속성을 찾아 프로퍼티 값으로 설정한다.
  4817. * @param {String | Number} [sValue] CSS 속성에 설정할 .<br>
  4818. * 단위가 필요한 값은 숫자 혹은 단위를 포함한 문자열을 사용한다.
  4819. * @return {String | $Element} 값을 가져올 때는 값을 문자열로 반환하고, 값을 설정할 때는 값을 설정한 현재의 $Element 반환한다.
  4820. * @description [Lite]
  4821. * @example
  4822. <style type="text/css">
  4823. #btn {
  4824. width: 120px;
  4825. height: 30px;
  4826. background-color: blue;
  4827. }
  4828. </style>
  4829. <span id="btn"></span>
  4830. ...
  4831. // CSS 속성 값 조회
  4832. $Element('btn').css('backgroundColor'); // rgb (0, 0, 255)
  4833. * @example
  4834. // CSS 속성 값 설정
  4835. $Element('btn').css('backgroundColor', 'red');
  4836. //Before
  4837. <span id="btn"></span>
  4838. //After
  4839. <span id="btn" style="background-color: red;"></span>
  4840. * @example
  4841. // 여러개의 CSS 속성 값을 설정
  4842. $Element('btn').css({
  4843. width: "200px", // 200
  4844. height: "80px" // 80 으로 설정하여도 결과는 같음
  4845. });
  4846. //Before
  4847. <span id="btn" style="background-color: red;"></span>
  4848. //After
  4849. <span id="btn" style="background-color: red; width: 200px; height: 80px;"></span>
  4850. */
  4851. jindo.$Element.prototype.css = function(sName, sValue) {
  4852. var e = this._element;
  4853. var type_v = (typeof sValue);
  4854. if (sName == 'opacity') return type_v == 'undefined' ? this.opacity() : this.opacity(sValue);
  4855. var type_n = (typeof sName);
  4856. if (type_n == "string") {
  4857. var view;
  4858. if (type_v == "string" || type_v == "number") {
  4859. var obj = {};
  4860. obj[sName] = sValue;
  4861. sName = obj;
  4862. } else {
  4863. var _getCss = this._getCss;
  4864. if((IS_FF||IS_OP)&&(sName=="backgroundPositionX"||sName=="backgroundPositionY")){
  4865. var bp = _getCss(e, "backgroundPosition").split(/\s+/);
  4866. return (sName == "backgroundPositionX") ? bp[0] : bp[1];
  4867. }
  4868. if (IS_IE && sName == "backgroundPosition") {
  4869. return _getCss(e, "backgroundPositionX") + " " + _getCss(e, "backgroundPositionY")
  4870. }
  4871. if ((IS_FF||IS_SF||IS_CH) && (sName=="padding"||sName=="margin")) {
  4872. var top = _getCss(e, sName+"Top");
  4873. var right = _getCss(e, sName+"Right");
  4874. var bottom = _getCss(e, sName+"Bottom");
  4875. var left = _getCss(e, sName+"Left");
  4876. if ((top == right) && (bottom == left)) {
  4877. return top;
  4878. }else if (top == bottom) {
  4879. if (right == left) {
  4880. return top+" "+right;
  4881. }else{
  4882. return top+" "+right+" "+bottom+" "+left;
  4883. }
  4884. }else{
  4885. return top+" "+right+" "+bottom+" "+left;
  4886. }
  4887. }
  4888. return _getCss(e, sName);
  4889. }
  4890. }
  4891. var h = jindo.$H;
  4892. if (typeof h != "undefined" && sName instanceof h) {
  4893. sName = sName._table;
  4894. }
  4895. if (typeof sName == "object") {
  4896. var v, type;
  4897. for(var k in sName) {
  4898. if(sName.hasOwnProperty(k)){
  4899. v = sName[k];
  4900. type = (typeof v);
  4901. if (type != "string" && type != "number") continue;
  4902. if (k == 'opacity') {
  4903. type == 'undefined' ? this.opacity() : this.opacity(v);
  4904. continue;
  4905. }
  4906. if (k == "cssFloat" && IS_IE) k = "styleFloat";
  4907. if((IS_FF||IS_OP)&&( k =="backgroundPositionX" || k == "backgroundPositionY")){
  4908. var bp = this.css("backgroundPosition").split(/\s+/);
  4909. v = k == "backgroundPositionX" ? v+" "+bp[1] : bp[0]+" "+v;
  4910. this._setCss(e, "backgroundPosition", v);
  4911. }else{
  4912. this._setCss(e, k, v);
  4913. }
  4914. }
  4915. }
  4916. }
  4917. return this;
  4918. };
  4919. /**
  4920. * css에서 사용되는 함수
  4921. * @ignore
  4922. * @param {Element} e
  4923. * @param {String} sName
  4924. */
  4925. jindo.$Element.prototype._getCss = function(e, sName){
  4926. var fpGetCss;
  4927. if (e.currentStyle) {
  4928. fpGetCss = function(e, sName){
  4929. try{
  4930. if (sName == "cssFloat") sName = "styleFloat";
  4931. var sStyle = e.style[sName];
  4932. if(sStyle){
  4933. return sStyle;
  4934. }else{
  4935. var oCurrentStyle = e.currentStyle;
  4936. if (oCurrentStyle) {
  4937. return oCurrentStyle[sName];
  4938. }
  4939. }
  4940. return sStyle;
  4941. }catch(ex){
  4942. throw new Error((e.tagName||"document") + "는 css를 사용 할수 없습니다.");
  4943. }
  4944. }
  4945. } else if (window.getComputedStyle) {
  4946. fpGetCss = function(e, sName){
  4947. try{
  4948. if (sName == "cssFloat") sName = "float";
  4949. var d = e.ownerDocument || e.document || document;
  4950. var sVal = (e.style[sName]||d.defaultView.getComputedStyle(e,null).getPropertyValue(sName.replace(/([A-Z])/g,"-$1").toLowerCase()));
  4951. if (sName == "textDecoration") sVal = sVal.replace(",","");
  4952. return sVal;
  4953. }catch(ex){
  4954. throw new Error((e.tagName||"document") + "는 css를 사용 할수 없습니다.");
  4955. }
  4956. }
  4957. } else {
  4958. fpGetCss = function(e, sName){
  4959. try{
  4960. if (sName == "cssFloat" && IS_IE) sName = "styleFloat";
  4961. return e.style[sName];
  4962. }catch(ex){
  4963. throw new Error((e.tagName||"document") + "는 css를 사용 할수 없습니다.");
  4964. }
  4965. }
  4966. }
  4967. jindo.$Element.prototype._getCss = fpGetCss;
  4968. return fpGetCss(e, sName);
  4969. }
  4970. /**
  4971. * css에서 css를 세팅하기 위한 함수
  4972. * @ignore
  4973. * @param {Element} e
  4974. * @param {String} k
  4975. */
  4976. jindo.$Element.prototype._setCss = function(e, k, v){
  4977. if (("#top#left#right#bottom#").indexOf(k+"#") > 0 && (typeof v == "number" ||(/\d$/.test(v)))) {
  4978. e.style[k] = parseInt(v,10)+"px";
  4979. }else{
  4980. e.style[k] = v;
  4981. }
  4982. }
  4983. /**
  4984. * DOM 엘리먼트의 HTML 속성을 가져오거나 설정한다.
  4985. * 하나의 인자만 사용하면 해당 HTML 속성의 속성 값을 가져온다. 해당 속성이 없다면 null을 반환한다.
  4986. * 개의 인자를 사용하면 번째 인자에 해당하는 HTML 속성의 속성 값을 번째 인자의 값으로 설정한다.
  4987. * 번째 인자로 Object 혹은 $H 객체를 사용하면 이상의 HTML 속성을 한꺼번에 정의할 있다.
  4988. * @param {String|Object|$H} sName HTML 속성 이름 혹은 설정값 객체
  4989. * @param {String|Number} [sValue] 설정 . 설정 값을 null로 지정하면 해당 HTML 속성을 삭제한다.
  4990. * @return {String|$Element} 값을 가져올 때는 String 설정 값을, 값을 설정할 때는 값을 설정한 현재의 $Element를 리턴한다.
  4991. * @description [Lite]
  4992. *
  4993. * @example
  4994. <a href="http://www.naver.com" id="sample_a" target="_blank">Naver</a>
  4995. $Element("sample_a").attr("href"); // http://www.naver.com
  4996. * @example
  4997. $Element("sample_a").attr("href", "http://www.hangame.com/");
  4998. //Before
  4999. <a href="http://www.naver.com" id="sample_a" target="_blank">Naver</a>
  5000. //After
  5001. <a href="http://www.hangame.com" id="sample_a" target="_blank">Naver</a>
  5002. * @example
  5003. $Element("sample_a").attr({
  5004. "href" : "http://www.hangame.com",
  5005. "target" : "_self"
  5006. })
  5007. //Before
  5008. <a href="http://www.naver.com" id="sample_a" target="_blank">Naver</a>
  5009. //After
  5010. <a href="http://www.hangame.com" id="sample_a" target="_self">Naver</a>
  5011. */
  5012. jindo.$Element.prototype.attr = function(sName, sValue) {
  5013. var e = this._element;
  5014. if (typeof sName == "string") {
  5015. if (typeof sValue != "undefined") {
  5016. var obj = {};
  5017. obj[sName] = sValue;
  5018. sName = obj;
  5019. } else {
  5020. if (sName == "class" || sName == "className"){
  5021. return e.className;
  5022. }else if(sName == "style"){
  5023. return e.style.cssText;
  5024. }else if(sName == "checked"||sName == "disabled"){
  5025. return !!e[sName];
  5026. }else if(sName == "value"){
  5027. return e.value;
  5028. }else if(sName == "href"){
  5029. return e.getAttribute(sName,2);
  5030. }
  5031. return e.getAttribute(sName);
  5032. }
  5033. }
  5034. if (typeof jindo.$H != "undefined" && sName instanceof jindo.$H) {
  5035. sName = sName.$value();
  5036. }
  5037. if (typeof sName == "object") {
  5038. for(var k in sName) {
  5039. if(sName.hasOwnProperty(k)){
  5040. if (typeof(sValue) != "undefined" && sValue === null) {
  5041. e.removeAttribute(k);
  5042. }else{
  5043. if (k == "class"|| k == "className") {
  5044. e.className = sName[k];
  5045. }else if(k == "style"){
  5046. e.style.cssText = sName[k];
  5047. }else if(k == "checked"||k == "disabled"){
  5048. e[k] = sName[k];
  5049. }else if(k == "value"){
  5050. e.value = sName[k];
  5051. }else{
  5052. e.setAttribute(k, sName[k]);
  5053. }
  5054. }
  5055. }
  5056. }
  5057. }
  5058. return this;
  5059. };
  5060. /**
  5061. * HTML 엘리먼트의 너비를 가져오거나 설정한다.
  5062. * @remark width 메서드는 HTML 엘리먼트의 실제 너비를 가져온다. 브라우저마다 Box 모델의 크기 계산 방법이 다르므로 CSS의 width 속성 값과 width 메서드의 반환 값은 서로 다를 있다.
  5063. * @param {Number} [width] 설정할 너비 . 단위는 px 이며 매개 변수의 값은 숫자로 지정한다.<br>
  5064. * 매개 변수를 생략하면 너비 값을 가져온다.
  5065. * @return {Number | $Element} 값을 가져오는 경우에는 HTML 엘리먼트의 실제 너비를, 값을 설정하는 경우에는 너비 값이 변경된 현재의 $Element 객체를 반환한다.
  5066. * @description [Lite]
  5067. * @see $Element#height
  5068. *
  5069. * @example
  5070. <style type="text/css">
  5071. div { width:70px; height:50px; padding:5px; margin:5px; background:red; }
  5072. </style>
  5073. <div id="sample_div"></div>
  5074. ...
  5075. // 조회
  5076. $Element("sample_div").width(); // 80
  5077. * @example
  5078. // 위의 예제 HTML 엘리먼트에 너비 값을 설정
  5079. $Element("sample_div").width(200);
  5080. //Before
  5081. <div id="sample_div"></div>
  5082. //After
  5083. <div id="sample_div" style="width: 190px"></div>
  5084. */
  5085. jindo.$Element.prototype.width = function(width) {
  5086. if (typeof width == "number") {
  5087. var e = this._element;
  5088. e.style.width = width+"px";
  5089. var off = e.offsetWidth;
  5090. if (off != width && off!==0) {
  5091. var w = (width*2 - off);
  5092. if (w>0)
  5093. e.style.width = w + "px";
  5094. }
  5095. return this;
  5096. }
  5097. return this._element.offsetWidth;
  5098. };
  5099. /**
  5100. * HTML 엘리먼트의 높이를 가져오거나 설정한다.
  5101. * @remark height 메서드는 HTML 엘리먼트의 실제 높이를 가져온다. 브라우저마다 Box 모델의 크기 계산 방법이 다르므로 CSS의 height 속성 값과 height 메서드의 반환 값은 서로 다를 있다.
  5102. * @param {Number} [height] 설정할 높이 . 단위는 px 이며 매개 변수의 값은 숫자로 지정한다.
  5103. * @return {Number | $Element} 값을 가져오는 경우에는 HTML 엘리먼트의 실제 높이를, 값을 설정하는 경우에는 높이 값이 변경된 현재의 $Element 객체를 반환한다.
  5104. * @description [Lite]
  5105. * @see $Element#width
  5106. *
  5107. * @example
  5108. <style type="text/css">
  5109. div { width:70px; height:50px; padding:5px; margin:5px; background:red; }
  5110. </style>
  5111. <div id="sample_div"></div>
  5112. ...
  5113. // 조회
  5114. $Element("sample_div").height(); // 60
  5115. * @example
  5116. // 위의 예제 HTML 엘리먼트에 높이 값을 설정
  5117. $Element("sample_div").height(100);
  5118. //Before
  5119. <div id="sample_div"></div>
  5120. //After
  5121. <div id="sample_div" style="height: 90px"></div>
  5122. */
  5123. jindo.$Element.prototype.height = function(height) {
  5124. if (typeof height == "number") {
  5125. var e = this._element;
  5126. e.style.height = height+"px";
  5127. var off = e.offsetHeight;
  5128. if (off != height && off!==0) {
  5129. var height = (height*2 - off);
  5130. if(height>0)
  5131. e.style.height = height + "px";
  5132. }
  5133. return this;
  5134. }
  5135. return this._element.offsetHeight;
  5136. };
  5137. /**
  5138. * HTML 엘리먼트의 클래스명을 설정하거나 반환한다.
  5139. * @param {String} [sClass] 설정할 클래스명<br>
  5140. * 매개 변수를 생략하면 HTML 엘리먼트의 현재의 클래스명을 반환한다.<br>
  5141. * 매개 변수를 지정하면 클래스명을 설정한다. 여러개의 클래스명을 설정하려면 공백으로 구분한다.
  5142. * @return {String | $Element} 클래스명을 조회하는 경우에는 클래스명을 반환한다.<br>
  5143. * 클래스가 이상이면 클래스명을 공백으로 구분하여 공백을 포함한 문자열로 반환한다.<br>
  5144. * 클래스명을 설정한 경우에는 변경된 현재의 $Element 객체를 반환한다.
  5145. * @description [Lite]
  5146. * @see $Element#hasClass
  5147. * @see $Element#addClass
  5148. * @see $Element#removeClass
  5149. * @see $Element#toggleClass
  5150. *
  5151. * @example
  5152. <style type="text/css">
  5153. p { margin: 8px; font-size:16px; }
  5154. .selected { color:#0077FF; }
  5155. .highlight { background:#C6E746; }
  5156. </style>
  5157. <p>Hello and <span id="sample_span" class="selected">Goodbye</span></p>
  5158. ...
  5159. // 클래스명 조회
  5160. $Element("sample_span").className(); // selected
  5161. * @example
  5162. // 위의 예제 HTML 엘리먼트에 클래스명 설정
  5163. welSample.className("highlight");
  5164. //Before
  5165. <p>Hello and <span id="sample_span" class="selected">Goodbye</span></p>
  5166. //After
  5167. <p>Hello and <span id="sample_span" class="highlight">Goodbye</span></p>
  5168. */
  5169. jindo.$Element.prototype.className = function(sClass) {
  5170. var e = this._element;
  5171. if (typeof sClass == "undefined") return e.className;
  5172. e.className = sClass;
  5173. return this;
  5174. };
  5175. /**
  5176. * HTML 엘리먼트에서 특정 클래스를 사용하고 있는지 확인한다.
  5177. * @param {String} sClass 확인할 클래스명
  5178. * @return {Boolean} 클래스 사용 여부
  5179. * @description [Lite]
  5180. * @see $Element#className
  5181. * @see $Element#addClass
  5182. * @see $Element#removeClass
  5183. * @see $Element#toggleClass
  5184. *
  5185. * @example
  5186. <style type="text/css">
  5187. p { margin: 8px; font-size:16px; }
  5188. .selected { color:#0077FF; }
  5189. .highlight { background:#C6E746; }
  5190. </style>
  5191. <p>Hello and <span id="sample_span" class="selected highlight">Goodbye</span></p>
  5192. ...
  5193. // 클래스의 사용여부를 확인
  5194. var welSample = $Element("sample_span");
  5195. welSample.hasClass("selected"); // true
  5196. welSample.hasClass("highlight"); // true
  5197. */
  5198. jindo.$Element.prototype.hasClass = function(sClass) {
  5199. if(this._element.classList){
  5200. jindo.$Element.prototype.hasClass = function(sClass){
  5201. return this._element.classList.contains(sClass);
  5202. }
  5203. } else {
  5204. jindo.$Element.prototype.hasClass = function(sClass){
  5205. return (" "+this._element.className+" ").indexOf(" "+sClass+" ") > -1;
  5206. }
  5207. }
  5208. return this.hasClass(sClass);
  5209. };
  5210. /**
  5211. * HTML 엘리먼트에 클래스를 추가한다.
  5212. * @param {String} sClass 추가할 클래스명. 여러개의 클래스명을 추가하려면 공백으로 구분한다.
  5213. * @return {$Element} 클래스가 추가된 현재의 $Element 객체
  5214. * @description [Lite]
  5215. * @see $Element#className
  5216. * @see $Element#hasClass
  5217. * @see $Element#removeClass
  5218. * @see $Element#toggleClass
  5219. *
  5220. * @example
  5221. // 클래스 추가
  5222. $Element("sample_span1").addClass("selected");
  5223. $Element("sample_span2").addClass("selected highlight");
  5224. //Before
  5225. <p>Hello and <span id="sample_span1">Goodbye</span></p>
  5226. <p>Hello and <span id="sample_span2">Goodbye</span></p>
  5227. //After
  5228. <p>Hello and <span id="sample_span1" class="selected">Goodbye</span></p>
  5229. <p>Hello and <span id="sample_span2" class="selected highlight">Goodbye</span></p>
  5230. */
  5231. jindo.$Element.prototype.addClass = function(sClass) {
  5232. if(this._element.classList){
  5233. jindo.$Element.prototype.addClass = function(sClass){
  5234. var aClass = sClass.split(/\s+/);
  5235. var flistApi = this._element.classList;
  5236. for(var i = aClass.length ; i-- ;){
  5237. flistApi.add(aClass[i]);
  5238. }
  5239. return this;
  5240. }
  5241. } else {
  5242. jindo.$Element.prototype.addClass = function(sClass){
  5243. var e = this._element;
  5244. var aClass = sClass.split(/\s+/);
  5245. var eachClass;
  5246. for (var i = aClass.length - 1; i >= 0 ; i--){
  5247. eachClass = aClass[i];
  5248. if (!this.hasClass(eachClass)) {
  5249. e.className = (e.className+" "+eachClass).replace(/^\s+/, "");
  5250. };
  5251. };
  5252. return this;
  5253. }
  5254. }
  5255. return this.addClass(sClass);
  5256. };
  5257. /**
  5258. * HTML 엘리먼트에서 특정 클래스를 제거한다.
  5259. * @param {String} sClass 제거할 클래스명. 여러개의 클래스명을 제거하려면 공백으로 구분한다.
  5260. * @return {$Element} 클래스가 제거된 현재의 $Element 객체
  5261. * @description [Lite]
  5262. * @see $Element#className
  5263. * @see $Element#hasClass
  5264. * @see $Element#addClass
  5265. * @see $Element#toggleClass
  5266. *
  5267. * @example
  5268. // 클래스 제거
  5269. $Element("sample_span").removeClass("selected");
  5270. //Before
  5271. <p>Hello and <span id="sample_span" class="selected highlight">Goodbye</span></p>
  5272. //After
  5273. <p>Hello and <span id="sample_span" class="highlight">Goodbye</span></p>
  5274. * @example
  5275. // 여러개의 클래스를 제거
  5276. $Element("sample_span").removeClass("selected highlight");
  5277. $Element("sample_span").removeClass("highlight selected");
  5278. //Before
  5279. <p>Hello and <span id="sample_span" class="selected highlight">Goodbye</span></p>
  5280. //After
  5281. <p>Hello and <span id="sample_span" class="">Goodbye</span></p>
  5282. */
  5283. jindo.$Element.prototype.removeClass = function(sClass) {
  5284. if(this._element.classList){
  5285. jindo.$Element.prototype.removeClass = function(sClass){
  5286. var flistApi = this._element.classList;
  5287. var aClass = sClass.split(" ");
  5288. for(var i = aClass.length ; i-- ;){
  5289. flistApi.remove(aClass[i]);
  5290. }
  5291. return this;
  5292. }
  5293. } else {
  5294. jindo.$Element.prototype.removeClass = function(sClass){
  5295. var e = this._element;
  5296. var aClass = sClass.split(/\s+/);
  5297. var eachClass;
  5298. for (var i = aClass.length - 1; i >= 0 ; i--){
  5299. eachClass = aClass[i];
  5300. if (this.hasClass(eachClass)) {
  5301. e.className = (" "+e.className.replace(/\s+$/, "").replace(/^\s+/, "")+" ").replace(" "+eachClass+" ", " ").replace(/\s+$/, "").replace(/^\s+/, "");
  5302. };
  5303. };
  5304. return this;
  5305. }
  5306. }
  5307. return this.removeClass(sClass);
  5308. };
  5309. /**
  5310. * HTML 엘리먼트에 클래스가 이미 적용되어 있으면 제거하고 만약 없으면 추가한다.
  5311. * @param {String} sClass 추가 혹은 제거할 클래스명
  5312. * @param {String} [sClass2] 추가 혹은 제거할 클래스명<br>
  5313. * sClass2 매개 변수를 생략하면 HTML 엘리먼트에서 sClass 매개 변수 값의 클래스를 사용 중인지 확인한다.<br>
  5314. * 만약 사용하고 있다면 해당 클래스를 제거하고, 사용하고 있지 않다면 추가한다.<br>
  5315. * 개의 매개 변수를 모두 사용하면, 클래스 중에서 사용하고 있는 것을 제거하고 나머지를 추가한다.
  5316. * @return {$Element} 클래스가 추가 혹은 제거된 현재의 $Element 객체
  5317. * @import core.$Element[hasClass,addClass,removeClass]
  5318. * @description [Lite]
  5319. * @see $Element#className
  5320. * @see $Element#hasClass
  5321. * @see $Element#addClass
  5322. * @see $Element#removeClass
  5323. *
  5324. * @example
  5325. // 매개 변수가 하나인 경우
  5326. $Element("sample_span1").toggleClass("highlight");
  5327. $Element("sample_span2").toggleClass("highlight");
  5328. //Before
  5329. <p>Hello and <span id="sample_span1" class="selected highlight">Goodbye</span></p>
  5330. <p>Hello and <span id="sample_span2" class="selected">Goodbye</span></p>
  5331. //After
  5332. <p>Hello and <span id="sample_span1" class="selected">Goodbye</span></p>
  5333. <p>Hello and <span id="sample_span2" class="selected highlight">Goodbye</span></p>
  5334. * @example
  5335. // 매개 변수가 두 개인 경우
  5336. $Element("sample_span1").toggleClass("selected", "highlight");
  5337. $Element("sample_span2").toggleClass("selected", "highlight");
  5338. //Before
  5339. <p>Hello and <span id="sample_span1" class="highlight">Goodbye</span></p>
  5340. <p>Hello and <span id="sample_span2" class="selected">Goodbye</span></p>
  5341. //After
  5342. <p>Hello and <span id="sample_span1" class="selected">Goodbye</span></p>
  5343. <p>Hello and <span id="sample_span2" class="highlight">Goodbye</span></p>
  5344. */
  5345. jindo.$Element.prototype.toggleClass = function(sClass, sClass2) {
  5346. if(this._element.classList){
  5347. jindo.$Element.prototype.toggleClass = function(sClass, sClass2){
  5348. if (typeof sClass2 == "undefined") {
  5349. this._element.classList.toggle(sClass);
  5350. } else {
  5351. if(this.hasClass(sClass)){
  5352. this.removeClass(sClass);
  5353. this.addClass(sClass2);
  5354. }else{
  5355. this.addClass(sClass);
  5356. this.removeClass(sClass2);
  5357. }
  5358. }
  5359. return this;
  5360. }
  5361. } else {
  5362. jindo.$Element.prototype.toggleClass = function(sClass, sClass2){
  5363. sClass2 = sClass2 || "";
  5364. if (this.hasClass(sClass)) {
  5365. this.removeClass(sClass);
  5366. if (sClass2) this.addClass(sClass2);
  5367. } else {
  5368. this.addClass(sClass);
  5369. if (sClass2) this.removeClass(sClass2);
  5370. }
  5371. return this;
  5372. }
  5373. }
  5374. return this.toggleClass(sClass, sClass2);
  5375. };
  5376. /**
  5377. * HTML 엘리먼트의 텍스트 노드 값을 가져오거나 설정한다.
  5378. * @param {String} [sText] 설정할 텍스트<br>
  5379. * 매개 변수를 생략하면 텍스트 노드를 조회하고, 매개 변수를 지정하면 매개 변수의 값으로 텍스트 노드를 설정한다.
  5380. * @returns {String} 값을 조회하는 경우에는 HTML 엘리먼트의 텍스트 노드를 반환하고,<br>
  5381. * 값을 설정하는 경우에는 텍스트 노드를 설정한 현재의 $Element 객체를 반환
  5382. * @description [Lite]
  5383. *
  5384. * @example
  5385. <ul id="sample_ul">
  5386. <li>하나</li>
  5387. <li></li>
  5388. <li></li>
  5389. <li></li>
  5390. </ul>
  5391. ...
  5392. // 텍스트 노드 값 조회
  5393. $Element("sample_ul").text();
  5394. // 결과
  5395. // 하나
  5396. // 둘
  5397. // 셋
  5398. // 넷
  5399. @example
  5400. // 텍스트 노드 값 설정
  5401. $Element("sample_ul").text('다섯');
  5402. //Before
  5403. <ul id="sample_ul">
  5404. <li>하나</li>
  5405. <li></li>
  5406. <li></li>
  5407. <li></li>
  5408. </ul>
  5409. //After
  5410. <ul id="sample_ul">다섯</ul>
  5411. @example
  5412. // 텍스트 노드 값 설정
  5413. $Element("sample_p").text("New Content");
  5414. //Before
  5415. <p id="sample_p">
  5416. Old Content
  5417. </p>
  5418. //After
  5419. <p id="sample_p">
  5420. New Content
  5421. </p>
  5422. */
  5423. jindo.$Element.prototype.text = function(sText) {
  5424. var ele = this._element;
  5425. var tag = this.tag;
  5426. var prop = (typeof ele.innerText != "undefined")?"innerText":"textContent";
  5427. if (tag == "textarea" || tag == "input") prop = "value";
  5428. var type = (typeof sText);
  5429. if (type != "undefined"&&(type == "string" || type == "number" || type == "boolean")) {
  5430. sText += "";
  5431. try {
  5432. /*
  5433. * Opera 11.01에서 textContext가 Get일때 정상적으로 동작하지 않음. 그래서 get일 때는 innerText을 사용하고 set하는 경우는 textContent을 사용한다.(http://devcafe.nhncorp.com/ajaxui/295768)
  5434. */
  5435. if (prop!="value") prop = (typeof ele.textContent != "undefined")?"textContent":"innerText";
  5436. ele[prop] = sText;
  5437. } catch(e) {
  5438. return this.html(sText.replace(/&/g, '&amp;').replace(/</g, '&lt;'));
  5439. }
  5440. return this;
  5441. }
  5442. return ele[prop];
  5443. };
  5444. /**
  5445. * HTML 엘리먼트의 내부 HTML(innerHTML) 가져오거나 설정한다.
  5446. * @param {String} [sHTML] 설정할 HTML 문자열<br>
  5447. * 매개 변수를 생략하면 내부 HTML 조회하고, 매개 변수를 지정하면 매개 변수의 값으로 내부 HTML을 변경한다.
  5448. * @return {String | $Element} 값을 조회하는 경우에는 HTML 엘리먼트의 내부 HTML을 반환하고,<br>
  5449. * 값을 설정하는 경우에는 내부 HTML 변경한 현재의 $Element 객체를 반환
  5450. * @see $Element#outerHTML
  5451. * @description [Lite]
  5452. *
  5453. * @example
  5454. <div id="sample_container">
  5455. <p><em>Old</em> content</p>
  5456. </div>
  5457. ...
  5458. // 내부 HTML 조회
  5459. $Element("sample_container").html(); // <p><em>Old</em> content</p>
  5460. * @example
  5461. // 내부 HTML 설정
  5462. $Element("sample_container").html("<p>New <em>content</em></p>");
  5463. //Before
  5464. <div id="sample_container">
  5465. <p><em>Old</em> content</p>
  5466. </div>
  5467. //After
  5468. <div id="sample_container">
  5469. <p>New <em>content</em></p>
  5470. </div>
  5471. */
  5472. jindo.$Element.prototype.html = function(sHTML) {
  5473. var isIe = IS_IE;
  5474. var isFF = IS_FF;
  5475. if (isIe) {
  5476. jindo.$Element.prototype.html = function(sHTML){
  5477. if (typeof sHTML != "undefined" && arguments.length) {
  5478. sHTML += "";
  5479. jindo.$$.release();
  5480. var oEl = this._element;
  5481. while(oEl.firstChild){
  5482. oEl.removeChild(oEl.firstChild);
  5483. }
  5484. /*
  5485. IE FireFox 일부 상황에서 SELECT 태그나 TABLE, TR, THEAD, TBODY 태그에 innerHTML 셋팅해도
  5486. 문제가 생기지 않도록 보완 - hooriza
  5487. */
  5488. var sId = 'R' + new Date().getTime() + parseInt(Math.random() * 100000,10);
  5489. var oDoc = oEl.ownerDocument || oEl.document || document;
  5490. var oDummy;
  5491. var sTag = oEl.tagName.toLowerCase();
  5492. switch (sTag) {
  5493. case 'select':
  5494. case 'table':
  5495. oDummy = oDoc.createElement("div");
  5496. oDummy.innerHTML = '<' + sTag + ' class="' + sId + '">' + sHTML + '</' + sTag + '>';
  5497. break;
  5498. case 'tr':
  5499. case 'thead':
  5500. case 'tbody':
  5501. case 'colgroup':
  5502. oDummy = oDoc.createElement("div");
  5503. oDummy.innerHTML = '<table><' + sTag + ' class="' + sId + '">' + sHTML + '</' + sTag + '></table>';
  5504. break;
  5505. default:
  5506. oEl.innerHTML = sHTML;
  5507. break;
  5508. }
  5509. if (oDummy) {
  5510. var oFound;
  5511. for (oFound = oDummy.firstChild; oFound; oFound = oFound.firstChild)
  5512. if (oFound.className == sId) break;
  5513. if (oFound) {
  5514. var notYetSelected = true;
  5515. for (var oChild; oChild = oEl.firstChild;) oChild.removeNode(true); // innerHTML = '';
  5516. for (var oChild = oFound.firstChild; oChild; oChild = oFound.firstChild){
  5517. if(sTag=='select'){
  5518. /*
  5519. * ie에서 select테그일 경우 option중 selected가 되어 있는 option이 있는 경우 중간에
  5520. * selected가 되어 있으면 다음 부터는 계속 selected가 true로 되어 있어
  5521. * 해결하기 위해 cloneNode를 이용하여 option을 카피한 selected를 변경함. - mixed
  5522. */
  5523. var cloneNode = oChild.cloneNode(true);
  5524. if (oChild.selected && notYetSelected) {
  5525. notYetSelected = false;
  5526. cloneNode.selected = true;
  5527. }
  5528. oEl.appendChild(cloneNode);
  5529. oChild.removeNode(true);
  5530. }else{
  5531. oEl.appendChild(oChild);
  5532. }
  5533. }
  5534. oDummy.removeNode && oDummy.removeNode(true);
  5535. }
  5536. oDummy = null;
  5537. }
  5538. return this;
  5539. }
  5540. return this._element.innerHTML;
  5541. }
  5542. }else if(isFF){
  5543. jindo.$Element.prototype.html = function(sHTML){
  5544. if (typeof sHTML != "undefined" && arguments.length) {
  5545. sHTML += "";
  5546. var oEl = this._element;
  5547. if(!oEl.parentNode){
  5548. /*
  5549. IE FireFox 일부 상황에서 SELECT 태그나 TABLE, TR, THEAD, TBODY 태그에 innerHTML 셋팅해도
  5550. 문제가 생기지 않도록 보완 - hooriza
  5551. */
  5552. var sId = 'R' + new Date().getTime() + parseInt(Math.random() * 100000,10);
  5553. var oDoc = oEl.ownerDocument || oEl.document || document;
  5554. var oDummy;
  5555. var sTag = oEl.tagName.toLowerCase();
  5556. switch (sTag) {
  5557. case 'select':
  5558. case 'table':
  5559. oDummy = oDoc.createElement("div");
  5560. oDummy.innerHTML = '<' + sTag + ' class="' + sId + '">' + sHTML + '</' + sTag + '>';
  5561. break;
  5562. case 'tr':
  5563. case 'thead':
  5564. case 'tbody':
  5565. case 'colgroup':
  5566. oDummy = oDoc.createElement("div");
  5567. oDummy.innerHTML = '<table><' + sTag + ' class="' + sId + '">' + sHTML + '</' + sTag + '></table>';
  5568. break;
  5569. default:
  5570. oEl.innerHTML = sHTML;
  5571. break;
  5572. }
  5573. if (oDummy) {
  5574. var oFound;
  5575. for (oFound = oDummy.firstChild; oFound; oFound = oFound.firstChild)
  5576. if (oFound.className == sId) break;
  5577. if (oFound) {
  5578. for (var oChild; oChild = oEl.firstChild;) oChild.removeNode(true); // innerHTML = '';
  5579. for (var oChild = oFound.firstChild; oChild; oChild = oFound.firstChild){
  5580. oEl.appendChild(oChild);
  5581. }
  5582. oDummy.removeNode && oDummy.removeNode(true);
  5583. }
  5584. oDummy = null;
  5585. }
  5586. }else{
  5587. oEl.innerHTML = sHTML;
  5588. }
  5589. return this;
  5590. }
  5591. return this._element.innerHTML;
  5592. }
  5593. }else{
  5594. jindo.$Element.prototype.html = function(sHTML){
  5595. if (typeof sHTML != "undefined" && arguments.length) {
  5596. sHTML += "";
  5597. var oEl = this._element;
  5598. oEl.innerHTML = sHTML;
  5599. return this;
  5600. }
  5601. return this._element.innerHTML;
  5602. }
  5603. }
  5604. return this.html(sHTML);
  5605. };
  5606. /**
  5607. * HTML 엘리먼트의 외부 HTML(outerHTML) 반환한다.
  5608. * @return {String} 외부 HTML
  5609. * @see $Element#html
  5610. * @description [Lite]
  5611. *
  5612. * @example
  5613. <h2 id="sample0">Today is...</h2>
  5614. <div id="sample1">
  5615. <p><span id="sample2">Sample</span> content</p>
  5616. </div>
  5617. ...
  5618. // 외부 HTML 값을 조회
  5619. $Element("sample0").outerHTML(); // <h2 id="sample0">Today is...</h2>
  5620. $Element("sample1").outerHTML(); // <div id="sample1"> <p><span id="sample2">Sample</span> content</p> </div>
  5621. $Element("sample2").outerHTML(); // <span id="sample2">Sample</span>
  5622. */
  5623. jindo.$Element.prototype.outerHTML = function() {
  5624. var e = this._element;
  5625. if (typeof e.outerHTML != "undefined") return e.outerHTML;
  5626. var oDoc = e.ownerDocument || e.document || document;
  5627. var div = oDoc.createElement("div");
  5628. var par = e.parentNode;
  5629. /**
  5630. 상위노드가 없으면 innerHTML반환
  5631. */
  5632. if(!par) return e.innerHTML;
  5633. par.insertBefore(div, e);
  5634. div.style.display = "none";
  5635. div.appendChild(e);
  5636. var s = div.innerHTML;
  5637. par.insertBefore(e, div);
  5638. par.removeChild(div);
  5639. return s;
  5640. };
  5641. /**
  5642. * HTML 엘리먼트를 HTML 문자열로 변환하여 반환한다. (outerHTML 메서드와 동일)
  5643. * @return {String} 외부 HTML
  5644. * @see $Element#outerHTML
  5645. */
  5646. jindo.$Element.prototype.toString = jindo.$Element.prototype.outerHTML;
  5647. /**
  5648. * @fileOverview $Element의 확장 메서드를 정의한 파일
  5649. * @name element.extend.js
  5650. */
  5651. /**
  5652. * appear ,disappear에서 사용되는 함수로 현재 transition을 사용 할수 있는지를 학인한다.
  5653. * @ignore
  5654. */
  5655. jindo.$Element._getTransition = function(){
  5656. var hasTransition = false , sTransitionName = "";
  5657. if (typeof document.body.style.trasition != "undefined") {
  5658. hasTransition = true;
  5659. sTransitionName = "trasition";
  5660. }
  5661. /*
  5662. 아직 firefox는 transitionEnd API를 지원 하지 않음.
  5663. */
  5664. // else if(typeof document.body.style.MozTransition !== "undefined"){
  5665. // hasTransition = true;
  5666. // sTransitionName = "MozTransition";
  5667. // }
  5668. else if(typeof document.body.style.webkitTransition !== "undefined"){
  5669. hasTransition = true;
  5670. sTransitionName = "webkitTransition";
  5671. }else if(typeof document.body.style.OTransition !== "undefined"){
  5672. hasTransition = true;
  5673. sTransitionName = "OTransition";
  5674. }
  5675. return (jindo.$Element._getTransition = function(){
  5676. return {
  5677. "hasTransition" : hasTransition,
  5678. "name" : sTransitionName
  5679. };
  5680. })();
  5681. }
  5682. /**
  5683. * HTML 엘리먼트를 서서히 나타나게 한다. (Fade-in 효과)
  5684. *
  5685. * @param {Number} duration HTML 엘리먼트가 완전히 나타날 때까지 걸리는 시간. 단위는 초를 사용한다.
  5686. * @param {Function} [callback] HTML 엘리먼트가 완전히 나타난 후에 실행할 콜백 함수.
  5687. * @return {$Element} 현재의 $Element 객체
  5688. *
  5689. * @remark IE6 에서 filter 사용 해당 엘리먼트가 position 속성을 가지고 있으면 사라지는 문제가 있기 때문에 HTML 엘리먼트에 position 속성이 없어야 한다.
  5690. * @remark webkit기반의 브라우저(safari5+, mobile safari, chrome, mobile webkit), opera10.60+ 에서는 CSS3 transition을 사용한다. 이외의 브라우저에서는 자바스크립트를 사용한다.
  5691. *
  5692. * @see $Element#show
  5693. * @see $Element#disappear
  5694. *
  5695. * @example
  5696. $Element("sample1").appear(5, function(){
  5697. $Element("sample2").appear(3);
  5698. });
  5699. //Before
  5700. <div style="display: none; background-color: rgb(51, 51, 153); width: 100px; height: 50px;" id="sample1">
  5701. <div style="display: none; background-color: rgb(165, 10, 81); width: 50px; height: 20px;" id="sample2">
  5702. </div>
  5703. </div>
  5704. //After(1) : sample1 엘리먼트가 나타남
  5705. <div style="display: block; background-color: rgb(51, 51, 153); width: 100px; height: 50px; opacity: 1;" id="sample1">
  5706. <div style="display: none; background-color: rgb(165, 10, 81); width: 50px; height: 20px;" id="sample2">
  5707. </div>
  5708. </div>
  5709. //After(2) : sample2 엘리먼트가 나타남
  5710. <div style="display: block; background-color: rgb(51, 51, 153); width: 100px; height: 50px; opacity: 1;" id="sample1">
  5711. <div style="display: block; background-color: rgb(165, 10, 81); width: 50px; height: 20px; opacity: 1;" id="sample2">
  5712. </div>
  5713. </div>
  5714. */
  5715. jindo.$Element.prototype.appear = function(duration, callback) {
  5716. var oTransition = jindo.$Element._getTransition();
  5717. if (oTransition.hasTransition) {
  5718. jindo.$Element.prototype.appear = function(duration, callback) {
  5719. duration = duration||0.3;
  5720. callback = callback || function(){};
  5721. var bindFunc = function(){
  5722. callback();
  5723. this.show();
  5724. this.removeEventListener(oTransition.name+"End", arguments.callee , false );
  5725. };
  5726. var ele = this._element;
  5727. var self = this;
  5728. if(!this.visible()){
  5729. ele.style.opacity = ele.style.opacity||0;
  5730. self.show();
  5731. }
  5732. ele.addEventListener( oTransition.name+"End", bindFunc , false );
  5733. ele.style[oTransition.name + 'Property'] = 'opacity';
  5734. ele.style[oTransition.name + 'Duration'] = duration+'s';
  5735. ele.style[oTransition.name + 'TimingFunction'] = 'linear';
  5736. setTimeout(function(){
  5737. ele.style.opacity = '1';
  5738. },1);
  5739. return this;
  5740. }
  5741. }else{
  5742. jindo.$Element.prototype.appear = function(duration, callback) {
  5743. var self = this;
  5744. var op = this.opacity();
  5745. if(!this.visible()) op = 0;
  5746. if (op == 1) return this;
  5747. try { clearTimeout(this._fade_timer); } catch(e){};
  5748. callback = callback || function(){};
  5749. var step = (1-op) / ((duration||0.3)*100);
  5750. var func = function(){
  5751. op += step;
  5752. self.opacity(op);
  5753. if (op >= 1) {
  5754. callback(self);
  5755. } else {
  5756. self._fade_timer = setTimeout(func, 10);
  5757. }
  5758. };
  5759. this.show();
  5760. func();
  5761. return this;
  5762. }
  5763. }
  5764. return this.appear(duration, callback);
  5765. };
  5766. /**
  5767. * HTML 엘리먼트를 서서히 사라지게 한다. (Fade-out 효과)<br>
  5768. * HTML 엘리먼트가 완전히 사라지면 엘리먼트의 display 속성은 none 으로 변한다.
  5769. *
  5770. * @param {Number} duration HTML 엘리먼트 완전히 사라질 때까지 걸리는 시간. 단위는 초를 사용한다.
  5771. * @param {Function} [callback] HTML 엘리먼트가 완전히 사라진 후에 실행할 콜백 함수.
  5772. * @return {$Element} 현재의 $Element 객체
  5773. *
  5774. * @remark webkit기반의 브라우저(safari5+, mobile safari, chrome, mobile webkit), opera10.60+ 에서는 CSS3 transition을 사용한다. 이외의 브라우저에서는 자바스크립트를 사용한다.
  5775. *
  5776. * @see $Element#hide
  5777. * @see $Element#appear
  5778. *
  5779. * @example
  5780. $Element("sample1").disappear(5, function(){
  5781. $Element("sample2").disappear(3);
  5782. });
  5783. //Before
  5784. <div id="sample1" style="background-color: rgb(51, 51, 153); width: 100px; height: 50px;">
  5785. </div>
  5786. <div id="sample2" style="background-color: rgb(165, 10, 81); width: 100px; height: 50px;">
  5787. </div>
  5788. //After(1) : sample1 엘리먼트가 사라짐
  5789. <div id="sample1" style="background-color: rgb(51, 51, 153); width: 100px; height: 50px; opacity: 1; display: none;">
  5790. </div>
  5791. <div id="sample2" style="background-color: rgb(165, 10, 81); width: 100px; height: 50px;">
  5792. </div>
  5793. //After(2) : sample2 엘리먼트가 사라짐
  5794. <div id="sample1" style="background-color: rgb(51, 51, 153); width: 100px; height: 50px; opacity: 1; display: none;">
  5795. </div>
  5796. <div id="sample2" style="background-color: rgb(165, 10, 81); width: 100px; height: 50px; opacity: 1; display: none;">
  5797. </div>
  5798. */
  5799. jindo.$Element.prototype.disappear = function(duration, callback) {
  5800. var oTransition = jindo.$Element._getTransition();
  5801. if (oTransition.hasTransition) {
  5802. jindo.$Element.prototype.disappear = function(duration, callback) {
  5803. duration = duration||0.3
  5804. var self = this;
  5805. callback = callback || function(){};
  5806. var bindFunc = function(){
  5807. callback();
  5808. this.removeEventListener(oTransition.name+"End", arguments.callee , false );
  5809. self.hide();
  5810. };
  5811. var ele = this._element;
  5812. ele.addEventListener( oTransition.name+"End", bindFunc , false );
  5813. ele.style[oTransition.name + 'Property'] = 'opacity';
  5814. ele.style[oTransition.name + 'Duration'] = duration+'s';
  5815. ele.style[oTransition.name + 'TimingFunction'] = 'linear';
  5816. /*
  5817. opera 버그로 인하여 아래와 같이 처리함.
  5818. */
  5819. setTimeout(function(){
  5820. ele.style.opacity = '0';
  5821. },1);
  5822. return this;
  5823. }
  5824. }else{
  5825. jindo.$Element.prototype.disappear = function(duration, callback) {
  5826. var self = this;
  5827. var op = this.opacity();
  5828. if (op == 0) return this;
  5829. try { clearTimeout(this._fade_timer); } catch(e){};
  5830. callback = callback || function(){};
  5831. var step = op / ((duration||0.3)*100);
  5832. var func = function(){
  5833. op -= step;
  5834. self.opacity(op);
  5835. if (op <= 0) {
  5836. self.hide();
  5837. self.opacity(1);
  5838. callback(self);
  5839. } else {
  5840. self._fade_timer = setTimeout(func, 10);
  5841. }
  5842. };
  5843. func();
  5844. return this;
  5845. }
  5846. }
  5847. return this.disappear(duration, callback);
  5848. };
  5849. /**
  5850. * HTML 엘리먼트의 위치를 가져오거나 설정한다.<br>
  5851. * <br>
  5852. * 매개 변수를 생략하면 위치 값을 가져온다.<br>
  5853. * 매개 변수를 지정하면 HTML 엘리먼트의 위치를 설정한다.<br>
  5854. * 기준점은 브라우저 문서의 왼쪽 상단이다.
  5855. *
  5856. * @param {Number} [nTop] 문서의 위에서 HTML 엘리먼트 위까지의 거리. 단위는 px
  5857. * @param {Number} [nLeft] 문서의 왼쪽 가장자리에서 HTML 엘리먼트 왼쪽 가장자리까지의 거리. 단위는 px
  5858. * @return {$Element | Object} 위치를 설정하면 위치 값이 변경된 $Element 객체를 반환하고,<br>
  5859. * 위치를 가져오면 HTML 엘리먼트의 top, left 위치 값을 객체로 반환한다.
  5860. *
  5861. * @remark HTML 엘리먼트가 보이는 상태에서 적용해야 한다. 엘리먼트가 화면에 보이지 않으면 offset 사용이 정확하지 않다.
  5862. * @remark 일부 브라우저와 일부 상황에서 inline 엘리먼트에 대한 위치가 올바르게 얻어지지 않는 문제가 있으며 경우 해당 엘리먼트를 position:relative; 바꿔주는 식으로 해결할 있다.
  5863. * @author Hooriza
  5864. *
  5865. * @example
  5866. <style type="text/css">
  5867. div { background-color:#2B81AF; width:20px; height:20px; float:left; left:100px; top:50px; position:absolute;}
  5868. </style>
  5869. <div id="sample"></div>
  5870. ...
  5871. // 위치 값 조회
  5872. $Element("sample").offset(); // { left=100, top=50 }
  5873. * @example
  5874. // 위치 값 설정
  5875. $Element("sample").offset(40, 30);
  5876. //Before
  5877. <div id="sample"></div>
  5878. //After
  5879. <div id="sample" style="top: 40px; left: 30px;"></div>
  5880. */
  5881. jindo.$Element.prototype.offset = function(nTop, nLeft) {
  5882. var oEl = this._element;
  5883. var oPhantom = null;
  5884. // setter
  5885. if (typeof nTop == 'number' && typeof nLeft == 'number') {
  5886. if (isNaN(parseInt(this.css('top'),10))) this.css('top', 0);
  5887. if (isNaN(parseInt(this.css('left'),10))) this.css('left', 0);
  5888. var oPos = this.offset();
  5889. var oGap = { top : nTop - oPos.top, left : nLeft - oPos.left };
  5890. oEl.style.top = parseInt(this.css('top'),10) + oGap.top + 'px';
  5891. oEl.style.left = parseInt(this.css('left'),10) + oGap.left + 'px';
  5892. return this;
  5893. }
  5894. // getter
  5895. var bSafari = /Safari/.test(navigator.userAgent);
  5896. var bIE = /MSIE/.test(navigator.userAgent);
  5897. var nVer = bIE?navigator.userAgent.match(/(?:MSIE) ([0-9.]+)/)[1]:0;
  5898. var fpSafari = function(oEl) {
  5899. var oPos = { left : 0, top : 0 };
  5900. for (var oParent = oEl, oOffsetParent = oParent.offsetParent; oParent = oParent.parentNode; ) {
  5901. if (oParent.offsetParent) {
  5902. oPos.left -= oParent.scrollLeft;
  5903. oPos.top -= oParent.scrollTop;
  5904. }
  5905. if (oParent == oOffsetParent) {
  5906. oPos.left += oEl.offsetLeft + oParent.clientLeft;
  5907. oPos.top += oEl.offsetTop + oParent.clientTop ;
  5908. if (!oParent.offsetParent) {
  5909. oPos.left += oParent.offsetLeft;
  5910. oPos.top += oParent.offsetTop;
  5911. }
  5912. oOffsetParent = oParent.offsetParent;
  5913. oEl = oParent;
  5914. }
  5915. }
  5916. return oPos;
  5917. };
  5918. var fpOthers = function(oEl) {
  5919. var oPos = { left : 0, top : 0 };
  5920. var oDoc = oEl.ownerDocument || oEl.document || document;
  5921. var oHtml = oDoc.documentElement;
  5922. var oBody = oDoc.body;
  5923. if (oEl.getBoundingClientRect) { // has getBoundingClientRect
  5924. if (!oPhantom) {
  5925. var bHasFrameBorder = (window == top);
  5926. if(!bHasFrameBorder){
  5927. try{
  5928. bHasFrameBorder = (window.frameElement && window.frameElement.frameBorder == 1);
  5929. }catch(e){}
  5930. }
  5931. if ((bIE && nVer < 8 && window.external) && bHasFrameBorder) {
  5932. oPhantom = { left : 2, top : 2 };
  5933. oBase = null;
  5934. } else {
  5935. oPhantom = { left : 0, top : 0 };
  5936. }
  5937. }
  5938. var box = oEl.getBoundingClientRect();
  5939. if (oEl !== oHtml && oEl !== oBody) {
  5940. oPos.left = box.left - oPhantom.left;
  5941. oPos.top = box.top - oPhantom.top;
  5942. oPos.left += oHtml.scrollLeft || oBody.scrollLeft;
  5943. oPos.top += oHtml.scrollTop || oBody.scrollTop;
  5944. }
  5945. } else if (oDoc.getBoxObjectFor) { // has getBoxObjectFor
  5946. var box = oDoc.getBoxObjectFor(oEl);
  5947. var vpBox = oDoc.getBoxObjectFor(oHtml || oBody);
  5948. oPos.left = box.screenX - vpBox.screenX;
  5949. oPos.top = box.screenY - vpBox.screenY;
  5950. } else {
  5951. for (var o = oEl; o; o = o.offsetParent) {
  5952. oPos.left += o.offsetLeft;
  5953. oPos.top += o.offsetTop;
  5954. }
  5955. for (var o = oEl.parentNode; o; o = o.parentNode) {
  5956. if (o.tagName == 'BODY') break;
  5957. if (o.tagName == 'TR') oPos.top += 2;
  5958. oPos.left -= o.scrollLeft;
  5959. oPos.top -= o.scrollTop;
  5960. }
  5961. }
  5962. return oPos;
  5963. };
  5964. return (bSafari ? fpSafari : fpOthers)(oEl);
  5965. };
  5966. /**
  5967. * 문자열 내의 JavaScript를 실행한다.<br>
  5968. * &lt;script&gt; 태그가 포함된 문자열을 매개 변수로 지정하면, &lt;script&gt; 안에 있는 내용을 파싱하여 eval 수행한다.
  5969. *
  5970. * @param {String} sHTML &lt;script&gt; 태그가 포함된 HTML 문자열
  5971. * @return {$Element} 현재의 $Element 객체를 반환
  5972. *
  5973. * @example
  5974. // script 태그가 포함된 문자열을 지정
  5975. var response = "<script type='text/javascript'>$Element('sample').appendHTML('<li>4</li>')</script>";
  5976. $Element("sample").evalScripts(response);
  5977. //Before
  5978. <ul id="sample">
  5979. <li>1</li>
  5980. <li>2</li>
  5981. <li>3</li>
  5982. </ul>
  5983. //After
  5984. <ul id="sample">
  5985. <li>1</li>
  5986. <li>2</li>
  5987. <li>3</li>
  5988. <li>4</li></ul>
  5989. */
  5990. jindo.$Element.prototype.evalScripts = function(sHTML) {
  5991. var aJS = [];
  5992. sHTML = sHTML.replace(new RegExp('<script(\\s[^>]+)*>(.*?)</'+'script>', 'gi'), function(_1, _2, sPart) { aJS.push(sPart); return ''; });
  5993. eval(aJS.join('\n'));
  5994. return this;
  5995. };
  5996. /**
  5997. * element를 뒤에 붙일때 사용되는 함수.
  5998. * @ignore
  5999. * @param {Element} 기준 엘리먼트
  6000. * @param {Element} 붙일 엘리먼트
  6001. * @return {$Element} 두번째 파라메터의 엘리먼트
  6002. */
  6003. jindo.$Element._append = function(oParent, oChild){
  6004. if (typeof oChild == "string") {
  6005. oChild = jindo.$(oChild);
  6006. }else if(oChild instanceof jindo.$Element){
  6007. oChild = oChild.$value();
  6008. }
  6009. oParent._element.appendChild(oChild);
  6010. return oParent;
  6011. }
  6012. /**
  6013. * element를 앞에 붙일때 사용되는 함수.
  6014. * @ignore
  6015. * @param {Element} 기준 엘리먼트
  6016. * @param {Element} 붙일 엘리먼트
  6017. * @return {$Element} 두번째 파라메터의 엘리먼트
  6018. */
  6019. jindo.$Element._prepend = function(oParent, oChild){
  6020. if (typeof oParent == "string") {
  6021. oParent = jindo.$(oParent);
  6022. }else if(oParent instanceof jindo.$Element){
  6023. oParent = oParent.$value();
  6024. }
  6025. var nodes = oParent.childNodes;
  6026. if (nodes.length > 0) {
  6027. oParent.insertBefore(oChild._element, nodes[0]);
  6028. } else {
  6029. oParent.appendChild(oChild._element);
  6030. }
  6031. return oChild;
  6032. }
  6033. /**
  6034. * HTML 엘리먼트에 마지막 자식 노드를 추가한다.
  6035. *
  6036. * @param {$Element | HTML Element | String} oElement 추가할 HTML 엘리먼트. 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  6037. * <br>
  6038. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 마지막 자식노드로 추가한다.<br>
  6039. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 마지막 자식노드로 추가한다.<br>
  6040. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 마지막 자식노드로 추가한다.
  6041. * @return {$Element} $Element 객체 자신
  6042. *
  6043. * @see $Element#prepend
  6044. * @see $Element#before
  6045. * @see $Element#after
  6046. * @see $Element#appendTo
  6047. * @see $Element#prependTo
  6048. *
  6049. * @example
  6050. // id 가 sample1 인 HTML 엘리먼트에
  6051. // id 가 sample2 인 HTML 엘리먼트를 추가
  6052. $Element("sample1").append("sample2");
  6053. //Before
  6054. <div id="sample2">
  6055. <div>Hello 2</div>
  6056. </div>
  6057. <div id="sample1">
  6058. <div>Hello 1</div>
  6059. </div>
  6060. //After
  6061. <div id="sample1">
  6062. <div>Hello 1</div>
  6063. <div id="sample2">
  6064. <div>Hello 2</div>
  6065. </div>
  6066. </div>
  6067. * @example
  6068. // id 가 sample 인 HTML 엘리먼트에
  6069. // 새로운 DIV 엘리먼트를 추가
  6070. var elChild = $("<div>Hello New</div>");
  6071. $Element("sample").append(elChild);
  6072. //Before
  6073. <div id="sample">
  6074. <div>Hello</div>
  6075. </div>
  6076. //After
  6077. <div id="sample">
  6078. <div>Hello </div>
  6079. <div>Hello New</div>
  6080. </div>
  6081. */
  6082. jindo.$Element.prototype.append = function(oElement) {
  6083. return jindo.$Element._append(this,oElement);
  6084. };
  6085. /**
  6086. * HTML 엘리먼트에 번째 자식 노드를 추가한다.
  6087. *
  6088. * @param {$Element | HTMLElement | String} oElement 추가할 HTML 엘리먼트. 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  6089. * <br>
  6090. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 번째 자식노드로 추가한다.<br>
  6091. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 번째 자식노드로 추가한다.<br>
  6092. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 번째 자식노드로 추가한다.
  6093. * @return {$Element} $Element 객체 자신
  6094. *
  6095. * @see $Element#append
  6096. * @see $Element#before
  6097. * @see $Element#after
  6098. * @see $Element#appendTo
  6099. * @see $Element#prependTo
  6100. *
  6101. * @example
  6102. // id 가 sample1 인 HTML 엘리먼트에서
  6103. // id 가 sample2 인 HTML 엘리먼트를 첫 번째 자식노드로 이동
  6104. $Element("sample1").prepend("sample2");
  6105. //Before
  6106. <div id="sample1">
  6107. <div>Hello 1</div>
  6108. <div id="sample2">
  6109. <div>Hello 2</div>
  6110. </div>
  6111. </div>
  6112. //After
  6113. <div id="sample1">
  6114. <div id="sample2">
  6115. <div>Hello 2</div>
  6116. </div>
  6117. <div>Hello 1</div>
  6118. </div>
  6119. * @example
  6120. // id 가 sample 인 HTML 엘리먼트에
  6121. // 새로운 DIV 엘리먼트를 추가
  6122. var elChild = $("<div>Hello New</div>");
  6123. $Element("sample").prepend(elChild);
  6124. //Before
  6125. <div id="sample">
  6126. <div>Hello</div>
  6127. </div>
  6128. //After
  6129. <div id="sample">
  6130. <div>Hello New</div>
  6131. <div>Hello</div>
  6132. </div>
  6133. */
  6134. jindo.$Element.prototype.prepend = function(oElement) {
  6135. return jindo.$Element._prepend(this._element, jindo.$Element(oElement));
  6136. };
  6137. /**
  6138. * $Element 객체 내부의 HTML 엘리먼트를 매개 변수로 지정한 엘리먼트로 대체한다.
  6139. *
  6140. * @param {$Element | HTML Element | String} oElement 대체할 HTML 엘리먼트. 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  6141. * <br>
  6142. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트로 대체한다.<br>
  6143. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트로 대체한다.<br>
  6144. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트로 대체한다.
  6145. * @return {$Element} HTML 엘리먼트가 대체 $Element 객체를 반환
  6146. *
  6147. * @example
  6148. // id 가 sample1 인 HTML 엘리먼트에서
  6149. // id 가 sample2 인 HTML 엘리먼트로 대체
  6150. $Element('sample1').replace('sample2');
  6151. //Before
  6152. <div>
  6153. <div id="sample1">Sample1</div>
  6154. </div>
  6155. <div id="sample2">Sample2</div>
  6156. //After
  6157. <div>
  6158. <div id="sample2">Sample2</div>
  6159. </div>
  6160. * @example
  6161. // 새로운 DIV 엘리먼트로 대체
  6162. $Element("btn").replace($("<div>Sample</div>"));
  6163. //Before
  6164. <button id="btn">Sample</button>
  6165. //After
  6166. <div>Sample</div>
  6167. */
  6168. jindo.$Element.prototype.replace = function(oElement) {
  6169. jindo.$$.release();
  6170. var e = this._element;
  6171. var oParentNode = e.parentNode;
  6172. var o = jindo.$Element(oElement);
  6173. if(oParentNode&&oParentNode.replaceChild){
  6174. oParentNode.replaceChild(o.$value(),e);
  6175. return o;
  6176. }
  6177. var o = o.$value();
  6178. oParentNode.insertBefore(o, e);
  6179. oParentNode.removeChild(e);
  6180. return o;
  6181. };
  6182. /**
  6183. * HTML 엘리먼트를 다른 HTML 엘리먼트의 마지막 자식노드로 추가한다.
  6184. *
  6185. * @param {$Element | HTML Element | String} oElement 부모가 HTML 엘리먼트. <br>
  6186. * <br>
  6187. * 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  6188. * <br>
  6189. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 부모로 한다.<br>
  6190. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 부모로 한다.<br>
  6191. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 부모로 한다.
  6192. * @return {$Element} 인자로 받은 엘리먼트
  6193. *
  6194. * @see $Element#append
  6195. * @see $Element#prepend
  6196. * @see $Element#after
  6197. * @see $Element#appendTo
  6198. * @see $Element#prependTo
  6199. *
  6200. * @example
  6201. // id 가 sample2 인 HTML 엘리먼트에
  6202. // id 가 sample1 인 HTML 엘리먼트를 추가
  6203. $Element("sample1").appendTo("sample2");
  6204. //Before
  6205. <div id="sample1">
  6206. <div>Hello 1</div>
  6207. </div>
  6208. <div id="sample2">
  6209. <div>Hello 2</div>
  6210. </div>
  6211. //After
  6212. <div id="sample2">
  6213. <div>Hello 2</div>
  6214. <div id="sample1">
  6215. <div>Hello 1</div>
  6216. </div>
  6217. </div>
  6218. */
  6219. jindo.$Element.prototype.appendTo = function(oElement) {
  6220. var ele = jindo.$Element(oElement);
  6221. jindo.$Element._append(ele, this._element);
  6222. return ele;
  6223. };
  6224. /**
  6225. * HTML 엘리먼트를 다른 HTML 엘리먼트의 번째 자식노드로 추가한다.
  6226. *
  6227. * @param {$Element | HTML Element | String} oElement 부모가 HTML 엘리먼트. 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  6228. * <br>
  6229. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 부모로 한다.<br>
  6230. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 부모로 한다.<br>
  6231. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 부모로 한다.
  6232. * @return {$Element} 인자로 받은 엘리먼트
  6233. *
  6234. * @see $Element#append
  6235. * @see $Element#prepend
  6236. * @see $Element#after
  6237. * @see $Element#appendTo
  6238. * @see $Element#prependTo
  6239. *
  6240. * @example
  6241. // id 가 sample2 인 HTML 엘리먼트에
  6242. // id 가 sample1 인 HTML 엘리먼트를 추가
  6243. $Element("sample1").prependTo("sample2");
  6244. //Before
  6245. <div id="sample1">
  6246. <div>Hello 1</div>
  6247. </div>
  6248. <div id="sample2">
  6249. <div>Hello 2</div>
  6250. </div>
  6251. //After
  6252. <div id="sample2">
  6253. <div id="sample1">
  6254. <div>Hello 1</div>
  6255. </div>
  6256. <div>Hello 2</div>
  6257. </div>
  6258. */
  6259. jindo.$Element.prototype.prependTo = function(oElement) {
  6260. jindo.$Element._prepend(oElement, this);
  6261. return jindo.$Element(oElement);
  6262. };
  6263. /**
  6264. * HTML 엘리먼트 바로 앞에 HTML 엘리먼트를 추가한다.
  6265. *
  6266. * @param {$Element | HTML Element | String} oElement 추가할 HTML 엘리먼트.<br>
  6267. * <br>
  6268. * 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  6269. * <br>
  6270. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 추가한다.<br>
  6271. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 추가한다.<br>
  6272. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 추가한다.
  6273. * @return {$Element} 추가 $Element 객체
  6274. *
  6275. * @see $Element#append
  6276. * @see $Element#prepend
  6277. * @see $Element#after
  6278. * @see $Element#appendTo
  6279. * @see $Element#prependTo
  6280. *
  6281. * @example
  6282. // id 가 sample1 인 HTML 엘리먼트 앞에
  6283. // id 가 sample2 인 HTML 엘리먼트를 추가 함
  6284. $Element("sample1").before("sample2"); // sample2를 래핑한 $Element 를 반환
  6285. //Before
  6286. <div id="sample1">
  6287. <div>Hello 1</div>
  6288. <div id="sample2">
  6289. <div>Hello 2</div>
  6290. </div>
  6291. </div>
  6292. //After
  6293. <div id="sample2">
  6294. <div>Hello 2</div>
  6295. </div>
  6296. <div id="sample1">
  6297. <div>Hello 1</div>
  6298. </div>
  6299. * @example
  6300. // 새로운 DIV 엘리먼트를 추가
  6301. var elNew = $("<div>Hello New</div>");
  6302. $Element("sample").before(elNew); // elNew 엘리먼트를 래핑한 $Element 를 반환
  6303. //Before
  6304. <div id="sample">
  6305. <div>Hello</div>
  6306. </div>
  6307. //After
  6308. <div>Hello New</div>
  6309. <div id="sample">
  6310. <div>Hello</div>
  6311. </div>
  6312. */
  6313. jindo.$Element.prototype.before = function(oElement) {
  6314. var oRich = jindo.$Element(oElement);
  6315. var o = oRich.$value();
  6316. this._element.parentNode.insertBefore(o, this._element);
  6317. return oRich;
  6318. };
  6319. /**
  6320. * HTML 엘리먼트 바로 뒤에 HTML 엘리먼트를 추가한다.
  6321. *
  6322. * @param {$Element | HTML Element | String} oElement 추가할 HTML 엘리먼트. 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  6323. * <br>
  6324. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 추가한다.<br>
  6325. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 추가한다.<br>
  6326. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 추가한다.
  6327. * @return {$Element} 추가 $Element 객체
  6328. *
  6329. * @see $Element#append
  6330. * @see $Element#prepend
  6331. * @see $Element#before
  6332. * @see $Element#appendTo
  6333. * @see $Element#prependTo
  6334. *
  6335. * @example
  6336. // id 가 sample1 인 HTML 엘리먼트 뒤에
  6337. // id 가 sample2 인 HTML 엘리먼트를 추가 함
  6338. $Element("sample1").after("sample2"); // sample2를 래핑한 $Element 를 반환
  6339. //Before
  6340. <div id="sample1">
  6341. <div>Hello 1</div>
  6342. <div id="sample2">
  6343. <div>Hello 2</div>
  6344. </div>
  6345. </div>
  6346. //After
  6347. <div id="sample1">
  6348. <div>Hello 1</div>
  6349. </div>
  6350. <div id="sample2">
  6351. <div>Hello 2</div>
  6352. </div>
  6353. * @example
  6354. // 새로운 DIV 엘리먼트를 추가
  6355. var elNew = $("<div>Hello New</div>");
  6356. $Element("sample").after(elNew); // elNew 엘리먼트를 래핑한 $Element 를 반환
  6357. //Before
  6358. <div id="sample">
  6359. <div>Hello</div>
  6360. </div>
  6361. //After
  6362. <div id="sample">
  6363. <div>Hello</div>
  6364. </div>
  6365. <div>Hello New</div>
  6366. */
  6367. jindo.$Element.prototype.after = function(oElement) {
  6368. var o = this.before(oElement);
  6369. o.before(this);
  6370. return o;
  6371. };
  6372. /**
  6373. * HTML 엘리먼트의 상위 엘리먼트 노드를 검색한다.
  6374. *
  6375. * @param {Function} [pFunc] 상위 엘리먼트 노드의 검색 조건을 지정한 콜백 함수.<br>
  6376. * 매개 변수를 생략하면 부모 엘리먼트 노드를 반환하고,<br>
  6377. * 매개 변수로 콜백 함수를 지정하면 콜백 함수의 실행 결과가 true 상위 엘리먼트 노드의 배열을 반환한다.<br>
  6378. * 콜백 함수에 매개 변수로 탐색 중인 상위 엘리먼트 노드의 $Element 객체를 넘긴다.
  6379. * @param {Number} [limit] 탐색할 상위 엘리먼트 노드의 뎁스.<br>
  6380. * 매개 변수를 생략하면 모든 상위 엘리먼트 노드를 탐색한다.<br>
  6381. * pFunc 매개 변수를 null로 설정하고 limit 매개 변수를 설정하면 제한된 뎁스의 상위 엘리먼트 노드를 조건 없이 검색한다.
  6382. * @return {$Element | Array} 부모 엘리먼트 노드 혹은 상위 엘리먼트 노드의 배열.<br>
  6383. * 매개 변수를 생략하여 부모 엘리먼트 노드를 반환하는 경우, $Element 타입으로 반환한다.<br>
  6384. * 이외에는 검색된 엘리먼트 노드를 $Element의 배열로 반환한다.
  6385. *
  6386. * @see $Element#child
  6387. * @see $Element#prev
  6388. * @see $Element#next
  6389. * @see $Element#first
  6390. * @see $Element#last
  6391. * @see $Element#indexOf
  6392. *
  6393. * @example
  6394. <div class="sample" id="div1">
  6395. <div id="div2">
  6396. <div class="sample" id="div3">
  6397. <div id="target">
  6398. Sample
  6399. <div id="div4">
  6400. Sample
  6401. </div>
  6402. <div class="sample" id="div5">
  6403. Sample
  6404. </div>
  6405. </div>
  6406. <div class="sample" id="div6">
  6407. Sample
  6408. </div>
  6409. </div>
  6410. </div>
  6411. </div>
  6412. <script type="text/javascript">
  6413. var welTarget = $Element("target");
  6414. var parent = welTarget.parent();
  6415. // id가 div3인 DIV를 래핑한 $Element를 반환
  6416. parent = welTarget.parent(function(v){
  6417. return v.hasClass("sample");
  6418. });
  6419. // id가 div3인 DIV를 래핑한 $Element와
  6420. // id가 div1인 DIV를 래핑한 $Element를 원소로 하는 배열을 반환
  6421. parent = welTarget.parent(function(v){
  6422. return v.hasClass("sample");
  6423. }, 1);
  6424. // id가 div3인 DIV를 래핑한 $Element를 원소로 하는 배열을 반환
  6425. </script>
  6426. */
  6427. jindo.$Element.prototype.parent = function(pFunc, limit) {
  6428. var e = this._element;
  6429. var a = [], p = null;
  6430. if (typeof pFunc == "undefined") return jindo.$Element(e.parentNode);
  6431. if (typeof limit == "undefined" || limit == 0) limit = -1;
  6432. while (e.parentNode && limit-- != 0) {
  6433. p = jindo.$Element(e.parentNode);
  6434. if (e.parentNode == document.documentElement) break;
  6435. if (!pFunc || (pFunc && pFunc(p))) a[a.length] = p;
  6436. e = e.parentNode;
  6437. }
  6438. return a;
  6439. };
  6440. /**
  6441. * HTML 엘리먼트의 하위 엘리먼트 노드를 검색한다.
  6442. *
  6443. * @param {Function} [pFunc] 하위 엘리먼트 노드의 검색 조건을 지정한 콜백 함수.<br>
  6444. * 매개 변수를 생략하면 자식 엘리먼트 노드의 배열을 반환하고,<br>
  6445. * 매개 변수로 콜백 함수를 지정하면 콜백 함수의 실행 결과가 true 하위 엘리먼트 노드의 배열을 반환한다.<br>
  6446. * 콜백 함수에 매개 변수로 탐색 중인 하위 엘리먼트 노드의 $Element 객체를 넘긴다.
  6447. * @param {Number} [limit] 탐색할 하위 엘리먼트 노드의 뎁스.<br>
  6448. * 매개 변수를 생략하면 모든 하위 엘리먼트 노드를 탐색한다.<br>
  6449. * pFunc 매개 변수를 null로 설정하고 limit 매개 변수를 설정하면 제한된 뎁스의 하위 엘리먼트 노드를 조건 없이 검색한다.
  6450. * @return {$Element | Array} 자식 엘리먼트 노드 혹은 조건에 맞는 하위 노드의 $Element의 배열을 반환한다.
  6451. *
  6452. * @see $Element#parent
  6453. * @see $Element#prev
  6454. * @see $Element#next
  6455. * @see $Element#first
  6456. * @see $Element#last
  6457. * @see $Element#indexOf
  6458. *
  6459. * @example
  6460. <div class="sample" id="target">
  6461. <div id="div1">
  6462. <div class="sample" id="div2">
  6463. <div id="div3">
  6464. Sample
  6465. <div id="div4">
  6466. Sample
  6467. </div>
  6468. <div class="sample" id="div5">
  6469. Sample
  6470. <div class="sample" id="div6">
  6471. Sample
  6472. </div>
  6473. </div>
  6474. </div>
  6475. </div>
  6476. </div>
  6477. <div class="sample" id="div7">
  6478. Sample
  6479. </div>
  6480. </div>
  6481. <script type="text/javascript">
  6482. var welTarget = $Element("target");
  6483. var child = welTarget.child();
  6484. // id가 div1인 DIV를 래핑한 $Element와
  6485. // id가 div7인 DIV를 래핑한 $Element를 원소로 하는 배열을 반환
  6486. child = welTarget.child(function(v){
  6487. return v.hasClass("sample");
  6488. });
  6489. // id가 div2인 DIV를 래핑한 $Element와
  6490. // id가 div5인 DIV를 래핑한 $Element와
  6491. // id가 div6인 DIV를 래핑한 $Element와
  6492. // id가 div7인 DIV를 래핑한 $Element를 원소로 하는 배열을 반환
  6493. child = welTarget.child(function(v){
  6494. return v.hasClass("sample");
  6495. }, 1);
  6496. // id가 div7인 DIV를 래핑한 $Element를 원소로 하는 배열을 반환
  6497. child = welTarget.child(function(v){
  6498. return v.hasClass("sample");
  6499. }, 2);
  6500. // id가 div2인 DIV를 래핑한 $Element와
  6501. // id가 div7인 DIV를 래핑한 $Element를 원소로 하는 배열을 반환
  6502. </script>
  6503. */
  6504. jindo.$Element.prototype.child = function(pFunc, limit) {
  6505. var e = this._element;
  6506. var a = [], c = null, f = null;
  6507. if (typeof pFunc == "undefined") return jindo.$A(e.childNodes).filter(function(v){ return v.nodeType == 1}).map(function(v){ return jindo.$Element(v) }).$value();
  6508. if (typeof limit == "undefined" || limit == 0) limit = -1;
  6509. (f = function(el, lim){
  6510. var ch = null, o = null;
  6511. for(var i=0; i < el.childNodes.length; i++) {
  6512. ch = el.childNodes[i];
  6513. if (ch.nodeType != 1) continue;
  6514. o = jindo.$Element(el.childNodes[i]);
  6515. if (!pFunc || (pFunc && pFunc(o))) a[a.length] = o;
  6516. if (lim != 0) f(el.childNodes[i], lim-1);
  6517. }
  6518. })(e, limit-1);
  6519. return a;
  6520. };
  6521. /**
  6522. * HTML 엘리먼트의 이전에 나오는 형제 엘리먼트 노드를 검색한다.
  6523. *
  6524. * @param {Function} [pFunc] 이전 형제 엘리먼트 노드의 검색 조건을 지정한 콜백 함수.<br>
  6525. * 매개 변수를 생략하면 바로 이전의 형제 엘리먼트 노드를 반환하고,<br>
  6526. * 매개 변수로 콜백 함수를 지정하면 콜백 함수의 실행 결과가 true 형제 엘리먼트 노드의 배열을 반환한다.<br>
  6527. * 콜백 함수에 매개 변수로 탐색 중인 형제 엘리먼트 노드를 넘긴다. ($Element 객체가 아님)
  6528. * @return {$Element | Array} 바로 전의 형제 엘리먼트 노드를 가리키는 $Element 혹은 조건에 맞는 형제 노드의 $Element의 배열을 반환한다.
  6529. *
  6530. * @see $Element#parent
  6531. * @see $Element#child
  6532. * @see $Element#next
  6533. * @see $Element#first
  6534. * @see $Element#last
  6535. * @see $Element#indexOf
  6536. *
  6537. * @example
  6538. <div class="sample" id="sample_div1">
  6539. <div id="sample_div2">
  6540. <div class="sample" id="sample_div3">
  6541. Sample1
  6542. </div>
  6543. <div id="sample_div4">
  6544. Sample2
  6545. </div>
  6546. <div class="sample" id="sample_div5">
  6547. Sample3
  6548. </div>
  6549. <div id="sample_div">
  6550. Sample4
  6551. <div id="sample_div6">
  6552. Sample5
  6553. </div>
  6554. </div>
  6555. <div id="sample_div7">
  6556. Sample6
  6557. </div>
  6558. <div class="sample" id="sample_div8">
  6559. Sample7
  6560. </div>
  6561. </div>
  6562. </div>
  6563. <script type="text/javascript">
  6564. var sibling = $Element("sample_div").prev();
  6565. // id가 sample_div5인 DIV를 래핑한 $Element를 반환
  6566. sibling = $Element("sample_div").prev(function(v){
  6567. return $Element(v).hasClass("sample");
  6568. });
  6569. // id가 sample_div5인 DIV를 래핑한 $Element와
  6570. // id가 sample_div3인 DIV를 래핑한 $Element를 원소로 하는 배열을 반환
  6571. </script>
  6572. */
  6573. jindo.$Element.prototype.prev = function(pFunc) {
  6574. var e = this._element;
  6575. var a = [];
  6576. var b = (typeof pFunc == "undefined");
  6577. if (!e) return b?jindo.$Element(null):a;
  6578. do {
  6579. e = e.previousSibling;
  6580. if (!e || e.nodeType != 1) continue;
  6581. if (b) return jindo.$Element(e);
  6582. if (!pFunc || pFunc(e)) a[a.length] = jindo.$Element(e);
  6583. } while(e);
  6584. return b?jindo.$Element(e):a;
  6585. };
  6586. /**
  6587. * HTML 엘리먼트의 다음에 나오는 형제 엘리먼트 노드를 검색한다.
  6588. *
  6589. * @param {Function} [pFunc] 다음 형제 엘리먼트 노드의 검색 조건을 지정한 콜백 함수.<br>
  6590. * 매개 변수를 생략하면 바로 다음의 형제 엘리먼트 노드를 반환하고,<br>
  6591. * 매개 변수로 콜백 함수를 지정하면 콜백 함수의 실행 결과가 true 형제 엘리먼트 노드의 배열을 반환한다.<br>
  6592. * 콜백 함수에 매개 변수로 탐색 중인 형제 엘리먼트 노드를 넘긴다. ($Element 객체가 아님)
  6593. * @return {$Element | Array} 바로 다음의 형제 엘리먼트 노드를 가리키는 $Element 혹은 조건에 맞는 형제 노드의 $Element의 배열을 반환한다.
  6594. *
  6595. * @see $Element#parent
  6596. * @see $Element#child
  6597. * @see $Element#prev
  6598. * @see $Element#first
  6599. * @see $Element#last
  6600. * @see $Element#indexOf
  6601. *
  6602. * @example
  6603. <div class="sample" id="sample_div1">
  6604. <div id="sample_div2">
  6605. <div class="sample" id="sample_div3">
  6606. Sample1
  6607. </div>
  6608. <div id="sample_div4">
  6609. Sample2
  6610. </div>
  6611. <div class="sample" id="sample_div5">
  6612. Sample3
  6613. </div>
  6614. <div id="sample_div">
  6615. Sample4
  6616. <div id="sample_div6">
  6617. Sample5
  6618. </div>
  6619. </div>
  6620. <div id="sample_div7">
  6621. Sample6
  6622. </div>
  6623. <div class="sample" id="sample_div8">
  6624. Sample7
  6625. </div>
  6626. </div>
  6627. </div>
  6628. <script type="text/javascript">
  6629. var sibling = $Element("sample_div").next();
  6630. // id가 sample_div7인 DIV를 래핑한 $Element를 반환
  6631. sibling = $Element("sample_div").next(function(v){
  6632. return $Element(v).hasClass("sample");
  6633. });
  6634. // id가 sample_div8인 DIV를 래핑한 $Element를 원소로 하는 배열을 반환
  6635. </script>
  6636. */
  6637. jindo.$Element.prototype.next = function(pFunc) {
  6638. var e = this._element;
  6639. var a = [];
  6640. var b = (typeof pFunc == "undefined");
  6641. if (!e) return b?jindo.$Element(null):a;
  6642. do {
  6643. e = e.nextSibling;
  6644. if (!e || e.nodeType != 1) continue;
  6645. if (b) return jindo.$Element(e);
  6646. if (!pFunc || pFunc(e)) a[a.length] = jindo.$Element(e);
  6647. } while(e);
  6648. return b?jindo.$Element(e):a;
  6649. };
  6650. /**
  6651. * HTML 엘리먼트의 번째 자식 엘리먼트 노드를 반환한다.
  6652. *
  6653. * @return {$Element} 번째 자식 엘리먼트 노드
  6654. * @since 1.2.0
  6655. *
  6656. * @see $Element#parent
  6657. * @see $Element#child
  6658. * @see $Element#prev
  6659. * @see $Element#next
  6660. * @see $Element#last
  6661. * @see $Element#indexOf
  6662. *
  6663. * @example
  6664. <div id="sample_div1">
  6665. <div id="sample_div2">
  6666. <div id="sample_div">
  6667. Sample1
  6668. <div id="sample_div3">
  6669. <div id="sample_div4">
  6670. Sample2
  6671. </div>
  6672. Sample3
  6673. </div>
  6674. <div id="sample_div5">
  6675. Sample4
  6676. <div id="sample_div6">
  6677. Sample5
  6678. </div>
  6679. </div>
  6680. </div>
  6681. </div>
  6682. </div>
  6683. <script type="text/javascript">
  6684. var firstChild = $Element("sample_div").first();
  6685. // id가 sample_div3인 DIV를 래핑한 $Element를 반환
  6686. </script>
  6687. */
  6688. jindo.$Element.prototype.first = function() {
  6689. var el = this._element.firstElementChild||this._element.firstChild;
  6690. if (!el) return null;
  6691. while(el && el.nodeType != 1) el = el.nextSibling;
  6692. return el?jindo.$Element(el):null;
  6693. }
  6694. /**
  6695. * HTML 엘리먼트의 마지막 자식 엘리먼트 노드를 반환한다.
  6696. *
  6697. * @return {$Element} 마지막 자식 엘리먼트 노드
  6698. * @since 1.2.0
  6699. *
  6700. * @see $Element#parent
  6701. * @see $Element#child
  6702. * @see $Element#prev
  6703. * @see $Element#next
  6704. * @see $Element#first
  6705. * @see $Element#indexOf
  6706. *
  6707. * @example
  6708. <div id="sample_div1">
  6709. <div id="sample_div2">
  6710. <div id="sample_div">
  6711. Sample1
  6712. <div id="sample_div3">
  6713. <div id="sample_div4">
  6714. Sample2
  6715. </div>
  6716. Sample3
  6717. </div>
  6718. <div id="sample_div5">
  6719. Sample4
  6720. <div id="sample_div6">
  6721. Sample5
  6722. </div>
  6723. </div>
  6724. </div>
  6725. </div>
  6726. </div>
  6727. <script type="text/javascript">
  6728. var lastChild = $Element("sample_div").last();
  6729. // id가 sample_div5인 DIV를 래핑한 $Element를 반환
  6730. </script>
  6731. */
  6732. jindo.$Element.prototype.last = function() {
  6733. var el = this._element.lastElementChild||this._element.lastChild;
  6734. if (!el) return null;
  6735. while(el && el.nodeType != 1) el = el.previousSibling;
  6736. return el?jindo.$Element(el):null;
  6737. }
  6738. /**
  6739. * HTML 엘리먼트의 부모 엘리먼트 노드를 확인한다.
  6740. *
  6741. * @param {HTML Element | String | $Element} element 부모 노드인지 확인할 HTML 엘리먼트.<br>
  6742. * <br>
  6743. * 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  6744. * <br>
  6745. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 확인한다.<br>
  6746. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 확인한다.<br>
  6747. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 확인한다.
  6748. * @return {Boolean} 매개 변수가 부모 엘리먼트 노드이면 true , 그렇지 않으면 false 반환한다.
  6749. *
  6750. * @see $Element#isParentOf
  6751. *
  6752. * @example
  6753. <div id="parent">
  6754. <div id="child">
  6755. <div id="grandchild"></div>
  6756. </div>
  6757. </div>
  6758. <div id="others"></div>
  6759. ...
  6760. // 부모/자식 확인하기
  6761. $Element("child").isChildOf("parent"); // 결과 : true
  6762. $Element("others").isChildOf("parent"); // 결과 : false
  6763. $Element("grandchild").isChildOf("parent"); // 결과 : true
  6764. */
  6765. jindo.$Element.prototype.isChildOf = function(element) {
  6766. return jindo.$Element._contain(jindo.$Element(element).$value(),this._element);
  6767. };
  6768. /**
  6769. * HTML 엘리먼트의 자식 엘리먼트 노드를 확인한다.
  6770. *
  6771. * @param {HTML Element | String | $Element} element 자식 노드인지 확인할 HTML 엘리먼트. 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다가매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 확인한다.<br>
  6772. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 확인한다.<br>
  6773. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 확인한다.
  6774. * @return {Boolean} 매개 변수가 자식 엘리먼트 노드이면 true , 그렇지 않으면 false 반환한다.
  6775. *
  6776. * @see $Element#isChildOf
  6777. *
  6778. * @example
  6779. <div id="parent">
  6780. <div id="child"></div>
  6781. </div>
  6782. <div id="others"></div>
  6783. ...
  6784. // 부모/자식 확인하기
  6785. $Element("parent").isParentOf("child"); // 결과 : true
  6786. $Element("others").isParentOf("child"); // 결과 : false
  6787. $Element("parent").isParentOf("grandchild");// 결과 : true
  6788. */
  6789. jindo.$Element.prototype.isParentOf = function(element) {
  6790. return jindo.$Element._contain(this._element, jindo.$Element(element).$value());
  6791. };
  6792. /**
  6793. * isChildOf , isParentOf의 기본이 되는 API(IE에서는 contains,기타 브라우져에는 compareDocumentPosition을 사용하고 둘다 없는 경우는 기존 레거시 API사용.)
  6794. * @param {HTMLElement} eParent 부모노드
  6795. * @param {HTMLElement} eChild 자식노드
  6796. * @ignore
  6797. */
  6798. jindo.$Element._contain = function(eParent,eChild){
  6799. if (document.compareDocumentPosition) {
  6800. jindo.$Element._contain = function(eParent,eChild){
  6801. return !!(eParent.compareDocumentPosition(eChild)&16);
  6802. }
  6803. }else if(document.body.contains){
  6804. jindo.$Element._contain = function(eParent,eChild){
  6805. return (eParent !== eChild)&&(eParent.contains ? eParent.contains(eChild) : true);
  6806. }
  6807. }else{
  6808. jindo.$Element._contain = function(eParent,eChild){
  6809. var e = eParent;
  6810. var el = eChild;
  6811. while(e && e.parentNode) {
  6812. e = e.parentNode;
  6813. if (e == el) return true;
  6814. }
  6815. return false;
  6816. }
  6817. }
  6818. return jindo.$Element._contain(eParent,eChild);
  6819. }
  6820. /**
  6821. * 현재의 HTML 엘리먼트와 동일한 엘리먼트인지 확인한다.
  6822. *
  6823. * @remark DOM3의 API중 isSameNode와 같은 함수로 레퍼런스까지 확인 함수이다.
  6824. * @remark isEqualNode와는 다른 함수이기 때문에 헷갈리지 않도록 한다.
  6825. *
  6826. * @param {HTML Element | String | $Element} element 같은 HTML 엘리먼트인지 확인할 HTML 엘리먼트. 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  6827. * <br>
  6828. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 확인한다.<br>
  6829. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 확인한다.<br>
  6830. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 확인한다.
  6831. * @return {Boolean} 매개 변수가 같은 HTML 엘리먼트이면 true , 그렇지 않으면 false 반환한다.
  6832. *
  6833. * @example
  6834. <div id="sample1"><span>Sample</span></div>
  6835. <div id="sample2"><span>Sample</span></div>
  6836. ...
  6837. // 같은 HTML 엘리먼트인지 확인
  6838. var welSpan1 = $Element("sample1").first(); // <span>Sample</span>
  6839. var welSpan2 = $Element("sample2").first(); // <span>Sample</span>
  6840. welSpan1.isEqual(welSpan2); // 결과 : false
  6841. welSpan1.isEqual(welSpan1); // 결과 : true
  6842. */
  6843. jindo.$Element.prototype.isEqual = function(element) {
  6844. try {
  6845. return (this._element === jindo.$Element(element).$value());
  6846. } catch(e) {
  6847. return false;
  6848. }
  6849. };
  6850. /**
  6851. * HTML 엘리먼트에 이벤트를 발생시킨다.
  6852. *
  6853. * @param {String} sEvent 실행할 이벤트 이름. on 접두사는 생략한다.
  6854. * @param {Object} [oProps] 이벤트 실행 사용할 이벤트 객체의 속성을 지정한다.
  6855. * @return {$Element} 이벤트가 발생한 HTML 엘리먼트
  6856. *
  6857. * @since WebKit 계열에서는 이벤트 객체의 keyCode read-only 관계로 key 이벤트를 발생시킬 경우 keyCode 값이 설정되지 않는다. 1.4.1 부터 keyCode 값을 설정할 있다.
  6858. *
  6859. * @example
  6860. $Element("div").fireEvent("click", {left : true, middle : false, right : false}); // click 이벤트 발생
  6861. $Element("div").fireEvent("mouseover", {screenX : 50, screenY : 50, clientX : 50, clientY : 50}); // mouseover 이벤트 발생
  6862. $Element("div").fireEvent("keydown", {keyCode : 13, alt : true, shift : false ,meta : false, ctrl : true}); // keydown 이벤트 발생
  6863. */
  6864. jindo.$Element.prototype.fireEvent = function(sEvent, oProps) {
  6865. function IE(sEvent, oProps) {
  6866. sEvent = (sEvent+"").toLowerCase();
  6867. var oEvent = document.createEventObject();
  6868. if(oProps){
  6869. for (k in oProps){
  6870. if(oProps.hasOwnProperty(k))
  6871. oEvent[k] = oProps[k];
  6872. }
  6873. oEvent.button = (oProps.left?1:0)+(oProps.middle?4:0)+(oProps.right?2:0);
  6874. oEvent.relatedTarget = oProps.relatedElement||null;
  6875. }
  6876. this._element.fireEvent("on"+sEvent, oEvent);
  6877. return this;
  6878. };
  6879. function DOM2(sEvent, oProps) {
  6880. var sType = "HTMLEvents";
  6881. sEvent = (sEvent+"").toLowerCase();
  6882. if (sEvent == "click" || sEvent.indexOf("mouse") == 0) {
  6883. sType = "MouseEvent";
  6884. if (sEvent == "mousewheel") sEvent = "dommousescroll";
  6885. } else if (sEvent.indexOf("key") == 0) {
  6886. sType = "KeyboardEvent";
  6887. }
  6888. var evt;
  6889. if (oProps) {
  6890. oProps.button = 0 + (oProps.middle?1:0) + (oProps.right?2:0);
  6891. oProps.ctrl = oProps.ctrl||false;
  6892. oProps.alt = oProps.alt||false;
  6893. oProps.shift = oProps.shift||false;
  6894. oProps.meta = oProps.meta||false;
  6895. switch (sType) {
  6896. case 'MouseEvent':
  6897. evt = document.createEvent(sType);
  6898. evt.initMouseEvent( sEvent, true, true, null, oProps.detail||0, oProps.screenX||0, oProps.screenY||0, oProps.clientX||0, oProps.clientY||0,
  6899. oProps.ctrl, oProps.alt, oProps.shift, oProps.meta, oProps.button, oProps.relatedElement||null);
  6900. break;
  6901. case 'KeyboardEvent':
  6902. if (window.KeyEvent) {
  6903. evt = document.createEvent('KeyEvents');
  6904. evt.initKeyEvent(sEvent, true, true, window, oProps.ctrl, oProps.alt, oProps.shift, oProps.meta, oProps.keyCode, oProps.keyCode);
  6905. } else {
  6906. try {
  6907. evt = document.createEvent("Events");
  6908. } catch (e){
  6909. evt = document.createEvent("UIEvents");
  6910. } finally {
  6911. evt.initEvent(sEvent, true, true);
  6912. evt.ctrlKey = oProps.ctrl;
  6913. evt.altKey = oProps.alt;
  6914. evt.shiftKey = oProps.shift;
  6915. evt.metaKey = oProps.meta;
  6916. evt.keyCode = oProps.keyCode;
  6917. evt.which = oProps.keyCode;
  6918. }
  6919. }
  6920. break;
  6921. default:
  6922. evt = document.createEvent(sType);
  6923. evt.initEvent(sEvent, true, true);
  6924. }
  6925. }else{
  6926. evt = document.createEvent(sType);
  6927. evt.initEvent(sEvent, true, true);
  6928. }
  6929. this._element.dispatchEvent(evt);
  6930. return this;
  6931. };
  6932. jindo.$Element.prototype.fireEvent = (typeof this._element.dispatchEvent != "undefined")?DOM2:IE;
  6933. return this.fireEvent(sEvent, oProps);
  6934. };
  6935. /**
  6936. * HTML 엘리먼트의 자식 노드를 모두 제거한다.
  6937. *
  6938. * @return {$Element} 자식 노드를 모두 제거한 현재의 $Element 객체
  6939. *
  6940. * @see $Element#leave
  6941. * @see $Element#remove
  6942. *
  6943. * @example
  6944. // 자식 노드를 모두 제거
  6945. $Element("sample").empty();
  6946. //Before
  6947. <div id="sample"><span>노드</span> <span></span> </div>
  6948. //After
  6949. <div id="sample"></div>
  6950. */
  6951. jindo.$Element.prototype.empty = function() {
  6952. jindo.$$.release();
  6953. this.html("");
  6954. return this;
  6955. };
  6956. /**
  6957. * HTML 엘리먼트의 특정 자식 노드를 제거한다. 제거되는 자식 엘리먼트 노드의 이벤트 핸들러도 제거한다.
  6958. *
  6959. * @param {HTML Element | String | $Element} oChild 제거할 자식 엘리먼트 노드.<br>
  6960. * <br>
  6961. * 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  6962. * <br>
  6963. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 제거한다.<br>
  6964. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 제거한다.<br>
  6965. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 제거한다.
  6966. * @return {$Element} 자식 노드를 모두 제거한 현재의 $Element 객체
  6967. *
  6968. * @see $Element#empty
  6969. * @see $Element#leave
  6970. *
  6971. * @example
  6972. // 특정 자식 노드를 제거
  6973. $Element("sample").remove("child2");
  6974. //Before
  6975. <div id="sample"><span id="child1">노드</span> <span id="child2"></span></div>
  6976. //After
  6977. <div id="sample"><span id="child1">노드</span> </div>
  6978. */
  6979. jindo.$Element.prototype.remove = function(oChild) {
  6980. jindo.$$.release();
  6981. jindo.$Element(oChild).leave();
  6982. return this;
  6983. }
  6984. /**
  6985. * HTML 엘리먼트를 부모 엘리먼트 노드에서 제거한다.<br>
  6986. * HTML 엘러먼트에 등록된 이벤트 핸들러도 제거한다.
  6987. *
  6988. * @return {$Element} 부모 엘리먼트 노드에서 제거 현재의 $Element 객체
  6989. *
  6990. * @see $Element#empty
  6991. * @see $Element#remove
  6992. *
  6993. * @example
  6994. // 부모 엘리먼트 노드에서 제거
  6995. $Element("sample").leave();
  6996. //Before
  6997. <div>
  6998. <div id="sample"><span>노드</span> <span></span> </div>
  6999. </div>
  7000. //After
  7001. // <div id="sample"><span>노드</span> <span>모두</span> 삭제하기 </div>를 래핑한 $Element가 반환된다
  7002. <div>
  7003. </div>
  7004. */
  7005. jindo.$Element.prototype.leave = function() {
  7006. var e = this._element;
  7007. if (e.parentNode) {
  7008. jindo.$$.release();
  7009. e.parentNode.removeChild(e);
  7010. }
  7011. jindo.$Fn.freeElement(this._element);
  7012. return this;
  7013. };
  7014. /**
  7015. * HTML 엘리먼트를 다른 HTML 엘리먼트로 감싼다.
  7016. *
  7017. * @param {String | HTML Element | $Element} wrapper 감쌀 HTML 엘리먼트. 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  7018. * <br>
  7019. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 사용한다.<br>
  7020. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 사용한다.<br>
  7021. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 사용한다.
  7022. * @return {$Element} 새로운 HTML 엘리먼트로 감싼 $Element 개체
  7023. *
  7024. * @example
  7025. $Element("sample1").wrap("sample2");
  7026. //Before
  7027. <div id="sample1"><span>Sample</span></div>
  7028. <div id="sample2"><span>Sample</span></div>
  7029. //After
  7030. <div id="sample2"><span>Sample</span><div id="sample1"><span>Sample</span></div></div>
  7031. * @example
  7032. $Element("box").wrap($('<DIV>'));
  7033. //Before
  7034. <span id="box"></span>
  7035. //After
  7036. <div><span id="box"></span></div>
  7037. */
  7038. jindo.$Element.prototype.wrap = function(wrapper) {
  7039. var e = this._element;
  7040. wrapper = jindo.$Element(wrapper).$value();
  7041. if (e.parentNode) {
  7042. e.parentNode.insertBefore(wrapper, e);
  7043. }
  7044. wrapper.appendChild(e);
  7045. return this;
  7046. };
  7047. /**
  7048. * HTML 엘리먼트의 텍스트 노드가 브라우저에서 줄로 보이도록 길이를 조절한다.
  7049. *
  7050. * @remark 메서드는 HTML 엘리먼트가 텍스트 노드만을 포함한다고 가정한다. 따라서, 외의 상황에서의 동작은 보장하지 않는다.
  7051. * @remark 브라우저에서의 HTML 엘리먼트의 너비를 기준으로 텍스트 노드의 길이를 정하므로 HTML 엘리먼트는 반드시 보이는 상태여야 한다.
  7052. * @remark 화면에 전체 텍스트 노드가 보였다가 줄어드는 경우가 있다. 이런 경우, HTML 엘리먼트에서 overflow:hidden 속성을 활용한다.
  7053. *
  7054. * @param {String} [stringTail] 말줄임 표시자. <br>
  7055. * 매개 변수에 지정한 문자열을 텍스트 노드 끝에 붙이고 텍스트 노드의 길이를 조절한다.<br>
  7056. * 매개 변수를 생락하면 말줄임표('...') 사용한다.
  7057. *
  7058. * @example
  7059. $Element("sample_span").ellipsis();
  7060. //Before
  7061. <div style="width:300px; border:1px solid #CCCCCC; padding:10px">
  7062. <span id="sample_span">NHN은 검색과 게임을 양축으로 혁신적이고 편리한 온라인 서비스를 꾸준히 선보이며 디지털 라이프를 선도하고 있습니다.</span>
  7063. </div>
  7064. //After
  7065. <div style="width:300px; border:1px solid #CCCCCC; padding:10px">
  7066. <span id="sample_span">NHN은 검색과 게임을 양축으로 혁신적...</span>
  7067. </div>
  7068. */
  7069. jindo.$Element.prototype.ellipsis = function(stringTail) {
  7070. stringTail = stringTail || "...";
  7071. var txt = this.text();
  7072. var len = txt.length;
  7073. var padding = parseInt(this.css("paddingTop"),10) + parseInt(this.css("paddingBottom"),10);
  7074. var cur_h = this.height() - padding;
  7075. var i = 0;
  7076. var h = this.text('A').height() - padding;
  7077. if (cur_h < h * 1.5) return this.text(txt);
  7078. cur_h = h;
  7079. while(cur_h < h * 1.5) {
  7080. i += Math.max(Math.ceil((len - i)/2), 1);
  7081. cur_h = this.text(txt.substring(0,i)+stringTail).height() - padding;
  7082. }
  7083. while(cur_h > h * 1.5) {
  7084. i--;
  7085. cur_h = this.text(txt.substring(0,i)+stringTail).height() - padding;
  7086. }
  7087. };
  7088. /**
  7089. * HTML 엘리먼트에서 매개 변수가 번째 자식 엘리먼트 노드인지 확인하여 인덱스를 반환한다.
  7090. *
  7091. * @param {String | HTML Element | $Element} element 확인할 HTML 엘리먼트. 문자열, HTML 엘리먼트, 혹은 $Element 매개 변수로 지정할 있다.<br>
  7092. * <br>
  7093. * 매개 변수가 문자열이면 해당 문자열을 id 하는 HTML 엘리먼트를 사용한다.<br>
  7094. * 매개 변수가 HTML 엘리먼트이면 해당 엘리먼트를 사용한다.<br>
  7095. * 매개 변수가 $Element 이면 $Element 객체 내부의 HTML 엘리먼트를 사용한다.
  7096. * @return {Number} 검색 결과 인덱스.<br>
  7097. * 인덱스는 0 부터 시작하며, 찾지 못한 경우에는 -1 반환한다.
  7098. *
  7099. * @since 1.2.0
  7100. *
  7101. * @see $Element#parent
  7102. * @see $Element#child
  7103. * @see $Element#prev
  7104. * @see $Element#next
  7105. * @see $Element#first
  7106. * @see $Element#last
  7107. *
  7108. * @example
  7109. <div id="sample_div1">
  7110. <div id="sample_div">
  7111. <div id="sample_div2">
  7112. Sample1
  7113. </div>
  7114. <div id="sample_div3">
  7115. <div id="sample_div4">
  7116. Sample2
  7117. </div>
  7118. Sample3
  7119. </div>
  7120. <div id="sample_div5">
  7121. Sample4
  7122. <div id="sample_div6">
  7123. Sample5
  7124. </div>
  7125. </div>
  7126. </div>
  7127. </div>
  7128. <script type="text/javascript">
  7129. var welSample = $Element("sample_div");
  7130. welSample.indexOf($Element("sample_div1")); // 결과 : -1
  7131. welSample.indexOf($Element("sample_div2")); // 결과 : 0
  7132. welSample.indexOf($Element("sample_div3")); // 결과 : 1
  7133. welSample.indexOf($Element("sample_div4")); // 결과 : -1
  7134. welSample.indexOf($Element("sample_div5")); // 결과 : 2
  7135. welSample.indexOf($Element("sample_div6")); // 결과 : -1
  7136. </script>
  7137. */
  7138. jindo.$Element.prototype.indexOf = function(element) {
  7139. try {
  7140. var e = jindo.$Element(element).$value();
  7141. var n = this._element.childNodes;
  7142. var c = 0;
  7143. var l = n.length;
  7144. for (var i=0; i < l; i++) {
  7145. if (n[i].nodeType != 1) continue;
  7146. if (n[i] === e) return c;
  7147. c++;
  7148. }
  7149. }catch(e){}
  7150. return -1;
  7151. };
  7152. /**
  7153. * HTML 엘리먼트에서 특정 CSS 셀렉터(selector) 만족하는 하위 엘리먼트 노드를 찾는다.
  7154. *
  7155. * @param {String} sSelector CSS 셀렉터
  7156. * @return {Array} CSS 셀렉터 조건을 만족하는 HTML 엘리먼트의 배열을 반환한다.<br>
  7157. * 만족하는 HTML 엘리먼트가 존재하지 않으면 배열을 반환한다.
  7158. *
  7159. * @see $Element#query
  7160. * @see $Element#queryAll
  7161. *
  7162. * @example
  7163. <div id="sample">
  7164. <div></div>
  7165. <div class="pink"></div>
  7166. <div></div>
  7167. <div class="pink"></div>
  7168. <div></div>
  7169. <div class="blue"></div>
  7170. <div class="blue"></div>
  7171. </div>
  7172. <script type="text/javascript">
  7173. $Element("sample").queryAll(".pink");
  7174. // <div class="pink"></div>와 <div class="pink"></div>를 원소로 하는 배열을 반환
  7175. $Element("sample").queryAll(".green");
  7176. // [] 빈 배열을 반환
  7177. </script>
  7178. */
  7179. jindo.$Element.prototype.queryAll = function(sSelector) {
  7180. return jindo.$$(sSelector, this._element);
  7181. };
  7182. /**
  7183. * HTML 엘리먼트에서 특정 CSS 셀렉터(selector) 만족하는 번째 하위 엘리먼트 노드를 반환한다.
  7184. *
  7185. * @param {String} sSelector CSS 셀렉터
  7186. * @return {HTML Element} CSS 셀렉터 조건을 만족하는 번째 HTML 엘리먼트.<br>
  7187. * 만족하는 HTML 엘리먼트가 존재하지 않으면 null 반환한다.
  7188. *
  7189. * @see $Element#test
  7190. * @see $Element#queryAll
  7191. *
  7192. * @example
  7193. <div id="sample">
  7194. <div></div>
  7195. <div class="pink"></div>
  7196. <div></div>
  7197. <div class="pink"></div>
  7198. <div></div>
  7199. <div class="blue"></div>
  7200. <div class="blue"></div>
  7201. </div>
  7202. <script type="text/javascript">
  7203. $Element("sample").query(".pink");
  7204. // 첫 번째 <div class="pink"></div> DIV 엘리먼트를 반환
  7205. $Element("sample").query(".green");
  7206. // null 을 반환
  7207. </script>
  7208. */
  7209. jindo.$Element.prototype.query = function(sSelector) {
  7210. return jindo.$$.getSingle(sSelector, this._element);
  7211. };
  7212. /**
  7213. * HTML 엘리먼트에서 특정 CSS 셀렉터(selector) 만족하는지 확인한다.
  7214. *
  7215. * @param {String} sSelector CSS 셀렉터
  7216. * @return {Boolean} CSS 셀렉터 조건을 만족하는지 확인하여 true/false 반환한다.
  7217. *
  7218. * @see $Element#query
  7219. * @see $Element#queryAll
  7220. *
  7221. * @example
  7222. <div id="sample" class="blue"></div>
  7223. <script type="text/javascript">
  7224. $Element("sample").test(".blue"); // 결과 : true
  7225. $Element("sample").test(".red"); // 결과 : false
  7226. </script>
  7227. */
  7228. jindo.$Element.prototype.test = function(sSelector) {
  7229. return jindo.$$.test(this._element, sSelector);
  7230. };
  7231. /**
  7232. * HTML 엘리먼트를 기준으로 XPath 문법을 사용하여 해당하는 HTML 엘리먼트를 가져온다.
  7233. *
  7234. * @remark 지원하는 문법이 무척 제한적으로 특수한 경우에서만 사용하는 것을 권장한다.
  7235. *
  7236. * @param {String} sXPath XPath 문법
  7237. * @return {Array} XPath 해당하는 HTML 엘리먼트를 원소로 하는 배열을 반환한다.
  7238. *
  7239. * @example
  7240. <div id="sample">
  7241. <div>
  7242. <div>1</div>
  7243. <div>2</div>
  7244. <div>3</div>
  7245. <div>4</div>
  7246. <div>5</div>
  7247. <div>6</div>
  7248. </div>
  7249. </div>
  7250. <script type="text/javascript">
  7251. $Element("sample").xpathAll("div/div[5]");
  7252. // <div>5</div> 엘리먼트를 원소로 하는 배열이 반환 됨
  7253. </script>
  7254. */
  7255. jindo.$Element.prototype.xpathAll = function(sXPath) {
  7256. return jindo.$$.xpath(sXPath, this._element);
  7257. };
  7258. /**
  7259. * insertAdjacentHTML 함수. 직접사용하지 못함.
  7260. * @ignore
  7261. */
  7262. jindo.$Element.insertAdjacentHTML = function(ins,html,insertType,type,fn){
  7263. var _ele = ins._element;
  7264. if( _ele.insertAdjacentHTML && !(/^<(option|tr|td|th|col)(?:.*?)>/.test(html.replace(/^(\s| )+|(\s| )+$/g, "").toLowerCase()))){
  7265. _ele.insertAdjacentHTML(insertType, html);
  7266. }else{
  7267. var oDoc = _ele.ownerDocument || _ele.document || document;
  7268. var fragment = oDoc.createDocumentFragment();
  7269. var defaultElement;
  7270. var sTag = html.replace(/^(\s| )+|(\s| )+$/g, "");
  7271. var oParentTag = {
  7272. "option" : "select",
  7273. "tr" : "tbody",
  7274. "thead" : "table",
  7275. "tbody" : "table",
  7276. "col" : "table",
  7277. "td" : "tr",
  7278. "th" : "tr",
  7279. "div" : "div"
  7280. }
  7281. var aMatch = /^\<(option|tr|thead|tbody|td|th|col)(?:.*?)\>/i.exec(sTag);
  7282. var sChild = aMatch === null ? "div" : aMatch[1].toLowerCase();
  7283. var sParent = oParentTag[sChild] ;
  7284. defaultElement = jindo._createEle(sParent,sTag,oDoc,true);
  7285. var scripts = defaultElement.getElementsByTagName("script");
  7286. for ( var i = 0, l = scripts.length; i < l; i++ ){
  7287. scripts[i].parentNode.removeChild( scripts[i] );
  7288. }
  7289. while ( defaultElement[ type ]){
  7290. fragment.appendChild( defaultElement[ type ] );
  7291. }
  7292. fn(fragment.cloneNode(true));
  7293. }
  7294. return ins;
  7295. }
  7296. /**
  7297. * HTML 엘리먼트 내부 HTML 가장 뒤에 HTML 덧붙인다.
  7298. *
  7299. * @param {String} sHTML 덧붙일 HTML 문자열
  7300. * @return {$Element} 1.4.8부터 내부 HTML 변경한 현재의 $Element 객체를 반환한다.
  7301. * @since 1.4.6 부터 사용 가능.
  7302. * @since 1.4.8 부터 $Element 객체를 반환한다.
  7303. * @see $Element#prependHTML
  7304. * @see $Element#beforeHTML
  7305. * @see $Element#afterHTML
  7306. *
  7307. * @example
  7308. // 내부 HTML 가장 뒤에 덧붙이기
  7309. $Element("sample_ul").appendHTML("<li>3</li><li>4</li>");
  7310. //Before
  7311. <ul id="sample_ul">
  7312. <li>1</li>
  7313. <li>2</li>
  7314. </ul>
  7315. //After
  7316. <ul id="sample_ul">
  7317. <li>1</li>
  7318. <li>2</li>
  7319. <li>3</li>
  7320. <li>4</li>
  7321. </ul>
  7322. */
  7323. jindo.$Element.prototype.appendHTML = function(sHTML) {
  7324. return jindo.$Element.insertAdjacentHTML(this,sHTML,"beforeEnd","firstChild",jindo.$Fn(function(oEle){
  7325. this.append(oEle);
  7326. },this).bind());
  7327. };
  7328. /**
  7329. * HTML 엘리먼트 내부 HTML 가장 앞에 HTML 삽입한다.
  7330. *
  7331. * @param {String} sHTML 삽입할 HTML 문자열
  7332. * @return {$Element} 1.4.8부터 내부 HTML 변경한 현재의 $Element 객체를 반환한다.
  7333. * @since 1.4.6부터 사용 가능.
  7334. * @see $Element#appendHTML
  7335. * @see $Element#beforeHTML
  7336. * @see $Element#afterHTML
  7337. *
  7338. * @example
  7339. // 내부 HTML 가장 앞에 삽입
  7340. $Element("sample_ul").prependHTML("<li>3</li><li>4</li>");
  7341. //Before
  7342. <ul id="sample_ul">
  7343. <li>1</li>
  7344. <li>2</li>
  7345. </ul>
  7346. //After
  7347. <ul id="sample_ul">
  7348. <li>4</li>
  7349. <li>3</li>
  7350. <li>1</li>
  7351. <li>2</li>
  7352. </ul>
  7353. */
  7354. jindo.$Element.prototype.prependHTML = function(sHTML) {
  7355. return jindo.$Element.insertAdjacentHTML(this,sHTML,"afterBegin","lastChild",jindo.$Fn(function(oEle){
  7356. this.prepend(oEle);
  7357. },this).bind());
  7358. };
  7359. /**
  7360. * HTML 엘리먼트 앞에 HTML 삽입한다.
  7361. *
  7362. * @param {String} sHTML 삽입할 HTML 문자열
  7363. * @return {$Element} 1.4.8부터 현재의 $Element 객체를 반환한다.
  7364. * @since 1.4.6부터 사용 가능.
  7365. * @see $Element#appendHTML
  7366. * @see $Element#prependHTML
  7367. * @see $Element#afterHTML
  7368. *
  7369. * @example
  7370. var welSample = $Element("sample_ul");
  7371. welSample.beforeHTML("<ul><li>3</li><li>4</li></ul>");
  7372. welSample.beforeHTML("<ul><li>5</li><li>6</li></ul>");
  7373. //Before
  7374. <ul id="sample_ul">
  7375. <li>1</li>
  7376. <li>2</li>
  7377. </ul>
  7378. //After
  7379. <ul>
  7380. <li>3</li>
  7381. <li>4</li>
  7382. </ul>
  7383. <ul>
  7384. <li>5</li>
  7385. <li>6</li>
  7386. </ul>
  7387. <ul id="sample_ul">
  7388. <li>1</li>
  7389. <li>2</li>
  7390. </ul>
  7391. */
  7392. jindo.$Element.prototype.beforeHTML = function(sHTML) {
  7393. return jindo.$Element.insertAdjacentHTML(this,sHTML,"beforeBegin","firstChild",jindo.$Fn(function(oEle){
  7394. this.before(oEle);
  7395. },this).bind());
  7396. };
  7397. /**
  7398. * HTML 엘리먼트 뒤에 HTML 덧붙인다.
  7399. * @param {String} sHTML 덧붙일 HTML 문자열
  7400. * @returns {$Element} 1.4.8부터 현재의 $Element 객체를 반환한다.
  7401. * @since 1.4.6부터 사용 가능.
  7402. * @see $Element#appendHTML
  7403. * @see $Element#prependHTML
  7404. * @see $Element#beforeHTML
  7405. * @example
  7406. var welSample = $Element("sample_ul");
  7407. welSample.beforeHTML("<ul><li>3</li><li>4</li></ul>");
  7408. welSample.beforeHTML("<ul><li>5</li><li>6</li></ul>");
  7409. //Before
  7410. <ul id="sample_ul">
  7411. <li>1</li>
  7412. <li>2</li>
  7413. </ul>
  7414. //After
  7415. <ul id="sample_ul">
  7416. <li>1</li>
  7417. <li>2</li>
  7418. </ul>
  7419. <ul>
  7420. <li>5</li>
  7421. <li>6</li>
  7422. </ul>
  7423. <ul>
  7424. <li>3</li>
  7425. <li>4</li>
  7426. </ul>
  7427. */
  7428. jindo.$Element.prototype.afterHTML = function(sHTML) {
  7429. return jindo.$Element.insertAdjacentHTML(this,sHTML,"afterEnd","lastChild",jindo.$Fn(function(oEle){
  7430. this._element.parentNode.insertBefore( oEle, this._element.nextSibling );
  7431. },this).bind());
  7432. };
  7433. /**
  7434. * 이벤트 델리게이션으로 이벤트를 처리한다.<br>
  7435. * 이벤트 델리게이션이란 이벤트 버블링을 이용하여 효율적으로 이벤트를 관리하는 방법이다.<br>
  7436. * 자세한 내용은 아래의 URL을 참고한다.<br>
  7437. * <br>
  7438. *
  7439. * <ul>
  7440. * <li><a href="http://devcode.nhncorp.com/projects/jindo/wiki/EventDelegate" target="_blank">Event Delegate ?</a></li>
  7441. * <ul>
  7442. *
  7443. * @param {String} sEvent 이벤트 이름. on 접두사는 생략한다.<br>
  7444. * domready, mousewheel, mouseenter, mouseleave 지원하지 않는다.<br>
  7445. *
  7446. * @param {String | Function} vFilter 원하는 HTML 엘리먼트에 대해서만 이벤트를 실행하도록 하기 위한 필터이다.<br>
  7447. * <br>
  7448. * 필터에는 CSS 셀렉터와 함수의 가지 타입이 있다.<br>
  7449. * <br>
  7450. * 필터를 CSS 셀렉터를 사용하려면 문자열을 매개 변수로 지정한다.<br>
  7451. * <br>
  7452. * 필터를 함수로 사용하려면 Boolean 반환하는 함수를 매개 변수로 지정한다.<br>
  7453. * 필터 함수의 번째 매개 변수는 HTML 엘리먼트 자신이고, 번째 매개 변수는 이벤트가 발생한 HTML 엘리먼트이다.
  7454. *
  7455. * @param {Function} fpCallback 필터에서 true 반환된 경우 실행되는 콜백 함수이다.<br>
  7456. * 매개 변수로 이벤트 객체가 지정된다.
  7457. *
  7458. * @return {$Element} $Element 객체를 리턴한다.
  7459. * @since 1.4.6부터 사용 가능.
  7460. * @see $Element#undelegate
  7461. *
  7462. * @example
  7463. <ul id="parent">
  7464. <li class="odd">1</li>
  7465. <li>2</li>
  7466. <li class="odd">3</li>
  7467. <li>4</li>
  7468. </ul>
  7469. // CSS 셀렉터를 필터로 사용하는 경우
  7470. $Element("parent").delegate("click",
  7471. ".odd", // 필터
  7472. function(eEvent){ // 콜백 함수
  7473. alert("odd 클래스를 가진 li가 클릭 될 때 실행");
  7474. });
  7475. * @example
  7476. <ul id="parent">
  7477. <li class="odd">1</li>
  7478. <li>2</li>
  7479. <li class="odd">3</li>
  7480. <li>4</li>
  7481. </ul>
  7482. // 함수를 필터로 사용하는 경우
  7483. $Element("parent").delegate("click",
  7484. function(oEle,oClickEle){ // 필터
  7485. return oClickEle.innerHTML == "2"
  7486. },
  7487. function(eEvent){ // 콜백 함수
  7488. alert("클릭한 엘리먼트의 innerHTML이 2인 경우에 실행");
  7489. });
  7490. */
  7491. jindo.$Element.prototype.delegate = function(sEvent , vFilter , fpCallback){
  7492. if(!this._element["_delegate_"+sEvent]){
  7493. this._element["_delegate_"+sEvent] = {};
  7494. var fAroundFunc = jindo.$Fn(function(sEvent,wEvent){
  7495. wEvent = wEvent || window.event;
  7496. if (typeof wEvent.currentTarget == "undefined") {
  7497. wEvent.currentTarget = this._element;
  7498. }
  7499. var oEle = wEvent.target || wEvent.srcElement;
  7500. var aData = this._element["_delegate_"+sEvent];
  7501. var data,func,event,resultFilter;
  7502. for(var i in aData){
  7503. data = aData[i];
  7504. resultFilter = data.checker(oEle);
  7505. if(resultFilter[0]){
  7506. func = data.func;
  7507. event = jindo.$Event(wEvent);
  7508. event.element = resultFilter[1];
  7509. for(var j = 0, l = func.length ; j < l ;j++){
  7510. func[j](event);
  7511. }
  7512. }
  7513. }
  7514. },this).bind(sEvent);
  7515. jindo.$Element._eventBind(this._element,sEvent,fAroundFunc);
  7516. var oEle = this._element;
  7517. oEle["_delegate_"+sEvent+"_func"] = fAroundFunc;
  7518. if (this._element["_delegate_events"]) {
  7519. this._element["_delegate_events"].push(sEvent);
  7520. }else{
  7521. this._element["_delegate_events"] = [sEvent];
  7522. }
  7523. oEle = null;
  7524. }
  7525. this._bind(sEvent,vFilter,fpCallback);
  7526. return this;
  7527. }
  7528. /**
  7529. * 이벤트를 바인딩 하는 함수.
  7530. * @param {Element} oEle 엘리먼트
  7531. * @param {Boolean} sEvent 이벤트 타입.
  7532. * @param {Function} fAroundFunc 바인딩할 함수
  7533. * @ignore.
  7534. */
  7535. jindo.$Element._eventBind = function(oEle,sEvent,fAroundFunc){
  7536. if(oEle.addEventListener){
  7537. jindo.$Element._eventBind = function(oEle,sEvent,fAroundFunc){
  7538. oEle.addEventListener(sEvent,fAroundFunc,false);
  7539. }
  7540. }else{
  7541. jindo.$Element._eventBind = function(oEle,sEvent,fAroundFunc){
  7542. oEle.attachEvent("on"+sEvent,fAroundFunc);
  7543. }
  7544. }
  7545. jindo.$Element._eventBind(oEle,sEvent,fAroundFunc);
  7546. }
  7547. /**
  7548. * HTML 엘리먼트에 등록된 이벤트 델리게이션을 해제한다.
  7549. *
  7550. * @param {String} sEvent 이벤드 델리게이션 등록 사용한 이벤트 이름. on 접두사는 생략한다.
  7551. * @param {String|Function} vFilter 이벤트 델리게이션 등록 사용한 필터.
  7552. * @param {Function} fpCallback 이벤트 델리게이션 등록 사용한 콜백 함수.
  7553. * @return {$Element} $Element 객체를 리턴한다.
  7554. * @since 1.4.6부터 사용 가능.
  7555. * @see $Element#delegate
  7556. *
  7557. * @example
  7558. <ul id="parent">
  7559. <li class="odd">1</li>
  7560. <li>2</li>
  7561. <li class="odd">3</li>
  7562. <li>4</li>
  7563. </ul>
  7564. // 콜백 함수
  7565. var fnOddClass = function(eEvent){
  7566. alert("odd 클래스를 가진 li가 클릭 될 때 실행");
  7567. };
  7568. $Element("parent").delegate("click", ".odd", fnOddClass); // 이벤트 델리게이션 사용
  7569. $Element("parent").undelegate("click", ".odd", fnOddClass); // 이벤트 해제
  7570. */
  7571. jindo.$Element.prototype.undelegate = function(sEvent, vFilter, fpCallback){
  7572. this._unbind(sEvent,vFilter,fpCallback);
  7573. return this;
  7574. }
  7575. /**
  7576. * 딜리게이션으로 실행되어야 함수를 추가 하는 함수.
  7577. * @param {String} sEvent 이벤트 타입.
  7578. * @param {String|Function} vFilter cssquery,function 이렇게 2가지 타입이 들어옴.
  7579. * @param {Function} fpCallback 해당 cChecker에 들어오는 함수가 맞을때 실행되는 함수.
  7580. * @returns {$Element} $Element 객체.
  7581. * @since 1.4.6부터 사용가능.
  7582. * @ignore
  7583. */
  7584. jindo.$Element.prototype._bind = function(sEvent,vFilter,fpCallback){
  7585. var _aDataOfEvent = this._element["_delegate_"+sEvent];
  7586. if(_aDataOfEvent){
  7587. var fpCheck;
  7588. if(typeof vFilter == "string"){
  7589. fpCheck = jindo.$Fn(function(sCssquery,oEle){
  7590. var eIncludeEle = oEle;
  7591. var isIncludeEle = jindo.$$.test(oEle, sCssquery);
  7592. if(!isIncludeEle){
  7593. var aPropagationElements = this._getParent(oEle);
  7594. for(var i = 0, leng = aPropagationElements.length ; i < leng ; i++){
  7595. eIncludeEle = aPropagationElements[i];
  7596. if(jindo.$$.test(eIncludeEle, sCssquery)){
  7597. isIncludeEle = true;
  7598. break;
  7599. }
  7600. }
  7601. }
  7602. return [isIncludeEle,eIncludeEle];
  7603. },this).bind(vFilter);
  7604. }else if(typeof vFilter == "function"){
  7605. fpCheck = jindo.$Fn(function(fpFilter,oEle){
  7606. var eIncludeEle = oEle;
  7607. var isIncludeEle = fpFilter(this._element,oEle);
  7608. if(!isIncludeEle){
  7609. var aPropagationElements = this._getParent(oEle);
  7610. for(var i = 0, leng = aPropagationElements.length ; i < leng ; i++){
  7611. eIncludeEle = aPropagationElements[i];
  7612. if(fpFilter(this._element,eIncludeEle)){
  7613. isIncludeEle = true;
  7614. break;
  7615. }
  7616. }
  7617. }
  7618. return [isIncludeEle,eIncludeEle];
  7619. },this).bind(vFilter);
  7620. }
  7621. this._element["_delegate_"+sEvent] = jindo.$Element._addBind(_aDataOfEvent,vFilter,fpCallback,fpCheck);
  7622. }else{
  7623. alert("check your delegate event.");
  7624. }
  7625. }
  7626. /**
  7627. * 파라메터로 들어오는 엘리먼트 부터 자신의 엘리먼트 까지의 엘리먼트를 구하는 함수.
  7628. * @param {Element} 엘리먼트.
  7629. * @returns {Array} 배열 객체.
  7630. * @ignore
  7631. */
  7632. jindo.$Element.prototype._getParent = function(oEle) {
  7633. var e = this._element;
  7634. var a = [], p = null;
  7635. while (oEle.parentNode && p != e) {
  7636. p = oEle.parentNode;
  7637. if (p == document.documentElement) break;
  7638. a[a.length] = p;
  7639. oEle = p;
  7640. }
  7641. return a;
  7642. };
  7643. /**
  7644. * 엘리먼트에 이벤트를 추가하는 함수.
  7645. * @param {Object} aDataOfEvent 이벤트와 함수를 가지고 있는 오브젝트.
  7646. * @param {String|Function} vFilter cssquery,check하는 함수.
  7647. * @param {Function} fpCallback 실행될 함수.
  7648. * @param {Function} fpCheck 체크하는 함수.
  7649. * @retruns {Object} aDataOfEvent를 반환.
  7650. * @ignore
  7651. */
  7652. jindo.$Element._addBind = function(aDataOfEvent,vFilter,fpCallback,fpCheck){
  7653. var aEvent = aDataOfEvent[vFilter];
  7654. if(aEvent){
  7655. var fpFuncs = aEvent.func;
  7656. fpFuncs.push(fpCallback);
  7657. aEvent.func = fpFuncs;
  7658. }else{
  7659. aEvent = {
  7660. checker : fpCheck,
  7661. func : [fpCallback]
  7662. };
  7663. }
  7664. aDataOfEvent[vFilter] = aEvent
  7665. return aDataOfEvent;
  7666. }
  7667. /**
  7668. * 딜리게이션에서 해제되어야 함수를 삭제하는 함수.
  7669. * @param {String} sEvent 이벤트 타입.
  7670. * @param {String|Function} vFilter cssquery,function 이렇게 2가지 타입이 들어옴.
  7671. * @param {Function} fpCallback 해당 cChecker에 들어오는 함수가 맞을때 실행되는 함수.
  7672. * @returns {$Element} $Element 객체.
  7673. * @since 1.4.6부터 사용가능.
  7674. * @ignore
  7675. */
  7676. jindo.$Element.prototype._unbind = function(sEvent, vFilter,fpCallback){
  7677. var oEle = this._element;
  7678. if (sEvent&&vFilter&&fpCallback) {
  7679. var oEventInfo = oEle["_delegate_"+sEvent];
  7680. if(oEventInfo&&oEventInfo[vFilter]){
  7681. var fpFuncs = oEventInfo[vFilter].func;
  7682. fpFuncs = oEventInfo[vFilter].func = jindo.$A(fpFuncs).refuse(fpCallback).$value();
  7683. if (!fpFuncs.length) {
  7684. jindo.$Element._deleteFilter(oEle,sEvent,vFilter);
  7685. }
  7686. }
  7687. }else if (sEvent&&vFilter) {
  7688. jindo.$Element._deleteFilter(oEle,sEvent,vFilter);
  7689. }else if (sEvent) {
  7690. jindo.$Element._deleteEvent(oEle,sEvent,vFilter);
  7691. }else{
  7692. var aEvents = oEle['_delegate_events'];
  7693. var sEachEvent;
  7694. for(var i = 0 , l = aEvents.length ; i < l ; i++){
  7695. sEachEvent = aEvents[i];
  7696. jindo.$Element._unEventBind(oEle,sEachEvent,oEle["_delegate_"+sEachEvent+"_func"]);
  7697. jindo.$Element._delDelegateInfo(oEle,"_delegate_"+sEachEvent);
  7698. jindo.$Element._delDelegateInfo(oEle,"_delegate_"+sEachEvent+"_func");
  7699. }
  7700. jindo.$Element._delDelegateInfo(oEle,"_delegate_events");
  7701. }
  7702. return this;
  7703. }
  7704. /**
  7705. * 오브젝트에 키값으로 정보삭제하는 함수
  7706. * @param {Object} 삭제할 오브젝트.
  7707. * @param {String|Function} sType 키값이 들어옴.
  7708. * @returns {Object} 삭제된 오브젝트.
  7709. * @since 1.4.6부터 사용가능.
  7710. * @ignore
  7711. */
  7712. jindo.$Element._delDelegateInfo = function(oObj , sType){
  7713. try{
  7714. oObj[sType] = null;
  7715. delete oObj[sType];
  7716. }catch(e){}
  7717. return oObj
  7718. }
  7719. /**
  7720. * 플터 기준으로 삭제하는 함수.
  7721. * @param {Element} 삭제할 엘리먼트.
  7722. * @param {String} 이벤트명.
  7723. * @param {String|Function} cssquery, 필터하는 함수.
  7724. * @since 1.4.6부터 사용가능.
  7725. * @ignore
  7726. */
  7727. jindo.$Element._deleteFilter = function(oEle,sEvent,vFilter){
  7728. var oEventInfo = oEle["_delegate_"+sEvent];
  7729. if(oEventInfo&&oEventInfo[vFilter]){
  7730. if (jindo.$H(oEventInfo).keys().length == 1) {
  7731. jindo.$Element._deleteEvent(oEle,sEvent,vFilter);
  7732. }else{
  7733. jindo.$Element._delDelegateInfo(oEventInfo,vFilter);
  7734. }
  7735. }
  7736. }
  7737. /**
  7738. * event 기준으로 삭제하는 함수.
  7739. * @param {Element} 삭제할 엘리먼트.
  7740. * @param {String} 이벤트명.
  7741. * @param {String|Function} cssquery, 필터하는 함수.
  7742. * @since 1.4.6부터 사용가능.
  7743. * @ignore
  7744. */
  7745. jindo.$Element._deleteEvent = function(oEle,sEvent,vFilter){
  7746. var aEvents = oEle['_delegate_events'];
  7747. jindo.$Element._unEventBind(oEle,sEvent,oEle["_delegate_"+sEvent+"_func"]);
  7748. jindo.$Element._delDelegateInfo(oEle,"_delegate_"+sEvent);
  7749. jindo.$Element._delDelegateInfo(oEle,"_delegate_"+sEvent+"_func");
  7750. aEvents = jindo.$A(aEvents).refuse(sEvent).$value();
  7751. if (!aEvents.length) {
  7752. jindo.$Element._delDelegateInfo(oEle,"_delegate_events");
  7753. }else{
  7754. oEle['_delegate_events'] = jindo.$A(aEvents).refuse(sEvent).$value();
  7755. }
  7756. }
  7757. /**
  7758. * 이벤트를 해제 하는 함수.
  7759. * @param {Element} oEle 엘리먼트
  7760. * @param {Boolean} sType 이벤트 타입.
  7761. * @param {Function} fAroundFunc 바인딩을 해제할 함수.
  7762. * @ignore
  7763. */
  7764. jindo.$Element._unEventBind = function(oEle,sType,fAroundFunc){
  7765. if(oEle.removeEventListener){
  7766. jindo.$Element._unEventBind = function(oEle,sType,fAroundFunc){
  7767. oEle.removeEventListener(sType,fAroundFunc,false);
  7768. }
  7769. }else{
  7770. jindo.$Element._unEventBind = function(oEle,sType,fAroundFunc){
  7771. oEle.detachEvent("on"+sType,fAroundFunc);
  7772. }
  7773. }
  7774. jindo.$Element._unEventBind(oEle,sType,fAroundFunc);
  7775. }
  7776. /**
  7777. * @fileOverview $Fn의 생성자 메서드를 정의한 파일
  7778. * @name function.js
  7779. */
  7780. /**
  7781. * $Fn 객체를 리턴한다.
  7782. * @extends core
  7783. * @class $Fn 클래스는 자바스크립트 Function 객체의 래퍼(Wrapper) 클래스이다.
  7784. * @constructor
  7785. * @param {Function | String} func
  7786. * <br>
  7787. * Function 객체 혹은 함수의 매개변수를 나타내는 문자열
  7788. * @param {Object | String} thisObject
  7789. * <br>
  7790. * 함수가 특정 객체의 메서드일 , 해당 객체도 같이 전달한다. 혹은 함수의 몸체를 나타내는 문자열.
  7791. * @return {$Fn} $Fn 객체
  7792. * @see $Fn#toFunction
  7793. * @description [Lite]
  7794. * @example
  7795. func : function() {
  7796. // code here
  7797. }
  7798. var fn = $Fn(func, this);
  7799. * @example
  7800. var someObject = {
  7801. func : function() {
  7802. // code here
  7803. }
  7804. }
  7805. var fn = $Fn(someObject.func, someObject);
  7806. * @example
  7807. var fn = $Fn("a, b", "return a + b;");
  7808. var result = fn.$value()(1, 2) // result = 3;
  7809. // fn은 함수 리터럴인 function(a, b){ return a + b;}와 동일한 함수를 래핑한다.
  7810. * @author Kim, Taegon
  7811. */
  7812. jindo.$Fn = function(func, thisObject) {
  7813. var cl = arguments.callee;
  7814. if (func instanceof cl) return func;
  7815. if (!(this instanceof cl)) return new cl(func, thisObject);
  7816. this._events = [];
  7817. this._tmpElm = null;
  7818. this._key = null;
  7819. if (typeof func == "function") {
  7820. this._func = func;
  7821. this._this = thisObject;
  7822. } else if (typeof func == "string" && typeof thisObject == "string") {
  7823. //this._func = new Function(func, thisObject);
  7824. this._func = eval("false||function("+func+"){"+thisObject+"}")
  7825. }
  7826. }
  7827. /**
  7828. * userAgent cache
  7829. * @ignore
  7830. */
  7831. var _ua = navigator.userAgent;
  7832. /**
  7833. * $value 메서드는 원래의 Function 객체를 리턴한다.
  7834. * @return {Function} 함수 객체
  7835. * @description [Lite]
  7836. * @example
  7837. func : function() {
  7838. // code here
  7839. }
  7840. var fn = $Fn(func, this);
  7841. fn.$value(); // 원래의 함수가 리턴된다.
  7842. */
  7843. jindo.$Fn.prototype.$value = function() {
  7844. return this._func;
  7845. };
  7846. /**
  7847. * bind 메서드는 함수가 객체의 메소드로 동작하도록 묶인 Function 객체를 리턴한다.
  7848. * @return {Function} thisObject의 메소드로 묶인 Function 객체
  7849. * @description [Lite]
  7850. * @example
  7851. var sName = "OUT";
  7852. var oThis = {
  7853. sName : "IN"
  7854. };
  7855. function getName() {
  7856. return this.sName;
  7857. }
  7858. oThis.getName = $Fn(getName, oThis).bind();
  7859. alert( getName() ); // OUT
  7860. alert( oThis.getName() ); // IN
  7861. * @example
  7862. // 함수를 미리 선언하고 나중에 사용할 때,
  7863. // 함수에서 참조 하는 값들은 해당 함수를 생성 할때의 값이 아니라 함수 실행 시점의 값이 사용 되므로 이때 bind를 이용한다.
  7864. for(var i=0; i<2;i++){
  7865. aTmp[i] = function(){alert(i);}
  7866. }
  7867. for(var n=0; n<2;n++){
  7868. aTmp[n](); // 숫자 2만 두번 alert된다.
  7869. }
  7870. for(var i=0; i<2;i++){
  7871. aTmp[i] = $Fn(function(nTest){alert(nTest);}, this).bind(i);
  7872. }
  7873. for(var n=0; n<2;n++){
  7874. aTmp[n](); // 숫자 0, 1이 alert된다.
  7875. }
  7876. * @example
  7877. //클래스 생성 시 함수를 매개변수로 할 때, scope를 맞춰주기 위해 bind를 사용한다.
  7878. var MyClass = $Class({
  7879. fFunc : null,
  7880. $init : function(func){
  7881. this.fFunc = func;
  7882. this.testFunc();
  7883. },
  7884. testFunc : function(){
  7885. this.fFunc();
  7886. }
  7887. })
  7888. var MainClass = $Class({
  7889. $init : function(){
  7890. var oMyClass1 = new MyClass(this.func1);
  7891. var oMyClass2 = new MyClass($Fn(this.func2, this).bind());
  7892. },
  7893. func1 : function(){
  7894. alert(this);// this는 MyClass 를 의미한다.
  7895. },
  7896. func2 : function(){
  7897. alert(this);// this는 MainClass 를 의미한다.
  7898. }
  7899. })
  7900. function init(){
  7901. var a = new MainClass();
  7902. }
  7903. */
  7904. jindo.$Fn.prototype.bind = function() {
  7905. var a = jindo.$A(arguments).$value();
  7906. var f = this._func;
  7907. var t = this._this;
  7908. var b = function() {
  7909. var args = jindo.$A(arguments).$value();
  7910. // fix opera concat bug
  7911. if (a.length) args = a.concat(args);
  7912. return f.apply(t, args);
  7913. };
  7914. return b;
  7915. };
  7916. /**
  7917. * bingForEvent는 객체와 메서드를 묶어 하나의 이벤트 핸들러 Function으로 반환한다.
  7918. * @param {Element, ...} [elementN] 이벤트 객체와 함께 전달할
  7919. * @see $Fn#bind
  7920. * @see $Event
  7921. * @description [Lite]
  7922. * @ignore
  7923. */
  7924. jindo.$Fn.prototype.bindForEvent = function() {
  7925. var a = arguments;
  7926. var f = this._func;
  7927. var t = this._this;
  7928. var m = this._tmpElm || null;
  7929. var b = function(e) {
  7930. var args = Array.prototype.slice.apply(a);
  7931. if (typeof e == "undefined") e = window.event;
  7932. if (typeof e.currentTarget == "undefined") {
  7933. e.currentTarget = m;
  7934. }
  7935. var oEvent = jindo.$Event(e);
  7936. args.unshift(oEvent);
  7937. var returnValue = f.apply(t, args);
  7938. if(typeof returnValue != "undefined" && oEvent.type=="beforeunload"){
  7939. e.returnValue = returnValue;
  7940. }
  7941. return returnValue;
  7942. };
  7943. return b;
  7944. };
  7945. /**
  7946. * attach 메서드는 함수를 특정 엘리먼트의 이벤트 핸들러로 할당한다.<br>
  7947. * 함수의 반환 값이 false인 경우, $Fn에 바인딩하여 사용했을 IE에서 기본 기능을 막기 때문에 사용하지 않도록 주의한다.
  7948. <ul>
  7949. <li>이벤트 이름에는 on 접두어를 사용하지 않는다.</li>
  7950. <li>마우스 스크롤 이벤트는 mousewheel 사용한다.</li>
  7951. <li>기본 이벤트 외에 추가로 사용이 가능한 이벤트에는 domready, mouseenter, mouseleave, mousewheel이 있다.</li>
  7952. </ul>
  7953. * @param {Element | Array} oElement 이벤트 핸들러를 할당할 엘리먼트(엘리먼트가 원소인 배열도 가능)
  7954. * @param {String} sEvent 이벤트 종류
  7955. * @param {Boolean} bUseCapture capturing을 사용할 (1.4.2 부터 지원)
  7956. * @see $Fn#detach
  7957. * @description [Lite]
  7958. * @return {$Fn} 생성된 $Fn 객체
  7959. * @example
  7960. var someObject = {
  7961. func : function() {
  7962. // code here
  7963. }
  7964. }
  7965. $Fn(someObject.func, someObject).attach($("test"),"click"); // 단일 엘리먼트에 클릭을 할당한 경우
  7966. $Fn(someObject.func, someObject).attach($$(".test"),"click"); // 여러 엘리먼트에 클릭을 할당한 경우
  7967. //attach에 첫번째 인자로 엘리먼트 배열이 들어오면 해당 모든 엘리먼트에 이벤트가 바인딩 됨.
  7968. */
  7969. jindo.$Fn.prototype.attach = function(oElement, sEvent, bUseCapture) {
  7970. var fn = null, l, ev = sEvent, el = oElement, ua = _ua;
  7971. if (typeof bUseCapture == "undefined") {
  7972. bUseCapture = false;
  7973. };
  7974. this._bUseCapture = bUseCapture;
  7975. if ((el instanceof Array) || (jindo.$A && (el instanceof jindo.$A) && (el=el.$value()))) {
  7976. for(var i=0; i < el.length; i++) this.attach(el[i], ev, bUseCapture);
  7977. return this;
  7978. }
  7979. if (!el || !ev) return this;
  7980. if (typeof el.$value == "function") el = el.$value();
  7981. el = jindo.$(el);
  7982. ev = ev.toLowerCase();
  7983. this._tmpElm = el;
  7984. fn = this.bindForEvent();
  7985. this._tmpElm = null;
  7986. var bIsIE = ua.indexOf("MSIE") > -1;
  7987. if (typeof el.addEventListener != "undefined") {
  7988. if (ev == "domready") {
  7989. ev = "DOMContentLoaded";
  7990. }else if (ev == "mousewheel" && ua.indexOf("WebKit") < 0 && !/Opera/.test(ua) && !bIsIE) {
  7991. /*
  7992. IE9인 경우도 DOMMouseScroll이 동작하지 않음.
  7993. */
  7994. ev = "DOMMouseScroll";
  7995. }else if (ev == "mouseenter" && !bIsIE){
  7996. ev = "mouseover";
  7997. fn = jindo.$Fn._fireWhenElementBoundary(el, fn);
  7998. }else if (ev == "mouseleave" && !bIsIE){
  7999. ev = "mouseout";
  8000. fn = jindo.$Fn._fireWhenElementBoundary(el, fn);
  8001. }else if(ev == "transitionend"||ev == "transitionstart"){
  8002. var sPrefix, sPostfix = ev.replace("transition","");
  8003. sPostfix = sPostfix.substr(0,1).toUpperCase() + sPostfix.substr(1);
  8004. if(typeof document.body.style.WebkitTransition !== "undefined"){
  8005. sPrefix = "webkit";
  8006. }else if(typeof document.body.style.OTransition !== "undefined"){
  8007. sPrefix = "o";
  8008. }else if(typeof document.body.style.MsTransition !== "undefined"){
  8009. sPrefix = "ms";
  8010. }
  8011. ev = (sPrefix?sPrefix+"Transition":"transition")+sPostfix;
  8012. this._for_test_attach = ev;
  8013. this._for_test_detach = "";
  8014. }else if(ev == "animationstart"||ev == "animationend"||ev == "animationiteration"){
  8015. var sPrefix, sPostfix = ev.replace("animation","");
  8016. sPostfix = sPostfix.substr(0,1).toUpperCase() + sPostfix.substr(1);
  8017. if(typeof document.body.style.WebkitAnimationName !== "undefined"){
  8018. sPrefix = "webkit";
  8019. }else if(typeof document.body.style.OAnimationName !== "undefined"){
  8020. sPrefix = "o";
  8021. }else if(typeof document.body.style.MsTransitionName !== "undefined"){
  8022. sPrefix = "ms";
  8023. }
  8024. ev = (sPrefix?sPrefix+"Animation":"animation")+sPostfix;
  8025. this._for_test_attach = ev;
  8026. this._for_test_detach = "";
  8027. }
  8028. el.addEventListener(ev, fn, bUseCapture);
  8029. } else if (typeof el.attachEvent != "undefined") {
  8030. if (ev == "domready") {
  8031. /*
  8032. iframe안에서 domready이벤트가 실행되지 않기 때문에 error를 던짐.
  8033. */
  8034. if(window.top != window) throw new Error("Domready Event doesn't work in the iframe.");
  8035. jindo.$Fn._domready(el, fn);
  8036. return this;
  8037. } else {
  8038. el.attachEvent("on"+ev, fn);
  8039. }
  8040. }
  8041. if (!this._key) {
  8042. this._key = "$"+jindo.$Fn.gc.count++;
  8043. jindo.$Fn.gc.pool[this._key] = this;
  8044. }
  8045. this._events[this._events.length] = {element:el, event:sEvent.toLowerCase(), func:fn};
  8046. return this;
  8047. };
  8048. /**
  8049. * detach 메서드는 엘리먼트의 이벤트 핸들러로 할당된 함수를 해제한다.
  8050. * @remark 이벤트 이름에는 on 접두어를 사용하지 않는다.
  8051. * @remark 마우스 스크롤 이벤트는 mousewheel 사용한다.
  8052. * @param {Element} oElement 이벤트 핸들러를 해제할 엘리먼트
  8053. * @param {String} sEvent 이벤트 종류
  8054. * @see $Fn#attach
  8055. * @description [Lite]
  8056. * @return {$Fn} 생성된 $Fn 객체
  8057. * @example
  8058. var someObject = {
  8059. func : function() {
  8060. // code here
  8061. }
  8062. }
  8063. $Fn(someObject.func, someObject).detach($("test"),"click"); // 단일 엘리먼트에 클릭을 할당한 경우
  8064. $Fn(someObject.func, someObject).detach($$(".test"),"click"); // 여러 엘리먼트에 클릭을 할당한 경우
  8065. */
  8066. jindo.$Fn.prototype.detach = function(oElement, sEvent) {
  8067. var fn = null, l, el = oElement, ev = sEvent, ua = _ua;
  8068. if ((el instanceof Array) || (jindo.$A && (el instanceof jindo.$A) && (el=el.$value()))) {
  8069. for(var i=0; i < el.length; i++) this.detach(el[i], ev);
  8070. return this;
  8071. }
  8072. if (!el || !ev) return this;
  8073. if (jindo.$Element && el instanceof jindo.$Element) el = el.$value();
  8074. el = jindo.$(el);
  8075. ev = ev.toLowerCase();
  8076. var e = this._events;
  8077. for(var i=0; i < e.length; i++) {
  8078. if (e[i].element !== el || e[i].event !== ev) continue;
  8079. fn = e[i].func;
  8080. this._events = jindo.$A(this._events).refuse(e[i]).$value();
  8081. break;
  8082. }
  8083. if (typeof el.removeEventListener != "undefined") {
  8084. if (ev == "domready") {
  8085. ev = "DOMContentLoaded";
  8086. }else if (ev == "mousewheel" && ua.indexOf("WebKit") < 0) {
  8087. ev = "DOMMouseScroll";
  8088. }else if (ev == "mouseenter"){
  8089. ev = "mouseover";
  8090. }else if (ev == "mouseleave"){
  8091. ev = "mouseout";
  8092. }else if(ev == "transitionend"||ev == "transitionstart"){
  8093. var sPrefix, sPostfix = ev.replace("transition","");
  8094. sPostfix = sPostfix.substr(0,1).toUpperCase() + sPostfix.substr(1);
  8095. if(typeof document.body.style.WebkitTransition !== "undefined"){
  8096. sPrefix = "webkit";
  8097. }else if(typeof document.body.style.OTransition !== "undefined"){
  8098. sPrefix = "o";
  8099. }else if(typeof document.body.style.MsTransition !== "undefined"){
  8100. sPrefix = "ms";
  8101. }
  8102. ev = (sPrefix?sPrefix+"Transition":"transition")+sPostfix;
  8103. this._for_test_detach = ev;
  8104. this._for_test_attach = "";
  8105. }else if(ev == "animationstart"||ev == "animationend"||ev == "animationiteration"){
  8106. var sPrefix, sPostfix = ev.replace("animation","");
  8107. sPostfix = sPostfix.substr(0,1).toUpperCase() + sPostfix.substr(1);
  8108. if(typeof document.body.style.WebkitAnimationName !== "undefined"){
  8109. sPrefix = "webkit";
  8110. }else if(typeof document.body.style.OAnimationName !== "undefined"){
  8111. sPrefix = "o";
  8112. }else if(typeof document.body.style.MsTransitionName !== "undefined"){
  8113. sPrefix = "ms";
  8114. }
  8115. ev = (sPrefix?sPrefix+"Animation":"animation")+sPostfix;
  8116. this._for_test_detach = ev;
  8117. this._for_test_attach = "";
  8118. }
  8119. if (fn) el.removeEventListener(ev, fn, false);
  8120. } else if (typeof el.detachEvent != "undefined") {
  8121. if (ev == "domready") {
  8122. jindo.$Fn._domready.list = jindo.$Fn._domready.list.refuse(fn);
  8123. return this;
  8124. } else {
  8125. el.detachEvent("on"+ev, fn);
  8126. }
  8127. }
  8128. return this;
  8129. };
  8130. /**
  8131. * delay 메서드는 래핑한 함수를 지정한 시간 이후에 호출한다.
  8132. * @param {Number} nSec 함수를 호출할 때까지 대기할 시간( 단위).
  8133. * @param {Array} args 함수를 호출할 사용할 매개변수. 매개변수가 여러 개일 경우 배열을 사용한다.
  8134. * @see $Fn#bind
  8135. * @see $Fn#setInterval
  8136. * @description [Lite]
  8137. * @return {$Fn} 생성된 $Fn 객체
  8138. * @example
  8139. function func(a, b) {
  8140. alert(a + b);
  8141. }
  8142. $Fn(func).delay(5, [3, 5]);//5초 이후에 3, 5 값을 매개변수로 하는 함수 func를 호출한다.
  8143. */
  8144. jindo.$Fn.prototype.delay = function(nSec, args) {
  8145. if (typeof args == "undefined") args = [];
  8146. this._delayKey = setTimeout(this.bind.apply(this, args), nSec*1000);
  8147. return this;
  8148. };
  8149. /**
  8150. * setInterval 메서드는 래핑한 함수를 지정한 시간 간격마다 호출한다.
  8151. * @param {Number} nSec 함수를 호출할 간격( 단위).
  8152. * @param {Array} args 함수를 호출할 사용할 매개변수. 매개변수가 여러 개일 경우 배열을 사용한다.
  8153. * @return {Number} Interval ID, 함수 호출을 해제할 사용한다.
  8154. * @see $Fn#bind
  8155. * @see $Fn#delay
  8156. * @description [Lite]
  8157. * @example
  8158. function func(a, b) {
  8159. alert(a + b);
  8160. }
  8161. $Fn(func).setInterval(5, [3, 5]);//5초 간격으로 3, 5 값을 매개변수로 하는 함수 func를 호출한다.
  8162. */
  8163. jindo.$Fn.prototype.setInterval = function(nSec, args) {
  8164. if (typeof args == "undefined") args = [];
  8165. this._repeatKey = setInterval(this.bind.apply(this, args), nSec*1000);
  8166. return this._repeatKey;
  8167. };
  8168. /**
  8169. * repeat 메서드는 setInterval와 같다.
  8170. * @param {Number} nSec 함수를 호출간 간격.
  8171. * @param {Array} args 함수를 호출할 사용할 매개변수. 매개변수가 여러 개일 경우 배열을 사용한다.
  8172. * @return {Number} Interval ID, 함수 호출을 해제할 사용한다.
  8173. * @see $Fn#bind
  8174. * @see $Fn#delay
  8175. * @description [Lite]
  8176. * @example
  8177. function func(a, b) {
  8178. alert(a + b);
  8179. }
  8180. $Fn(func).repeat(5, [3, 5]);//5초 간격으로 3, 5 값을 매개변수로 하는 함수 func를 호출한다.
  8181. */
  8182. jindo.$Fn.prototype.repeat = jindo.$Fn.prototype.setInterval;
  8183. /**
  8184. * stopDelay는 delay 메서드로 지정한 함수 호출을 멈출 사용한다.
  8185. * @return {$Fn} $Fn 객체
  8186. * @see $Fn#delay
  8187. * @example
  8188. function func(a, b) {
  8189. alert(a + b);
  8190. }
  8191. var fpDelay = $Fn(func);
  8192. fpDelay.delay(5, [3, 5]);
  8193. fpDelay.stopDelay();
  8194. */
  8195. jindo.$Fn.prototype.stopDelay = function(){
  8196. if(typeof this._delayKey != "undefined"){
  8197. window.clearTimeout(this._delayKey);
  8198. delete this._delayKey;
  8199. }
  8200. return this;
  8201. }
  8202. /**
  8203. * stopRepeat는 repeat메서드로 지정한 함수 호출을 멈출 사용한다.
  8204. * @return {$Fn} $Fn 객체
  8205. * @see $Fn#repeat
  8206. * @example
  8207. function func(a, b) {
  8208. alert(a + b);
  8209. }
  8210. var fpDelay = $Fn(func);
  8211. fpDelay.repeat(5, [3, 5]);
  8212. fpDelay.stopRepeat();
  8213. */
  8214. jindo.$Fn.prototype.stopRepeat = function(){
  8215. if(typeof this._repeatKey != "undefined"){
  8216. window.clearInterval(this._repeatKey);
  8217. delete this._repeatKey;
  8218. }
  8219. return this;
  8220. }
  8221. /**
  8222. * 메모리에서 객체를 사용한 참조를 모두 해제한다(직접 호출 금지).
  8223. * @param {Element} 해당 요소의 이벤트 핸들러만 해제.
  8224. * @ignore
  8225. */
  8226. jindo.$Fn.prototype.free = function(oElement) {
  8227. var len = this._events.length;
  8228. while(len > 0) {
  8229. var el = this._events[--len].element;
  8230. var sEvent = this._events[len].event;
  8231. var fn = this._events[len].func;
  8232. if (oElement && el!==oElement){
  8233. continue;
  8234. }
  8235. this.detach(el, sEvent);
  8236. /*
  8237. unload시에 엘리먼트에 attach한 함수를 detach하는 로직이 있는데 해당 로직으로 인하여 unload이벤트가 실행되지 않아 실행시키는 로직을 만듬. 그리고 해당 로직은 gc에서 호출할때만 호출.
  8238. */
  8239. var isGCCall = !oElement;
  8240. if (isGCCall && window === el && sEvent == "unload" && _ua.indexOf("MSIE")<1) {
  8241. this._func.call(this._this);
  8242. }
  8243. delete this._events[len];
  8244. }
  8245. if(this._events.length==0)
  8246. try { delete jindo.$Fn.gc.pool[this._key]; }catch(e){};
  8247. };
  8248. /**
  8249. * IE에서 domready(=DOMContentLoaded) 이벤트를 에뮬레이션한다.
  8250. * @ignore
  8251. */
  8252. jindo.$Fn._domready = function(doc, func) {
  8253. if (typeof jindo.$Fn._domready.list == "undefined") {
  8254. var f = null, l = jindo.$Fn._domready.list = jindo.$A([func]);
  8255. // use the trick by Diego Perini
  8256. // http://javascript.nwbox.com/IEContentLoaded/
  8257. var done = false, execFuncs = function(){
  8258. if(!done) {
  8259. done = true;
  8260. var evt = {
  8261. type : "domready",
  8262. target : doc,
  8263. currentTarget : doc
  8264. };
  8265. while(f = l.shift()) f(evt);
  8266. }
  8267. };
  8268. (function (){
  8269. try {
  8270. doc.documentElement.doScroll("left");
  8271. } catch(e) {
  8272. setTimeout(arguments.callee, 50);
  8273. return;
  8274. }
  8275. execFuncs();
  8276. })();
  8277. // trying to always fire before onload
  8278. doc.onreadystatechange = function() {
  8279. if (doc.readyState == 'complete') {
  8280. doc.onreadystatechange = null;
  8281. execFuncs();
  8282. }
  8283. };
  8284. } else {
  8285. jindo.$Fn._domready.list.push(func);
  8286. }
  8287. };
  8288. /**
  8289. * IE에서 mouseenter/mouseleave 이벤트를 에뮬레이션하기 위한 요소 영역을 벗어나는 경우에만 실행하는 함수 필터
  8290. * @ignore
  8291. */
  8292. jindo.$Fn._fireWhenElementBoundary = function(doc, func) {
  8293. return function(evt){
  8294. var oEvent = jindo.$Event(evt);
  8295. var relatedElement = jindo.$Element(oEvent.relatedElement);
  8296. if(relatedElement && (relatedElement.isEqual(this) || relatedElement.isChildOf(this))) return;
  8297. func.call(this,evt);
  8298. }
  8299. };
  8300. /**
  8301. * gc 메서드는 엘리먼트에 할당된 모든 이벤트 핸들러를 해제한다.
  8302. * @example
  8303. var someObject = {
  8304. func1 : function() {
  8305. // code here
  8306. },
  8307. func2 : function() {
  8308. // code here
  8309. }
  8310. }
  8311. $Fn(someObject.func1, someObject).attach($("test1"),"mouseup");
  8312. $Fn(someObject.func2, someObject).attach($("test1"),"mousedown");
  8313. $Fn(someObject.func1, someObject).attach($("test2"),"mouseup");
  8314. $Fn(someObject.func2, someObject).attach($("test2"),"mousedown");
  8315. ..
  8316. ..
  8317. $Fn.gc();
  8318. */
  8319. jindo.$Fn.gc = function() {
  8320. var p = jindo.$Fn.gc.pool;
  8321. for(var key in p) {
  8322. if(p.hasOwnProperty(key))
  8323. try { p[key].free(); }catch(e){ };
  8324. }
  8325. /*
  8326. 레퍼런스를 삭제한다.
  8327. */
  8328. jindo.$Fn.gc.pool = p = {};
  8329. };
  8330. /**
  8331. * freeElement 메소드는 지정한 엘리먼트에 할당된 이벤트 핸들러를 모두 해제한다.
  8332. * @since 1.3.5
  8333. * @see $Fn#gc
  8334. * @example
  8335. var someObject = {
  8336. func : function() {
  8337. // code here
  8338. }
  8339. }
  8340. $Fn(someObject.func, someObject).attach($("test"),"mouseup");
  8341. $Fn(someObject.func, someObject).attach($("test"),"mousedown");
  8342. $Fn.freeElement($("test"));
  8343. */
  8344. jindo.$Fn.freeElement = function(oElement){
  8345. var p = jindo.$Fn.gc.pool;
  8346. for(var key in p) {
  8347. if(p.hasOwnProperty(key)){
  8348. try {
  8349. p[key].free(oElement);
  8350. }catch(e){ };
  8351. }
  8352. }
  8353. }
  8354. jindo.$Fn.gc.count = 0;
  8355. jindo.$Fn.gc.pool = {};
  8356. function isUnCacheAgent(){
  8357. var isIPad = (_ua.indexOf("iPad") > -1);
  8358. var isAndroid = (_ua.indexOf("Android") > -1);
  8359. var isMSafari = (!(_ua.indexOf("IEMobile") > -1) && (_ua.indexOf("Mobile") > -1) )||(isIPad && (_ua.indexOf("Safari") > -1));
  8360. return isMSafari && !isIPad && !isAndroid;
  8361. }
  8362. if (typeof window != "undefined" && !isUnCacheAgent()) {
  8363. jindo.$Fn(jindo.$Fn.gc).attach(window, "unload");
  8364. }
  8365. /**
  8366. * @fileOverview $Event의 생성자 메서드를 정의한 파일
  8367. * @name event.js
  8368. */
  8369. /**
  8370. * JavaScript Core 이벤트 객체로부터 $Event 객체를 생성한다.
  8371. * @class $Event 클래스는 자바스크립트 Event 객체의 래퍼(Wrapper) 클래스이다. 사용자는 $Event.element 메서드를 사용하여 이벤트가 발생한 객체를 있다.
  8372. * @param {Event} e Event 객체
  8373. * @constructor
  8374. * @description [Lite]
  8375. * @author Kim, Taegon
  8376. */
  8377. jindo.$Event = function(e) {
  8378. var cl = arguments.callee;
  8379. if (e instanceof cl) return e;
  8380. if (!(this instanceof cl)) return new cl(e);
  8381. if (typeof e == "undefined") e = window.event;
  8382. if (e === window.event && document.createEventObject) e = document.createEventObject(e);
  8383. this._event = e;
  8384. this._globalEvent = window.event;
  8385. /**
  8386. 이벤트의 종류
  8387. */
  8388. this.type = e.type.toLowerCase();
  8389. if (this.type == "dommousescroll") {
  8390. this.type = "mousewheel";
  8391. } else if (this.type == "domcontentloaded") {
  8392. this.type = "domready";
  8393. }
  8394. this.canceled = false;
  8395. /**
  8396. 이벤트가 발생한 엘리먼트
  8397. */
  8398. this.element = e.target || e.srcElement;
  8399. /**
  8400. 이벤트가 정의된 엘리먼트
  8401. */
  8402. this.currentElement = e.currentTarget;
  8403. /**
  8404. 이벤트의 연관 엘리먼트
  8405. */
  8406. this.relatedElement = null;
  8407. if (typeof e.relatedTarget != "undefined") {
  8408. this.relatedElement = e.relatedTarget;
  8409. } else if(e.fromElement && e.toElement) {
  8410. this.relatedElement = e[(this.type=="mouseout")?"toElement":"fromElement"];
  8411. }
  8412. }
  8413. /**
  8414. * mouse 메서드는 마우스 이벤트의 버튼, 정보를 리턴한다.
  8415. * @description [Lite]
  8416. * @example
  8417. function eventHandler(evt) {
  8418. var mouse = evt.mouse();
  8419. mouse.delta; // Number. 휠이 움직인 정도. 휠을 위로 굴리면 양수, 아래로 굴리면 음수.
  8420. mouse.left; // Boolean. 마우스 왼쪽 버튼을 눌렸으면 true, 아니면 false
  8421. mouse.middle; // Boolean. 마우스 중간 버튼을 눌렸으면 true, 아니면 false
  8422. mouse.right; // Boolean. 마우스 오른쪽 버튼을 눌렸으면 true, 아니면 false
  8423. }
  8424. * @return {Object} 마우스 정보를 가지는 객체. 리턴한 객체의 속성은 예제를 참조한다.
  8425. */
  8426. jindo.$Event.prototype.mouse = function() {
  8427. var e = this._event;
  8428. var delta = 0;
  8429. var left = false,mid = false,right = false;
  8430. var left = e.which ? e.button==0 : !!(e.button&1);
  8431. var mid = e.which ? e.button==1 : !!(e.button&4);
  8432. var right = e.which ? e.button==2 : !!(e.button&2);
  8433. var ret = {};
  8434. if (e.wheelDelta) {
  8435. delta = e.wheelDelta / 120;
  8436. } else if (e.detail) {
  8437. delta = -e.detail / 3;
  8438. }
  8439. ret = {
  8440. delta : delta,
  8441. left : left,
  8442. middle : mid,
  8443. right : right
  8444. };
  8445. // replace method
  8446. this.mouse = function(){ return ret };
  8447. return ret;
  8448. };
  8449. /**
  8450. * key 메서드는 키보드 이벤트 정보를 리턴한다.
  8451. * @description [Lite]
  8452. * @example
  8453. function eventHandler(evt) {
  8454. var key = evt.key();
  8455. key.keyCode; // Number. 눌린 키보드의 키코드
  8456. key.alt; // Boolean. Alt 키를 눌렸으면 true.
  8457. key.ctrl; // Boolean. Ctrl 키를 눌렸으면 true.
  8458. key.meta; // Boolean. Meta 키를 눌렸으면 true. Meta키는 맥의 커맨드키를 검출할 때 사용합니다.
  8459. key.shift; // Boolean. Shift 키를 눌렸으면 true.
  8460. key.up; // Boolean. 위쪽 화살표 키를 눌렸으면 true.
  8461. key.down; // Boolean. 아래쪽 화살표 키를 눌렸으면 true.
  8462. key.left; // Boolean. 왼쪽 화살표 키를 눌렸으면 true.
  8463. key.right; // Boolean. 오른쪽 화살표 키를 눌렸으면 true.
  8464. key.enter; // Boolean. 리턴키를 눌렀으면 true
  8465. key.esc; // Boolean. ESC키를 눌렀으면 true
  8466. }
  8467. }
  8468. * @return {Object} 키보드 이벤트의 눌린 키값. 객체의 속성은 예제를 참조한다.
  8469. */
  8470. jindo.$Event.prototype.key = function() {
  8471. var e = this._event;
  8472. var k = e.keyCode || e.charCode;
  8473. var ret = {
  8474. keyCode : k,
  8475. alt : e.altKey,
  8476. ctrl : e.ctrlKey,
  8477. meta : e.metaKey,
  8478. shift : e.shiftKey,
  8479. up : (k == 38),
  8480. down : (k == 40),
  8481. left : (k == 37),
  8482. right : (k == 39),
  8483. enter : (k == 13),
  8484. esc : (k == 27)
  8485. };
  8486. this.key = function(){ return ret };
  8487. return ret;
  8488. };
  8489. /**
  8490. * pos 메서드는 마우스 커서의 위치 정보를 리턴한다.
  8491. * @param {Boolean} bGetOffset 현재 엘리먼트에 대한 마우스 커서의 상대위치인 offsetX, offsetY를 구할 것인지의 여부. true면 값을 구한다(offsetX, offsetY는 1.2.0버전부터 추가). $Element 포함되어 있어야 한다.
  8492. * @description [Lite]
  8493. * @example
  8494. function eventHandler(evt) {
  8495. var pos = evt.pos();
  8496. pos.clientX; // Number. 현재 화면에 대한 X 좌표
  8497. pos.clientY; // Number. 현재 화면에 대한 Y 좌표
  8498. pos.pageX; // Number. 문서 전체에 대한 X 좌표
  8499. pos.pageY; // Number. 문서 전체에 대한 Y 좌표
  8500. pos.layerX; // Number. <b>deprecated.</b> 이벤트가 발생한 엘리먼트로부터의 상대적인 X 좌표
  8501. pos.layerY; // Number. <b>deprecated.</b> 이벤트가 발생한 엘리먼트로부터의 상대적인 Y 좌표
  8502. pos.offsetX; // Number. 이벤트가 발생한 엘리먼트에 대한 마우스 커서의 상대적인 X좌표 (1.2.0 이상)
  8503. pos.offsetY; // Number. 이벤트가 발생한 엘리먼트에 대한 마우스 커서의 상대적인 Y좌표 (1.2.0 이상)
  8504. }
  8505. * @return {Object} 마우스 커서의 위치 정보. 객체의 속성은 예제를 참조한다.
  8506. * @remark layerX, layerY는 차후 지원하지 않을(deprecated) 예정입니다.
  8507. */
  8508. jindo.$Event.prototype.pos = function(bGetOffset) {
  8509. var e = this._event;
  8510. var b = (this.element.ownerDocument||document).body;
  8511. var de = (this.element.ownerDocument||document).documentElement;
  8512. var pos = [b.scrollLeft || de.scrollLeft, b.scrollTop || de.scrollTop];
  8513. var ret = {
  8514. clientX : e.clientX,
  8515. clientY : e.clientY,
  8516. pageX : 'pageX' in e ? e.pageX : e.clientX+pos[0]-b.clientLeft,
  8517. pageY : 'pageY' in e ? e.pageY : e.clientY+pos[1]-b.clientTop,
  8518. layerX : 'offsetX' in e ? e.offsetX : e.layerX - 1,
  8519. layerY : 'offsetY' in e ? e.offsetY : e.layerY - 1
  8520. };
  8521. /*
  8522. 오프셋을 구하는 메소드의 비용이 크므로, 요청시에만 구하도록 한다.
  8523. */
  8524. if (bGetOffset && jindo.$Element) {
  8525. var offset = jindo.$Element(this.element).offset();
  8526. ret.offsetX = ret.pageX - offset.left;
  8527. ret.offsetY = ret.pageY - offset.top;
  8528. }
  8529. return ret;
  8530. };
  8531. /**
  8532. * stop 메서드는 이벤트의 버블링과 기본 동작을 중지시킨다.
  8533. * @remark 버블링은 특정 HTML 엘리먼트에서 이벤트가 발생했을 이벤트가 상위 노드로 전파되는 현상이다. 예를 들어, div 객체를 클릭할 div와 함께 상위 엘리먼트인 document에도 onclick 이벤트가 발생한다. stop() 메소드는 지정한 객체에서만 이벤트가 발생하도록 버블링을 차단한다.
  8534. * @description [Lite]
  8535. * @example
  8536. // 기본 동작만 중지시키고 싶을 때 (1.1.3버전 이상)
  8537. function stopDefaultOnly(evt) {
  8538. // Here is some code to execute
  8539. // Stop default event only
  8540. evt.stop($Event.CANCEL_DEFAULT);
  8541. }
  8542. * @return {$Event} 이벤트 객체.
  8543. * @param {Number} nCancel 이벤트의 버블링과 기본 동작을 선택하여 중지시킨다. 기본값은 $Event.CANCEL_ALL 이다(1.1.3 버전 이상).
  8544. */
  8545. jindo.$Event.prototype.stop = function(nCancel) {
  8546. nCancel = nCancel || jindo.$Event.CANCEL_ALL;
  8547. var e = (window.event && window.event == this._globalEvent)?this._globalEvent:this._event;
  8548. var b = !!(nCancel & jindo.$Event.CANCEL_BUBBLE); // stop bubbling
  8549. var d = !!(nCancel & jindo.$Event.CANCEL_DEFAULT); // stop default event
  8550. this.canceled = true;
  8551. if (typeof e.preventDefault != "undefined" && d) e.preventDefault();
  8552. if (typeof e.stopPropagation != "undefined" && b) e.stopPropagation();
  8553. if(d) e.returnValue = false;
  8554. if(b) e.cancelBubble = true;
  8555. return this;
  8556. };
  8557. /**
  8558. * stopDefault 메서드는 이벤트의 기본 동작을 중지시킨다.
  8559. * @return {$Event} 이벤트 객체.
  8560. * @see $Event#stop
  8561. * @description [Lite]
  8562. */
  8563. jindo.$Event.prototype.stopDefault = function(){
  8564. return this.stop(jindo.$Event.CANCEL_DEFAULT);
  8565. }
  8566. /**
  8567. * stopBubble 메서드는 이벤트의 버블링을 중지시킨다.
  8568. * @return {$Event} 이벤트 객체.
  8569. * @see $Event#stop
  8570. * @description [Lite]
  8571. */
  8572. jindo.$Event.prototype.stopBubble = function(){
  8573. return this.stop(jindo.$Event.CANCEL_BUBBLE);
  8574. }
  8575. /**
  8576. * $value 메서드는 원래의 이벤트 객체를 리턴한다
  8577. * @example
  8578. function eventHandler(evt){
  8579. evt.$value();
  8580. }
  8581. * @return {Event} Event
  8582. */
  8583. jindo.$Event.prototype.$value = function() {
  8584. return this._event;
  8585. };
  8586. /**
  8587. * $Event#stop 메서드에서 버블링을 중지시킨다.
  8588. * @final
  8589. */
  8590. jindo.$Event.CANCEL_BUBBLE = 1;
  8591. /**
  8592. * $Event#stop 메서드에서 기본 동작을 중지시킨다.
  8593. * @final
  8594. */
  8595. jindo.$Event.CANCEL_DEFAULT = 2;
  8596. /**
  8597. * $Event#stop 메서드에서 버블링과 기본 동작 모두 중지시킨다.
  8598. * @final
  8599. */
  8600. jindo.$Event.CANCEL_ALL = 3;
  8601. /**
  8602. * @fileOverview $ElementList의 생성자 메서드를 정의한 파일
  8603. * @name elementlist.js
  8604. */
  8605. /**
  8606. * $ElementList 객체를 생성 리턴한다.
  8607. * @class $ElementList 클래스는 id 배열, 혹은 CSS 쿼리 등을 사용하여 DOM 엘리먼트의 배열을 만든다.
  8608. * @param {String | Array} els 문서에서 DOM 엘리먼트를 찾기 위한 CSS 선택자 혹은 id, HTMLElement, $Element의 배열
  8609. * @constructor
  8610. * @borrows $Element#show as this.show
  8611. * @borrows $Element#hide as this.hide
  8612. * @borrows $Element#toggle as this.toggle
  8613. * @borrows $Element#addClass as this.addClass
  8614. * @borrows $Element#removeClass as this.removeClass
  8615. * @borrows $Element#toggleClass as this.toggleClass
  8616. * @borrows $Element#fireEvent as this.fireEvent
  8617. * @borrows $Element#leave as this.leave
  8618. * @borrows $Element#empty as this.empty
  8619. * @borrows $Element#appear as this.appear
  8620. * @borrows $Element#disappear as this.disappear
  8621. * @borrows $Element#className as this.className
  8622. * @borrows $Element#width as this.width
  8623. * @borrows $Element#height as this.height
  8624. * @borrows $Element#text as this.text
  8625. * @borrows $Element#html as this.html
  8626. * @borrows $Element#css as this.css
  8627. * @borrows $Element#attr as this.attr
  8628. * @author Kim, Taegon
  8629. */
  8630. jindo.$ElementList = function (els) {
  8631. var cl = arguments.callee;
  8632. if (els instanceof cl) return els;
  8633. if (!(this instanceof cl)) return new cl(els);
  8634. if (els instanceof Array) {
  8635. els = jindo.$A(els);
  8636. } else if(jindo.$A && els instanceof jindo.$A){
  8637. els = jindo.$A(els.$value());
  8638. } else if (typeof els == "string" && jindo.cssquery) {
  8639. els = jindo.$A(jindo.cssquery(els));
  8640. } else {
  8641. els = jindo.$A();
  8642. }
  8643. this._elements = els.map(function(v,i,a){ return jindo.$Element(v) });
  8644. }
  8645. /**
  8646. * get 메서드는 $ElementList에서 인덱스에 해당하는 엘리먼트를 가져온다.
  8647. * @param {Number} idx 가져올 엘리먼트의 인덱스. 인덱스는 0에서 부터 시작한다.
  8648. * @return {$Element} 인덱스에 해당하는 엘리먼트
  8649. */
  8650. jindo.$ElementList.prototype.get = function(idx) {
  8651. return this._elements.$value()[idx];
  8652. };
  8653. /**
  8654. * getFirst 메서드는 $ElementList의 첫번째 엘리먼트를 가져온다.
  8655. * @remark getFirst 메서드의 리턴값은 $ElementList.get(0) 리턴값과 동일하다.
  8656. * @return {$Element} 첫번째 엘리먼트
  8657. */
  8658. jindo.$ElementList.prototype.getFirst = function() {
  8659. return this.get(0);
  8660. };
  8661. /**
  8662. * length메소드는 $A의 length를 이용한다.(1.4.3 부터 사용 가능.)
  8663. * @return Number 배열의 크기
  8664. * @param {Number} [nLen] 새로 리턴할 배열의 크기. nLen이 기존의 배열보다 크면 oValue으로 초기화한 원소를 마지막에 덧붙인다. nLen이 기존 배열보다 작으면 nLen번째 이후의 원소는 제거한다.
  8665. * @param {Value} [oValue] 새로운 원소를 추가할 사용할 초기값
  8666. * @see $A#length
  8667. */
  8668. jindo.$ElementList.prototype.length = function(nLen, oValue) {
  8669. return this._elements.length(nLen, oValue);
  8670. }
  8671. /**
  8672. * getLast 메서드는 $ElementList의 마지막 엘리먼트를 가져온다.
  8673. * @return {$Element} 마지막 엘리먼트
  8674. */
  8675. jindo.$ElementList.prototype.getLast = function() {
  8676. return this.get(Math.max(this._elements.length()-1,0));
  8677. };
  8678. /**
  8679. * $value 메소드는 자신의 배열 엘리먼트을 반환 한다.
  8680. * @return {Array} $Element가 들어 있는 배열.
  8681. */
  8682. jindo.$ElementList.prototype.$value = function() {
  8683. return this._elements.$value();
  8684. };
  8685. (function(proto){
  8686. var setters = ['show','hide','toggle','addClass','removeClass','toggleClass','fireEvent','leave',
  8687. 'empty','appear','disappear','className','width','height','text','html','css','attr'];
  8688. jindo.$A(setters).forEach(function(name){
  8689. proto[name] = function() {
  8690. var args = jindo.$A(arguments).$value();
  8691. this._elements.forEach(function(el){
  8692. el[name].apply(el, args);
  8693. });
  8694. return this;
  8695. }
  8696. });
  8697. jindo.$A(['appear','disappear']).forEach(function(name){
  8698. proto[name] = function(duration, callback) {
  8699. var len = this._elements.length;
  8700. var self = this;
  8701. this._elements.forEach(function(el,idx){
  8702. if(idx == len-1) {
  8703. el[name](duration, function(){callback(self)});
  8704. } else {
  8705. el[name](duration);
  8706. }
  8707. });
  8708. return this;
  8709. }
  8710. });
  8711. })(jindo.$ElementList.prototype);
  8712. /**
  8713. * @fileOverview $Json의 생성자 메서드를 정의한 파일
  8714. * @name json.js
  8715. */
  8716. /**
  8717. * $S 객체를 생성한다.
  8718. * @class $S 클래스는 문자열을 처리하기 위한 래퍼(Wrapper) 클래스이다.
  8719. * @constructor
  8720. * @param {String} str
  8721. * <br>
  8722. * 문자열을 매개변수로 지정한다.
  8723. * @author Kim, Taegon
  8724. */
  8725. jindo.$S = function(str) {
  8726. var cl = arguments.callee;
  8727. if (typeof str == "undefined") str = "";
  8728. if (str instanceof cl) return str;
  8729. if (!(this instanceof cl)) return new cl(str);
  8730. this._str = str+"";
  8731. }
  8732. /**
  8733. * $value 메서드는 원래의 문자열을 리턴한다.
  8734. * @return {String} 래핑된 원래의 문자열
  8735. * @see $S#toString
  8736. * @example
  8737. var str = $S("Hello world!!");
  8738. str.$value();
  8739. *
  8740. * // 결과 :
  8741. * // Hello world!!
  8742. */
  8743. jindo.$S.prototype.$value = function() {
  8744. return this._str;
  8745. };
  8746. /**
  8747. * toString 메서드는 원래의 문자열을 리턴한다.
  8748. * @return {String} 래핑된 원래의 문자열
  8749. * @remark $value와 같은 의미
  8750. * @example
  8751. var str = $S("Hello world!!");
  8752. str.toString();
  8753. *
  8754. * // 결과 :
  8755. * // Hello world!!
  8756. */
  8757. jindo.$S.prototype.toString = jindo.$S.prototype.$value;
  8758. /**
  8759. * trim 메서드는 문자열의 공백을 제거한다.(1.4.1 부터 전각공백도 제거)
  8760. * @return {$S} 문자열의 끝을 제거한 새로운 $S 객체
  8761. * @example
  8762. var str = " I have many spaces. ";
  8763. document.write ( $S(str).trim() );
  8764. *
  8765. * // 결과 :
  8766. * // I have many spaces.
  8767. */
  8768. jindo.$S.prototype.trim = function() {
  8769. if ("".trim) {
  8770. jindo.$S.prototype.trim = function() {
  8771. return jindo.$S(this._str.trim());
  8772. }
  8773. }else{
  8774. jindo.$S.prototype.trim = function() {
  8775. return jindo.$S(this._str.replace(/^(\s| )+/g, "").replace(/(\s| )+$/g, ""));
  8776. }
  8777. }
  8778. return jindo.$S(this.trim());
  8779. };
  8780. /**
  8781. * escapeHTML 메서드는 HTML 특수 문자를 HTML 엔티티(Entities)형식으로 이스케이프(escape)한다.
  8782. * @return {$S} HTML 특수 문자를 엔티티 형식으로 변환한 새로운 $S 객체
  8783. * @see $S#unescapeHTML
  8784. * @remark ", &, <, > ,' 각각 &quot;, &amp;, &lt;, &gt; &#39; 변경한다.
  8785. * @example
  8786. var str = ">_<;;";
  8787. document.write( $S(str).escapeHTML() );
  8788. *
  8789. * // 결과 :
  8790. * // &amp;gt;_&amp;lt;;;
  8791. */
  8792. jindo.$S.prototype.escapeHTML = function() {
  8793. var entities = {'"':'quot','&':'amp','<':'lt','>':'gt','\'':'#39'};
  8794. var s = this._str.replace(/[<>&"']/g, function(m0){
  8795. return entities[m0]?'&'+entities[m0]+';':m0;
  8796. });
  8797. return jindo.$S(s);
  8798. };
  8799. /**
  8800. * stripTags 메서드는 문자열에서 XML 혹은 HTML 태그를 제거한다.
  8801. * @return {$S} XML 혹은 HTML 태그를 제거한 새로운 $S 객체
  8802. * @example
  8803. var str = "Meeting <b>people</b> is easy.";
  8804. document.write( $S(str).stripTags() );
  8805. *
  8806. * // 결과 :
  8807. * // Meeting people is easy.
  8808. */
  8809. jindo.$S.prototype.stripTags = function() {
  8810. return jindo.$S(this._str.replace(/<\/?(?:h[1-5]|[a-z]+(?:\:[a-z]+)?)[^>]*>/ig, ''));
  8811. };
  8812. /**
  8813. * times 메서드는 문자열을 매개변수로 지정한 숫자만큼 반복한다.
  8814. * @param {Number} nTimes 반복할 횟수
  8815. * @return {$S} 문자열을 지정한 숫자만큼 반복한 새로운 $S 객체
  8816. * @example
  8817. document.write ( $S("Abc").times(3) );
  8818. *
  8819. * // 결과 : AbcAbcAbc
  8820. */
  8821. jindo.$S.prototype.times = function(nTimes) {
  8822. var buf = [];
  8823. for(var i=0; i < nTimes; i++) {
  8824. buf[buf.length] = this._str;
  8825. }
  8826. return jindo.$S(buf.join(''));
  8827. };
  8828. /**
  8829. * unescapeHTML 메서드는 이스케이프(escape) HTML을 원래의 HTML로 리턴한다.
  8830. * @return {$S} 이스케이프된 HTML을 원래의 HTML로 변환한 새로운 $S 객체
  8831. * @remark &quot;, &amp;, &lt;, &gt; &#39; 각각 ", &, <, >, ' 으로 변경한다.
  8832. * @see $S#escapeHTML
  8833. * @example
  8834. * var str = "&lt;a href=&quot;http://naver.com&quot;&gt;Naver&lt;/a&gt;";
  8835. * document.write( $S(str).unescapeHTML() );
  8836. *
  8837. * // 결과 :
  8838. * // <a href="http://naver.com">Naver</a>
  8839. */
  8840. jindo.$S.prototype.unescapeHTML = function() {
  8841. var entities = {'quot':'"','amp':'&','lt':'<','gt':'>','#39':'\''};
  8842. var s = this._str.replace(/&([a-z]+|#[0-9]+);/g, function(m0,m1){
  8843. return entities[m1]?entities[m1]:m0;
  8844. });
  8845. return jindo.$S(s);
  8846. };
  8847. /**
  8848. * escape 메서드는 문자열에 포함된 한글을 ASCII 문자열로 인코딩한다.
  8849. * @remark \r, \n, \t, ', ", non-ASCII 문자를 이스케이프 처리한다.
  8850. * @return {$S} 문자열을 이스케이프 처리한 새로운 $S 객체
  8851. * @see $S#escapeHTML
  8852. * @example
  8853. * var str = '가"\'나\\';
  8854. * document.write( $S(str).escape() );
  8855. *
  8856. * // 결과 :
  8857. * \uAC00\"\'\uB098\\
  8858. */
  8859. jindo.$S.prototype.escape = function() {
  8860. var s = this._str.replace(/([\u0080-\uFFFF]+)|[\n\r\t"'\\]/g, function(m0,m1,_){
  8861. if(m1) return escape(m1).replace(/%/g,'\\');
  8862. return (_={"\n":"\\n","\r":"\\r","\t":"\\t"})[m0]?_[m0]:"\\"+m0;
  8863. });
  8864. return jindo.$S(s);
  8865. };
  8866. /**
  8867. * bytes 메서드는 문자열의 실제 바이트(byte) 수를 리턴하고, 제한하려는 바이트(byte) 수를 지정하면 문자열을 해당 크기에 맞게 잘라낸다.(1.4.3 부터 charset사용 가능)
  8868. * @return 문자열의 바이트 . , 첫번째 매개변수를 설정하면 자기 객체($S) 리턴한다.
  8869. * @param {Number|Object} nBytes 맞출 문자열의 바이트(byte) | charset을 지정할 사용
  8870. * @remark 문서의 charset을 해석해서 인코딩 방식에 따라 한글을 비롯한 유니코드 문자열의 바이트 수를 계산한다.
  8871. * @example
  8872. // 문서가 euc-kr 환경임을 가정합니다.
  8873. *
  8874. var str = "한글과 English가 섞인 문장...";
  8875. document.write( $S(str).bytes() );
  8876. *
  8877. * // 결과 :
  8878. * // 37
  8879. *
  8880. document.write( $S(str).bytes(20) );
  8881. *
  8882. * // 결과 :
  8883. * // 한글과 English가
  8884. *
  8885. document.write( $S(str).bytes({charset:'euc-kr',size:20}) );
  8886. *
  8887. * // 결과 :
  8888. * // 한글과 English가 섞
  8889. *
  8890. document.write( $S(str).bytes({charset:'euc-kr'}) );
  8891. *
  8892. * // 결과 :
  8893. * // 29
  8894. */
  8895. jindo.$S.prototype.bytes = function(vConfig) {
  8896. var code = 0, bytes = 0, i = 0, len = this._str.length;
  8897. var charset = ((document.charset || document.characterSet || document.defaultCharset)+"");
  8898. var cut,nBytes;
  8899. if (typeof vConfig == "undefined") {
  8900. cut = false;
  8901. }else if(vConfig.constructor == Number){
  8902. cut = true;
  8903. nBytes = vConfig;
  8904. }else if(vConfig.constructor == Object){
  8905. charset = vConfig.charset||charset;
  8906. nBytes = vConfig.size||false;
  8907. cut = !!nBytes;
  8908. }else{
  8909. cut = false;
  8910. }
  8911. if (charset.toLowerCase() == "utf-8") {
  8912. /*
  8913. 유니코드 문자열의 바이트 수는 위키피디아를 참고했다(http://ko.wikipedia.org/wiki/UTF-8).
  8914. */
  8915. for(i=0; i < len; i++) {
  8916. code = this._str.charCodeAt(i);
  8917. if (code < 128) {
  8918. bytes += 1;
  8919. }else if (code < 2048){
  8920. bytes += 2;
  8921. }else if (code < 65536){
  8922. bytes += 3;
  8923. }else{
  8924. bytes += 4;
  8925. }
  8926. if (cut && bytes > nBytes) {
  8927. this._str = this._str.substr(0,i);
  8928. break;
  8929. }
  8930. }
  8931. } else {
  8932. for(i=0; i < len; i++) {
  8933. bytes += (this._str.charCodeAt(i) > 128)?2:1;
  8934. if (cut && bytes > nBytes) {
  8935. this._str = this._str.substr(0,i);
  8936. break;
  8937. }
  8938. }
  8939. }
  8940. return cut?this:bytes;
  8941. };
  8942. /**
  8943. * parseString 메서드는 URL 쿼리 스트링을 객체로 파싱한다.
  8944. * @return {Object} 문자열을 파싱한 객체
  8945. * @example
  8946. * var str = "aa=first&bb=second";
  8947. * var obj = $S(str).parseString();
  8948. *
  8949. * // 결과 :
  8950. * // obj => { aa : "first", bb : "second" }
  8951. */
  8952. jindo.$S.prototype.parseString = function() {
  8953. if(this._str=="") return {};
  8954. var str = this._str.split(/&/g), pos, key, val, buf = {},isescape = false;
  8955. for(var i=0; i < str.length; i++) {
  8956. key = str[i].substring(0, pos=str[i].indexOf("=")), isescape = false;
  8957. try{
  8958. val = decodeURIComponent(str[i].substring(pos+1));
  8959. }catch(e){
  8960. isescape = true;
  8961. val = decodeURIComponent(unescape(str[i].substring(pos+1)));
  8962. }
  8963. if (key.substr(key.length-2,2) == "[]") {
  8964. key = key.substring(0, key.length-2);
  8965. if (typeof buf[key] == "undefined") buf[key] = [];
  8966. buf[key][buf[key].length] = isescape? escape(val) : val;;
  8967. } else {
  8968. buf[key] = isescape? escape(val) : val;
  8969. }
  8970. }
  8971. return buf;
  8972. };
  8973. /**
  8974. * escapeRegex 메서드는 정규식에 사용할 있도록 문자열을 이스케이프(escape) 한다.
  8975. * @since 1.2.0
  8976. * @return {String} 이스케이프된 문자열
  8977. * @example
  8978. var str = "Slash / is very important. Backslash \ is more important. +_+";
  8979. document.write( $S(str).escapeRegex() );
  8980. *
  8981. * // 결과 : \/ is very important\. Backslash \\ is more important\. \+_\+
  8982. */
  8983. jindo.$S.prototype.escapeRegex = function() {
  8984. var s = this._str;
  8985. var r = /([\?\.\*\+\-\/\(\)\{\}\[\]\:\!\^\$\\\|])/g;
  8986. return jindo.$S(s.replace(r, "\\$1"));
  8987. };
  8988. /**
  8989. * format 메서드는 문자열을 형식 문자열에 대입하여 새로운 문자열을 만든다. 형식 문자열은 % 시작하며, 형식 문자열의 종류는 <a href="http://www.php.net/manual/en/function.sprintf.php">PHP</a> .
  8990. * @param {String} formatString 형식 문자열
  8991. * @return {String} 문자열을 형식 문자열에 대입하여 만든 새로운 문자열.
  8992. * @example
  8993. var str = $S("%4d년 %02d월 %02d일").format(2008, 2, 13);
  8994. *
  8995. * // 결과 :
  8996. * // str = "2008년 02월 13일"
  8997. var str = $S("패딩 %5s 빈공백").format("값");
  8998. *
  8999. * // 결과 :
  9000. * // str => "패딩 값 빈공백"
  9001. var str = $S("%b").format(10);
  9002. *
  9003. * // 결과 :
  9004. * // str => "1010"
  9005. var str = $S("%x").format(10);
  9006. *
  9007. * // 결과 :
  9008. * // str => "a"
  9009. var str = $S("%X").format(10);
  9010. *
  9011. * // 결과 :
  9012. * // str => "A"
  9013. * @see $S#times
  9014. */
  9015. jindo.$S.prototype.format = function() {
  9016. var args = arguments;
  9017. var idx = 0;
  9018. var s = this._str.replace(/%([ 0])?(-)?([1-9][0-9]*)?([bcdsoxX])/g, function(m0,m1,m2,m3,m4){
  9019. var a = args[idx++];
  9020. var ret = "", pad = "";
  9021. m3 = m3?+m3:0;
  9022. if (m4 == "s") {
  9023. ret = a+"";
  9024. } else if (" bcdoxX".indexOf(m4) > 0) {
  9025. if (typeof a != "number") return "";
  9026. ret = (m4 == "c")?String.fromCharCode(a):a.toString(({b:2,d:10,o:8,x:16,X:16})[m4]);
  9027. if (" X".indexOf(m4) > 0) ret = ret.toUpperCase();
  9028. }
  9029. if (ret.length < m3) pad = jindo.$S(m1||" ").times(m3 - ret.length).toString();
  9030. (m2 == '-')?(ret+=pad):(ret=pad+ret);
  9031. return ret;
  9032. });
  9033. return jindo.$S(s);
  9034. };
  9035. /**
  9036. * @fileOverview $Document 생성자 메서드를 정의한 파일
  9037. * @name document.js
  9038. */
  9039. /**
  9040. * $Document 객체를 생성하고 리턴한다.
  9041. * @class $Document 클래스는 문서와 관련된 여러가지 기능의 메서드를 제공한다
  9042. * @param {Document} doc 기능에 사용된 document 객체. 기본값은 현재 문서의 document.
  9043. * @constructor
  9044. * @author Hooriza
  9045. */
  9046. jindo.$Document = function (el) {
  9047. var cl = arguments.callee;
  9048. if (el instanceof cl) return el;
  9049. if (!(this instanceof cl)) return new cl(el);
  9050. this._doc = el || document;
  9051. this._docKey = this.renderingMode() == 'Standards' ? 'documentElement' : 'body';
  9052. };
  9053. /**
  9054. * $value 메서드는 원래의 document 객체를 리턴한다.
  9055. * @return {HTMLDocument} document 객체
  9056. */
  9057. jindo.$Document.prototype.$value = function() {
  9058. return this._doc;
  9059. };
  9060. /**
  9061. * scrollSize 메서드는 문서의 실제 가로, 세로 크기를 구한다
  9062. * @return {Object} 가로크기는 width, 세로크기는 height 라는 키값으로 리턴된다.
  9063. * @example
  9064. var size = $Document().scrollSize();
  9065. alert('가로 : ' + size.width + ' / 세로 : ' + size.height);
  9066. */
  9067. jindo.$Document.prototype.scrollSize = function() {
  9068. /*
  9069. webkit 계열에서는 Standard 모드라도 body를 사용해야 정상적인 scroll Size를 얻어온다.
  9070. */
  9071. var isWebkit = navigator.userAgent.indexOf("WebKit")>-1;
  9072. var oDoc = this._doc[isWebkit?'body':this._docKey];
  9073. return {
  9074. width : Math.max(oDoc.scrollWidth, oDoc.clientWidth),
  9075. height : Math.max(oDoc.scrollHeight, oDoc.clientHeight)
  9076. };
  9077. };
  9078. /**
  9079. * scrollPosition 메서드는 문서의 스크롤바 위치를 구한다
  9080. * @return {Object} 가로 위치는 left, 세로위치는 top 라는 키값으로 리턴된다.
  9081. * @example
  9082. var size = $Document().scrollPosition();
  9083. alert('가로 : ' + size.left + ' / 세로 : ' + size.top);
  9084. * @since 1.3.5
  9085. */
  9086. jindo.$Document.prototype.scrollPosition = function() {
  9087. /*
  9088. webkit 계열에서는 Standard 모드라도 body를 사용해야 정상적인 scroll Size를 얻어온다.
  9089. */
  9090. var isWebkit = navigator.userAgent.indexOf("WebKit")>-1;
  9091. var oDoc = this._doc[isWebkit?'body':this._docKey];
  9092. return {
  9093. left : oDoc.scrollLeft||window.pageXOffset||window.scrollX||0,
  9094. top : oDoc.scrollTop||window.pageYOffset||window.scrollY||0
  9095. };
  9096. };
  9097. /**
  9098. * clientSize 메서드는 스크롤바로 인해 가려진 부분을 제외한 문서 보이는 부분의 가로, 세로 크기를 구한다
  9099. * @return {Object} 가로크기는 width, 세로크기는 height 라는 키값으로 리턴된다
  9100. * @example
  9101. var size = $Document(document).clientSize();
  9102. alert('가로 : ' + size.width + ' / 세로 : ' + size.height);
  9103. */
  9104. jindo.$Document.prototype.clientSize = function() {
  9105. var agent = navigator.userAgent;
  9106. var oDoc = this._doc[this._docKey];
  9107. var isSafari = agent.indexOf("WebKit")>-1 && agent.indexOf("Chrome")==-1;
  9108. /*
  9109. 사파리의 경우 윈도우 리사이즈시에 clientWidth,clientHeight값이 정상적으로 나오지 않아서 window.innerWidth,innerHeight로 대체
  9110. */
  9111. return (isSafari)?{
  9112. width : window.innerWidth,
  9113. height : window.innerHeight
  9114. }:{
  9115. width : oDoc.clientWidth,
  9116. height : oDoc.clientHeight
  9117. };
  9118. };
  9119. /**
  9120. * renderingMode 메서드는 문서의 렌더링 방식을 얻는다
  9121. * @return {String} 렌더링 모드
  9122. * <dl>
  9123. * <dt>Standards</dt>
  9124. * <dd>표준 렌더링 모드</dd>
  9125. * <dt>Almost</dt>
  9126. * <dd>유사 표준 렌더링 모드 (IE 외의 브라우저에서 DTD 올바르게 지정하지 않았을때 리턴)</dd>
  9127. * <dt>Quirks</dt>
  9128. * <dd>비표준 렌더링 모드</dd>
  9129. * </dl>
  9130. * @example
  9131. var mode = $Document().renderingMode();
  9132. alert('렌더링 방식 : ' + mode);
  9133. */
  9134. jindo.$Document.prototype.renderingMode = function() {
  9135. var agent = navigator.userAgent;
  9136. var isIe = (typeof window.opera=="undefined" && agent.indexOf("MSIE")>-1);
  9137. var isSafari = (agent.indexOf("WebKit")>-1 && agent.indexOf("Chrome")<0 && navigator.vendor.indexOf("Apple")>-1);
  9138. var sRet;
  9139. if ('compatMode' in this._doc){
  9140. sRet = this._doc.compatMode == 'CSS1Compat' ? 'Standards' : (isIe ? 'Quirks' : 'Almost');
  9141. }else{
  9142. sRet = isSafari ? 'Standards' : 'Quirks';
  9143. }
  9144. return sRet;
  9145. };
  9146. /**
  9147. * 문서에서 주어진 selector를 만족시키는 요소의 배열을 반환한다. 만족하는 요소가 존재하지 않으면 배열을 반환한다.
  9148. * @param {String} sSelector
  9149. * @return {Array} 조건을 만족하는 요소의 배열
  9150. */
  9151. jindo.$Document.prototype.queryAll = function(sSelector) {
  9152. return jindo.$$(sSelector, this._doc);
  9153. };
  9154. /**
  9155. * 문서에서 주어진 selector를 만족시키는 요소중 번째 요소를 반환한다. 만족하는 요소가 존재하지 않으면 null을 반환한다.
  9156. * @param {String} sSelector
  9157. * @return {Element} 조건을 만족하는 요소중 첫번째 요소
  9158. */
  9159. jindo.$Document.prototype.query = function(sSelector) {
  9160. return jindo.$$.getSingle(sSelector, this._doc);
  9161. };
  9162. /**
  9163. * 문서에서 XPath 문법에 해당하는 모든 엘리먼트를 배열로 리턴한다.
  9164. * @remark 지원하는 문법에 제약 사항이 많으므로 특수한 경우에만 사용한다.
  9165. * @param {String} sXPath 엘리먼트의 위치를 지정한 XPath
  9166. * @return {Array} path에 해당하는 요소의 배열
  9167. * @example
  9168. var oDocument = $Document();
  9169. alert (oDocument.xpathAll("body/div/div").length);
  9170. */
  9171. jindo.$Document.prototype.xpathAll = function(sXPath) {
  9172. return jindo.$$.xpath(sXPath, this._doc);
  9173. };
  9174. /**
  9175. * @fileOverview $Form 생성자 메서드를 정의한 파일
  9176. * @name form.js
  9177. */
  9178. /**
  9179. * $Form 객체를 생성 리턴한다.
  9180. * @class $Form 클래스는 form 엘리먼트와 자식 엘리먼트를 제어하는 클래스이다.
  9181. * @param {Element | String} el (form) 엘리먼트, 혹은 엘리먼트의 id. 만약 동일한 id를 이상의 엘리먼트에서 사용하면 먼저 나오는 엘리먼트를 리턴한다.
  9182. * @constructor
  9183. * @author Hooriza
  9184. */
  9185. jindo.$Form = function (el) {
  9186. var cl = arguments.callee;
  9187. if (el instanceof cl) return el;
  9188. if (!(this instanceof cl)) return new cl(el);
  9189. el = jindo.$(el);
  9190. if (!el.tagName || el.tagName.toUpperCase() != 'FORM') throw new Error('The element should be a FORM element');
  9191. this._form = el;
  9192. }
  9193. /**
  9194. * $value 메서드는 랩핑된 원래 엘리먼트를 리턴한다
  9195. * @return {HTMLElement} 엘리먼트
  9196. * @example
  9197. var el = $('<form>');
  9198. var form = $Form(el);
  9199. alert(form.$value() === el); // true
  9200. */
  9201. jindo.$Form.prototype.$value = function() {
  9202. return this._form;
  9203. };
  9204. /**
  9205. * serialize 메서드는 특정 또는 전체 엘리멘트 입력요소를 문자열 형태로 리턴한다.
  9206. * @param {Mixed} Mixed 인수를 지정하지 않거나 인수를 하나 이상 설정할 있다.
  9207. * <ol>
  9208. * <li>매개 변수를 지정하지 않으면 엘리먼트와 자식 엘리먼트의 모든 값을 쿼리 형태의 문자열로 리턴한다.</li>
  9209. * <li>매개 변수로 문자열을 설정하면 문자열과 일치하는 name 속성을 가지는 엘리먼트를 탐색하고 값을 리턴한다.</li>
  9210. * <li>매배 변수로 이상의 문자열을 설정하면, 문자열과 일치하는 name 속성을 가지는 엘리먼트를 모두 탐색하고 값을 쿼리 스트링 형태로 리턴한다. </li>
  9211. * </ol>
  9212. * @return {String} 쿼리 문자열 형태로 변환한 엘리먼트와 .
  9213. * @example
  9214. <form id="TEST">
  9215. <input name="ONE" value="1" type="text" />
  9216. <input name="TWO" value="2" checked="checked" type="checkbox" />
  9217. <input name="THREE" value="3_1" type="radio" />
  9218. <input name="THREE" value="3_2" checked="checked" type="radio" />
  9219. <input name="THREE" value="3_3" type="radio" />
  9220. <select name="FOUR">
  9221. <option value="4_1">..</option>
  9222. <option value="4_2">..</option>
  9223. <option value="4_3" selected="selected">..</option>
  9224. </select>
  9225. </form>
  9226. <script type="text/javascript">
  9227. var form = $Form('TEST');
  9228. var allstr = form.serialize();
  9229. alert(allstr == 'ONE=1&TWO=2&THREE=3_2&FOUR=4_3'); // true
  9230. var str = form.serialize('ONE', 'THREE');
  9231. alert(str == 'ONE=1&THREE=3_2'); // true
  9232. </script>
  9233. */
  9234. jindo.$Form.prototype.serialize = function() {
  9235. var self = this;
  9236. var oRet = {};
  9237. var nLen = arguments.length;
  9238. var fpInsert = function(sKey) {
  9239. var sVal = self.value(sKey);
  9240. if (typeof sVal != 'undefined') oRet[sKey] = sVal;
  9241. };
  9242. if (nLen == 0) {
  9243. jindo.$A(this.element()).forEach(function(o) { if (o.name) fpInsert(o.name); });
  9244. }else{
  9245. for (var i = 0; i < nLen; i++) {
  9246. fpInsert(arguments[i]);
  9247. }
  9248. }
  9249. return jindo.$H(oRet).toQueryString();
  9250. };
  9251. /**
  9252. * element 메서드는 특정 또는 전체 입력요소를 리턴한다.
  9253. * @param {String} sKey 얻고자 하는 입력요소 엘리먼트의 name 문자열, 생략시에는 모든 입력요소들을 배열로 리턴한다.
  9254. * @return {HTMLElement | Array} 입력 요소 엘리먼트
  9255. */
  9256. jindo.$Form.prototype.element = function(sKey) {
  9257. if (arguments.length > 0)
  9258. return this._form[sKey];
  9259. return this._form.elements;
  9260. };
  9261. /**
  9262. * enable 메서드는 입력 요소의 활성화 여부를 얻거나 설정한다.
  9263. * @param {Mixed} mixed enable 메서드는 매개 변수의 개수나 종류에 따라 다르게 동작한다. 자세한 사용법은 다음과 같다.
  9264. * <ol>
  9265. * <li> 매개 변수로 문자열을 사용하면 문자열과 일치하는 name 속성을 가진 엘리먼트를 탐색한다. 엘리먼트를 발견했다면 엘리먼트의 활성화 여부를 리턴한다.</li>
  9266. * <li> 매개 변수로 문자열과 불린(Boolean) 사용하면 문자열과 일치하는 name 속성을 가진 엘리먼트를 탐색한 , 활성화 여부를 설정한다. </li>
  9267. * <li> 매개 변수로 객체를 사용할 있다. 객체는 속성 값과 name이 일치하는 엘리먼트를 탐색해서 값에 따라 활성화 여부를 설정한다. </li>
  9268. * </ol>
  9269. * @return {Boolean|$Form} 엘리먼트의 활성화 여부를 가져오거나 엘리먼트의 활성화 여부를 설정한 $Form 객체.
  9270. * @example
  9271. <form id="TEST">
  9272. <input name="ONE" disabled="disabled" type="text" />
  9273. <input name="TWO" type="checkbox" />
  9274. </form>
  9275. <script type="text/javascript">
  9276. var form = $Form('TEST');
  9277. var one_enabled = form.enable('ONE');
  9278. alert(one_enabled === false); // true
  9279. form.enable('TWO', false);
  9280. form.enable({
  9281. 'ONE' : true,
  9282. 'TWO' : false
  9283. });
  9284. </script>
  9285. */
  9286. jindo.$Form.prototype.enable = function() {
  9287. var sKey = arguments[0];
  9288. if (typeof sKey == 'object') {
  9289. var self = this;
  9290. jindo.$H(sKey).forEach(function(bFlag, sKey) { self.enable(sKey, bFlag); });
  9291. return this;
  9292. }
  9293. var aEls = this.element(sKey);
  9294. if (!aEls) return this;
  9295. aEls = aEls.nodeType == 1 ? [ aEls ] : aEls;
  9296. if (arguments.length < 2) {
  9297. var bEnabled = true;
  9298. jindo.$A(aEls).forEach(function(o) { if (o.disabled) {
  9299. bEnabled = false;
  9300. jindo.$A.Break();
  9301. }});
  9302. return bEnabled;
  9303. } else { // setter
  9304. var sFlag = arguments[1];
  9305. jindo.$A(aEls).forEach(function(o) { o.disabled = !sFlag; });
  9306. return this;
  9307. }
  9308. };
  9309. /**
  9310. * value 메서드는 엘리먼트의 값을 얻거나 설정한다.
  9311. * @param {Mixed} Mixed 정확안 인수 정보는 다음과 같다.
  9312. * <ol>
  9313. * <li>매개 변수로 문자열을 설정하면 name 속성이 일치하는 앨리먼트를 탐색하고 값을 리턴한다</li>
  9314. * <li>매개 변수로 개의 문자열과 불린 값을 name 속성이 일치하는 앨리먼트를 탐색하고 값을 설정한다. </br> checkbox, radio, selectbox / .</li>
  9315. * <li> 이상의 엘리먼트 값을 동시에 지정하고 싶으면 '엘리먼트 이름 : 엘리먼트 값' 원소로 가지는 객체를 매개 변수로 설정한다.</li>
  9316. * </ol>
  9317. * @return {String|$Form} 인수로 엘리먼트만 지정했다면 지정한 엘리먼트의 값을, 인수로 엘리먼와 엘리먼트의 값을 지정했다면 $Form 객체를 리턴한다.
  9318. * @example
  9319. <form id="TEST">
  9320. <input name="ONE" value="1" type="text" />
  9321. <input name="TWO" value="2" type="checkbox" />
  9322. </form>
  9323. <script type="text/javascript">
  9324. var form = $Form('TEST');
  9325. var one_value = form.value('ONE');
  9326. alert(one_value === '1'); // true
  9327. var two_value = form.value('TWO');
  9328. alert(two_value === undefined); // true
  9329. form.value('TWO', 2);
  9330. alert(two_value === '2'); // true
  9331. form.value({
  9332. 'ONE' : '1111',
  9333. 'TWO' : '2'
  9334. });
  9335. // form.value('ONE') -> 1111
  9336. // form.value('ONE') -> 2
  9337. </script>
  9338. */
  9339. jindo.$Form.prototype.value = function(sKey) {
  9340. if (typeof sKey == 'object') {
  9341. var self = this;
  9342. jindo.$H(sKey).forEach(function(bFlag, sKey) { self.value(sKey, bFlag); });
  9343. return this;
  9344. }
  9345. var aEls = this.element(sKey);
  9346. if (!aEls) throw new Error('엘리먼트는 존재하지 않습니다.');
  9347. aEls = aEls.nodeType == 1 ? [ aEls ] : aEls;
  9348. if (arguments.length > 1) { // setter
  9349. var sVal = arguments[1];
  9350. jindo.$A(aEls).forEach(function(o) {
  9351. switch (o.type) {
  9352. case 'radio':
  9353. o.checked = (o.value == sVal);
  9354. break;
  9355. case 'checkbox':
  9356. if(sVal.constructor == Array){
  9357. o.checked = jindo.$A(sVal).has(o.value);
  9358. }else{
  9359. o.checked = (o.value == sVal);
  9360. }
  9361. break;
  9362. case 'select-one':
  9363. var nIndex = -1;
  9364. for (var i = 0, len = o.options.length; i < len; i++){
  9365. if (o.options[i].value == sVal) nIndex = i;
  9366. }
  9367. o.selectedIndex = nIndex;
  9368. break;
  9369. case 'select-multiple':
  9370. var nIndex = -1;
  9371. if(sVal.constructor == Array){
  9372. var waVal = jindo.$A(sVal);
  9373. for (var i = 0, len = o.options.length; i < len; i++){
  9374. o.options[i].selected = waVal.has(o.options[i].value);
  9375. }
  9376. }else{
  9377. for (var i = 0, len = o.options.length; i < len; i++){
  9378. if (o.options[i].value == sVal) nIndex = i;
  9379. }
  9380. o.selectedIndex = nIndex;
  9381. }
  9382. break;
  9383. default:
  9384. o.value = sVal;
  9385. break;
  9386. }
  9387. });
  9388. return this;
  9389. }
  9390. // getter
  9391. var aRet = [];
  9392. jindo.$A(aEls).forEach(function(o) {
  9393. switch (o.type) {
  9394. case 'radio':
  9395. case 'checkbox':
  9396. if (o.checked) aRet.push(o.value);
  9397. break;
  9398. case 'select-one':
  9399. if (o.selectedIndex != -1) aRet.push(o.options[o.selectedIndex].value);
  9400. break;
  9401. case 'select-multiple':
  9402. if (o.selectedIndex != -1){
  9403. for (var i = 0, len = o.options.length; i < len; i++){
  9404. if (o.options[i].selected) aRet.push(o.options[i].value);
  9405. }
  9406. }
  9407. break;
  9408. default:
  9409. aRet.push(o.value);
  9410. break;
  9411. }
  9412. });
  9413. return aRet.length > 1 ? aRet : aRet[0];
  9414. };
  9415. /**
  9416. * submit 메서드는 폼의 데이터를 웹으로 제출(submit) 한다.
  9417. * @param {String} sTargetName 제출할 폼이 있는 윈도우의 이름. sTargetName을 생략하면 기본 타겟
  9418. * @param {String} fValidation 제출할 폼의 밸리데이션 함수. form 요소를 인자로 받는다.
  9419. * @return {$Form} 데이터를 제출한 $Form 객체.
  9420. * @example
  9421. var form = $Form(el);
  9422. form.submit();
  9423. form.submit('foo');
  9424. */
  9425. jindo.$Form.prototype.submit = function(sTargetName, fValidation) {
  9426. var sOrgTarget = null;
  9427. if (typeof sTargetName == 'string') {
  9428. sOrgTarget = this._form.target;
  9429. this._form.target = sTargetName;
  9430. }
  9431. if(typeof sTargetName == 'function') fValidation = sTargetName;
  9432. if(typeof fValidation != 'undefined'){
  9433. if(!fValidation(this._form)) return this;
  9434. }
  9435. this._form.submit();
  9436. if (sOrgTarget !== null)
  9437. this._form.target = sOrgTarget;
  9438. return this;
  9439. };
  9440. /**
  9441. * reset 메서드는 폼을 초기화(reset)한다.
  9442. * @param {String} fValidation 제출할 폼의 밸리데이션 함수. form 요소를 인자로 받는다.
  9443. * @return {$Form} 초기화한 $Form 객체.
  9444. * @example
  9445. var form = $Form(el);
  9446. form.reset();
  9447. */
  9448. jindo.$Form.prototype.reset = function(fValidation) {
  9449. if(typeof fValidation != 'undefined'){
  9450. if(!fValidation(this._form)) return this;
  9451. }
  9452. this._form.reset();
  9453. return this;
  9454. };
  9455. /**
  9456. * @fileOverview $Template의 생성자 메서드를 정의한 파일
  9457. * @name template.js
  9458. */
  9459. /**
  9460. * $Template 객체를 생성한다.
  9461. * @class $Template 클래스는 템플릿을 해석하여 템플릿 문자열에 동적으로 문자를 삽입한다.
  9462. * @constructor
  9463. * @author Kim, Taegon
  9464. *
  9465. * @param {String | HTML Element | $Template} str
  9466. * <br>
  9467. * $Template 문자열, HTML 엘리먼트, 혹은 $Template 인자로 지정할 있다.<br>
  9468. * <br>
  9469. * 인자가 문자열이면 가지 방식으로 동작한다.<br>
  9470. * 만일 문자열이 HTML 엘리먼트의 id 라면 HTML 엘리먼트의 innerHTML 템플릿으로 사용한다.<br>
  9471. * 만약 일반 문자열이라면 문자열 자체를 템플릿으로 사용한다.<br>
  9472. * <br>
  9473. * 인자가 HTML 엘리먼트이면 TEXTAREA SCRIPT 만이 사용 가능하다.<br>
  9474. * HTML 엘리먼트 value 값의 문자열을 플릿으로 사용하며, value 값이 없는 경우 HTML 엘리먼트의 innerHTML을 템플릿으로 사용한다.<br>
  9475. * <br>
  9476. * 인자가 $Template 이면 전달된 인자를 그대로 반환하며 인자를 생략하면 "" 템플릿으로 사용한다.
  9477. * @return {$Template} 생성된 $Template 객체
  9478. *
  9479. * @remark 인자가 SCRIPT인 경우의 type은 반드시 "text/template"으로 지정해야 한다.
  9480. *
  9481. * @example
  9482. // 인자가 일반 문자열인 경우
  9483. var tpl = $Template("{=service} : {=url}");
  9484. *
  9485. * @example
  9486. <textarea id="tpl1">
  9487. {=service} : {=url}
  9488. &lt;/textarea&gt;
  9489. // 같은 TEXTAREA 엘리먼트를 템플릿으로 사용한다
  9490. var template1 = $Template("tpl1"); // 인자가 HTML 엘리먼트의 id 아이디
  9491. var template2 = $Template($("tpl1")); // 인자가 TEXTAREA 엘리먼트인 경우
  9492. </script>
  9493. *
  9494. * @example
  9495. <script type="text/template" id="tpl2">
  9496. {=service} : {=url}
  9497. </script>
  9498. // 같은 SCRIPT 엘리먼트를 템플릿으로 사용한다
  9499. var template1 = $Template("tpl2"); // 인자가 HTML 엘리먼트의 id 아이디
  9500. var template2 = $Template($("tpl2")); // 인자가 SCRIPT 엘리먼트인 경우
  9501. */
  9502. jindo.$Template = function(str) {
  9503. var obj = null, tag = "";
  9504. var cl = arguments.callee;
  9505. if (str instanceof cl) return str;
  9506. if (!(this instanceof cl)) return new cl(str);
  9507. if(typeof str == "undefined") {
  9508. str = "";
  9509. }else if( (obj=document.getElementById(str)||str) && obj.tagName && (tag=obj.tagName.toUpperCase()) && (tag == "TEXTAREA" || (tag == "SCRIPT" && obj.getAttribute("type") == "text/template")) ) {
  9510. str = (obj.value||obj.innerHTML).replace(/^\s+|\s+$/g,"");
  9511. }
  9512. this._str = str+"";
  9513. }
  9514. jindo.$Template.splitter = /(?!\\)[\{\}]/g;
  9515. jindo.$Template.pattern = /^(?:if (.+)|elseif (.+)|for (?:(.+)\:)?(.+) in (.+)|(else)|\/(if|for)|=(.+)|js (.+)|set (.+))$/;
  9516. /**
  9517. * 템플릿을 해석하고 데이터를 적용하여 새로운 문자열을 생성한다.<br>
  9518. * <br>
  9519. * 템플릿을 해석할 때에<br>
  9520. * 템플릿 내에 패턴이 있으면 패턴에 따라 템플릿을 해석하는 방법이 다르다.( 패턴의 해석은 예제를 참고한다)<br>
  9521. * 템플릿 내에 패턴이 없으면 단순 문자열 치환으로 처리한다.
  9522. * @param {Object} data 템플릿에 들어갈 데이터를 가지는 객체<br>
  9523. * 템플릿에 데이터를 적용할 부분은 객체의 프로퍼티(property) 이름으로 찾는다.
  9524. * @return {String} 템플릿을 해석하고 데이터를 적용한 새로운 문자열
  9525. *
  9526. * @example
  9527. // 단순 문자열 치환
  9528. // {=value} 부분의 값을 치환한다.
  9529. var tpl = $Template("Value1 : {=val1}, Value2 : {=val2}")
  9530. var data = { val1: "first value", val2: "second value" };
  9531. document.write( tpl.process(data) );
  9532. // 결과
  9533. // Value1 : first value, Value2 : second value
  9534. * @example
  9535. // if/elseif/else : 조건문
  9536. // 템플릿을 해석할 때 조건문을 판단하여 처리한다.
  9537. var tpl= $Template("{if num >= 7}7보다 크거나 같다.{elseif num <= 5}5보다 작거나 같다.{else}아마 6?{/if}");
  9538. var data = { num: 5 };
  9539. document.write( tpl.process(data) );
  9540. // 결과
  9541. // 5보다 작거나 같다.
  9542. * @example
  9543. // set : 임시 변수 사용
  9544. // set val=1 로 설정하는 경우 {=val} 부분에 1을 대입한다.
  9545. var tpl = $Template("{set val3=val1}Value1 : {=val1}, Value2 : {=val2}, Value3 : {=val3}")
  9546. var data = { val1: "first value", val2: "second value" };
  9547. document.write( tpl.process(data) );
  9548. // 결과
  9549. // Value1 : first value, Value2 : second value, Value3 : first value
  9550. * @example
  9551. // js : JavaScript 사용
  9552. // 템플릿을 해석할 때 해당 JavaScript를 실행한다.
  9553. var tpl = $Template("Value1 : {js $S(=val1).bytes()}, Value2 : {=val2}")
  9554. var data = { val1: "first value", val2: "second value" };
  9555. document.write( tpl.process(data) );
  9556. // 결과
  9557. // Value1 : 11, Value2 : second value
  9558. * @example
  9559. // for in : 반복문(인덱스를 사용하지 않는 경우)
  9560. var tpl = $Template("<h1>포탈 사이트</h1>\n<ul>{for site in portals}\n<li><a href='{=site.url}'>{=site.name}</a></li>{/for}\n</ul>");
  9561. var data = { portals: [
  9562. { name: "네이버", url : "http://www.naver.com" },
  9563. { name: "다음", url : "http://www.daum.net" },
  9564. { name: "야후", url : "http://www.yahoo.co.kr" }
  9565. ]};
  9566. document.write( tpl.process(data) );
  9567. // 결과
  9568. //<h1>포탈 사이트</h1>
  9569. //<ul>
  9570. //<li><a href='http://www.naver.com'>네이버</a></li>
  9571. //<li><a href='http://www.daum.net'>다음</a></li>
  9572. //<li><a href='http://www.yahoo.co.kr'>야후</a></li>
  9573. //</ul>
  9574. * @example
  9575. // for: 반복문(인덱스를 사용하는 경우)
  9576. var tpl = $Template("{for num:word in numbers}{=word}({=num}){/for}");
  9577. var data = { numbers: ["zero", "one", "two", "three"] };
  9578. document.write( tpl.process(data) );
  9579. // 결과
  9580. // zero(0) one(1) two(2) three(3)
  9581. */
  9582. jindo.$Template.prototype.process = function(data) {
  9583. var key = "\x01";
  9584. var leftBrace = "\x02";
  9585. var rightBrace = "\x03";
  9586. var tpl = (" "+this._str+" ").replace(/\\{/g,leftBrace).replace(/\\}/g,rightBrace).replace(/(?!\\)\}\{/g, "}"+key+"{").split(jindo.$Template.splitter), i = tpl.length;
  9587. var map = {'"':'\\"','\\':'\\\\','\n':'\\n','\r':'\\r','\t':'\\t','\f':'\\f'};
  9588. var reg = [/(["'](?:(?:\\.)+|[^\\["']+)*["']|[a-zA-Z_][\w\.]*)/g, /[\n\r\t\f"\\]/g, /^\s+/, /\s+$/, /#/g];
  9589. var cb = [function(m){ return (m.substring(0,1)=='"' || m.substring(0,1)=='\''||m=='null')?m:"d."+m; }, function(m){return map[m]||m}, "", ""];
  9590. var stm = [];
  9591. var lev = 0;
  9592. // remove " "
  9593. tpl[0] = tpl[0].substr(1);
  9594. tpl[i-1] = tpl[i-1].substr(0, tpl[i-1].length-1);
  9595. // no pattern
  9596. if(i<2) return tpl[0];
  9597. tpl = jindo.$A(tpl).reverse().$value();
  9598. var delete_info;
  9599. while(i--) {
  9600. if(i%2) {
  9601. tpl[i] = tpl[i].replace(jindo.$Template.pattern, function(){
  9602. var m = arguments;
  9603. // set
  9604. if (m[10]) {
  9605. return m[10].replace(/(\w+)(?:\s*)=(?:\s*)(?:([a-zA-Z0-9_]+)|(.+))$/g, function(){
  9606. var mm = arguments;
  9607. var str = "d."+mm[1]+"=";
  9608. if(mm[2]){
  9609. str+="d."+mm[2];
  9610. }else {
  9611. str += mm[3].replace( /(=(?:[a-zA-Z_][\w\.]*)+)/g,
  9612. function(m){ return (m.substring(0,1)=='=')?"d."+m.replace('=','') : m; }
  9613. );
  9614. }
  9615. return str;
  9616. }) + ";";
  9617. }
  9618. // js
  9619. if(m[9]) {
  9620. return 's[i++]=' + m[9].replace( /(=(?:[a-zA-Z_][\w\.]*)+)/g,
  9621. function(m){ return (m.substring(0,1)=='=')?"d."+m.replace('=','') : m; }
  9622. )+';';
  9623. }
  9624. // variables
  9625. if(m[8]) return 's[i++]= d.'+m[8]+';';
  9626. // if
  9627. if(m[1]) {
  9628. return 'if('+m[1].replace(reg[0],cb[0]).replace(/d\.(typeof) /,'$1 ').replace(/ d\.(instanceof) d\./,' $1 ')+'){';
  9629. }
  9630. // else if
  9631. if(m[2]) return '}else if('+m[2].replace(reg[0],cb[0]).replace(/d\.(typeof) /,'$1 ').replace(/ d\.(instanceof) d\./,' $1 ')+'){';
  9632. // for loop
  9633. if(m[5]) {
  9634. delete_info = m[4];
  9635. var _aStr = [];
  9636. _aStr.push('var t#=d.'+m[5]+'||{},p#=isArray(t#),i#=0;');
  9637. _aStr.push('for(var x# in t#){');
  9638. _aStr.push('if(!t#.hasOwnProperty(x#)){continue;}');
  9639. _aStr.push(' if( (p# && isNaN(i#=parseInt(x#,10))) || (!p# && !t#.propertyIsEnumerable(x#)) ) continue;');
  9640. _aStr.push(' d.'+m[4]+'=t#[x#];');
  9641. _aStr.push(m[3]?'d.'+m[3]+'=p#?i#:x#;':'');
  9642. return _aStr.join("").replace(reg[4], lev++ );
  9643. }
  9644. // else
  9645. if(m[6]) return '}else{';
  9646. // end if, end for
  9647. if(m[7]) {
  9648. if(m[7]=="for"){
  9649. return "delete d."+delete_info+"; };";
  9650. }else{
  9651. return '};';
  9652. }
  9653. }
  9654. return m[0];
  9655. });
  9656. }else if(tpl[i] == key) {
  9657. tpl[i] = "";
  9658. }else if(tpl[i]){
  9659. tpl[i] = 's[i++]="'+tpl[i].replace(reg[1],cb[1])+'";';
  9660. }
  9661. }
  9662. tpl = jindo.$A(tpl).reverse().$value().join('').replace(new RegExp(leftBrace,'g'),"{").replace(new RegExp(rightBrace,'g'),"}");
  9663. var _aStr = [];
  9664. _aStr.push('var s=[],i=0;');
  9665. _aStr.push('function isArray(o){ return Object.prototype.toString.call(o) == "[object Array]" };');
  9666. _aStr.push(tpl);
  9667. _aStr.push('return s.join("");');
  9668. tpl = eval("false||function(d){"+_aStr.join("")+"}");
  9669. tpl = tpl(data);
  9670. //(new Function("d",_aStr.join("")))(data);
  9671. return tpl;
  9672. };
  9673. /**
  9674. * @fileOverview $Date의 생성자 메서드를 정의한 파일
  9675. * @name date.js
  9676. */
  9677. /**
  9678. * $Date 객체를 생성하고 리턴한다.
  9679. * ISO문자를 넣은 경우 jindo.$Date.utc을 기반하여 계산된다.
  9680. * @extends core
  9681. * @class $Date 클래스는 날짜를 처리하기 위한 Date 타입의 레퍼(Wrapper) 클래스이다.
  9682. * @constructor
  9683. * @author Kim, Taegon
  9684. * @example
  9685. $Date();
  9686. $Date(milliseconds);
  9687. $Date(dateString);
  9688. //1.4.6 이후 부터 달까지만 넣어도 $Date사용 가능하여 빈 값은 1로 셋팅.
  9689. $Date(year, month, [date, [hours, [minitues, [seconds, [milliseconds]]]]]);
  9690. $Date(2010,6);//이러고 하면 $Date(2010,6,1,1,1,1,1); 와 같음.
  9691. */
  9692. jindo.$Date = function(src) {
  9693. var a=arguments,t="";
  9694. var cl=arguments.callee;
  9695. if (src && src instanceof cl) return src;
  9696. if (!(this instanceof cl)) return new cl(a[0],a[1],a[2],a[3],a[4],a[5],a[6]);
  9697. if ((t=typeof src) == "string") {
  9698. /*
  9699. iso string일때
  9700. */
  9701. if (/(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d)))/.test(src)) {
  9702. try{
  9703. this._date = new Date(src);
  9704. if (!this._date.toISOString) {
  9705. this._date = jindo.$Date.makeISO(src);
  9706. }else if(this._date.toISOString() == "Invalid Date"){
  9707. this._date = jindo.$Date.makeISO(src);
  9708. }
  9709. }catch(e){
  9710. this._date = jindo.$Date.makeISO(src);
  9711. }
  9712. }else{
  9713. this._date = cl.parse(src);
  9714. }
  9715. } else if (t == "number") {
  9716. if (typeof a[1] == "undefined") {
  9717. /*
  9718. 하나의 숫지인 경우는 밀리 세켄드로 계산함.
  9719. */
  9720. this._date = new Date(src);
  9721. }else{
  9722. for(var i = 0 ; i < 7 ; i++){
  9723. if(typeof a[i] != "number"){
  9724. a[i] = 1;
  9725. }
  9726. }
  9727. this._date = new Date(a[0],a[1],a[2],a[3],a[4],a[5],a[6]);
  9728. }
  9729. } else if (t == "object" && src.constructor == Date) {
  9730. (this._date = new Date).setTime(src.getTime());
  9731. this._date.setMilliseconds(src.getMilliseconds());
  9732. } else {
  9733. this._date = new Date;
  9734. }
  9735. this._names = {};
  9736. for(var i in jindo.$Date.names){
  9737. if(jindo.$Date.names.hasOwnProperty(i))
  9738. this._names[i] = jindo.$Date.names[i];
  9739. }
  9740. }
  9741. jindo.$Date.makeISO = function(src){
  9742. var match = src.match(/(\d\d\d\d)(?:-?(\d\d)(?:-?(\d\d)(?:[T ](\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|(?:([-+])(\d\d)(?::?(\d\d))?)?)?)?)?)?/);
  9743. var hour = parseInt(match[4]||0,10);
  9744. var min = parseInt(match[5]||0,10);
  9745. if (match[8] == "Z") {
  9746. hour += jindo.$Date.utc;
  9747. }else if(match[9] == "+" || match[9] == "-"){
  9748. hour += (jindo.$Date.utc - parseInt(match[9]+match[10],10));
  9749. min += parseInt(match[9] + match[11],10);
  9750. }
  9751. return new Date(match[1]||0,parseInt(match[2]||0,10)-1,match[3]||0,hour ,min ,match[6]||0,match[7]||0);
  9752. }
  9753. /**
  9754. * names 속성은 $Date에서 사용할 , 요일, 오전/오후의 이름을 문자열로 저장한다. s_ 접두어로 가지는 이름들은 약어(abbreviation)이다.
  9755. */
  9756. jindo.$Date.names = {
  9757. month : ["January","Febrary","March","April","May","June","July","August","September","October","Novermber","December"],
  9758. s_month : ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],
  9759. day : ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],
  9760. s_day : ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],
  9761. ampm : ["AM", "PM"]
  9762. };
  9763. /**
  9764. * UTC는 <a href="http://ko.wikipedia.org/wiki/UTC">협정 세계시간</a> +9.
  9765. * @example
  9766. jindo.$Date.utc = -10; 하면 하와이를 기준으로 계산된다.
  9767. */
  9768. jindo.$Date.utc = 9;
  9769. /**
  9770. * now 메서드는 현재 시간을 밀리초 단위의 정수로 리턴한다.
  9771. * @return {Number} 밀리초 단위의 정수인 현재 시간
  9772. */
  9773. jindo.$Date.now = function() {
  9774. return Date.now();
  9775. };
  9776. /**
  9777. * names속성을 셋팅 혹은 가져 온다.(1.4.1 추가)
  9778. * @param {Object} oNames
  9779. */
  9780. jindo.$Date.prototype.name = function(oNames){
  9781. if(arguments.length){
  9782. for(var i in oNames){
  9783. if(oNames.hasOwnProperty(i))
  9784. this._names[i] = oNames[i];
  9785. }
  9786. }else{
  9787. return this._names;
  9788. }
  9789. }
  9790. /**
  9791. * parse 메서드는 인수로 지정한 문자열을 파싱하여 문자열의 형식에 맞는 Date 객체를 생성한다.
  9792. * @param {String} strDate 날짜, 혹은 시간 형식을 지정한 파싱 대상 문자열
  9793. * @return {Object} Date 객체.
  9794. */
  9795. jindo.$Date.parse = function(strDate) {
  9796. return new Date(Date.parse(strDate));
  9797. };
  9798. /**
  9799. * $value 메서드는 $Date가 감싸고 있던 원본 Date 객체를 반환한다.
  9800. * @returns {Object} Date 객체
  9801. */
  9802. jindo.$Date.prototype.$value = function(){
  9803. return this._date;
  9804. };
  9805. /**
  9806. * format 메서드는 $Date 객체가 저장하고 있는 시간을 인수로 지정한 형식 문자열에 맞추어 변환한다. 형식 문자열은 PHP의 date 함수와 동일하게 사용한다.
  9807. <table>
  9808. <caption>날짜</caption>
  9809. <thead>
  9810. <tr>
  9811. <th scope="col">문자</th>
  9812. <th scope="col">설명</th>
  9813. <th scope="col">기타</th>
  9814. </tr>
  9815. </thead>
  9816. <tbody>
  9817. <tr>
  9818. <td>d</td>
  9819. <td>두자리 날짜</td>
  9820. <td>01 ~ 31</td>
  9821. </tr>
  9822. <tr>
  9823. <td>j</td>
  9824. <td>0 없는 날짜</td>
  9825. <td>1 ~ 31</td>
  9826. </tr>
  9827. <tr>
  9828. <td>l (소문자L)</td>
  9829. <td>주의 전체 날짜</td>
  9830. <td>$Date.names.day에 지정되는 날짜</td>
  9831. </tr>
  9832. <tr>
  9833. <td>D</td>
  9834. <td>요약된 날짜</td>
  9835. <td>$Date.names.s_day에 지정된 날짜</td>
  9836. </tr>
  9837. <tr>
  9838. <td>w</td>
  9839. <td> 주의 몇번째 </td>
  9840. <td>0() ~ 6()</td>
  9841. </tr>
  9842. <tr>
  9843. <td>N</td>
  9844. <td>ISO-8601 주의 몇번째 </td>
  9845. <td>1() ~ 7()</td>
  9846. </tr>
  9847. <tr>
  9848. <td>S</td>
  9849. <td>2글자, 서수형식의 표현(1st, 2nd)</td>
  9850. <td>st, nd, rd, th</td>
  9851. </tr>
  9852. <tr>
  9853. <td>z</td>
  9854. <td>해당 년도의 몇번째 (0부터)</td>
  9855. <td>0 ~ 365</td>
  9856. </tr>
  9857. </tbody>
  9858. </table>
  9859. <table>
  9860. <caption></caption>
  9861. <thead>
  9862. <tr>
  9863. <th scope="col">문자</th>
  9864. <th scope="col">설명</th>
  9865. <th scope="col">기타</th>
  9866. </tr>
  9867. </thead>
  9868. <tbody>
  9869. <tr>
  9870. <td>m</td>
  9871. <td>두자리 고정으로 </td>
  9872. <td>01 ~ 12</td>
  9873. </tr>
  9874. <tr>
  9875. <td>n</td>
  9876. <td>앞에 0제외 </td>
  9877. <td>1 ~ 12</td>
  9878. </tr>
  9879. </tbody>
  9880. </table>
  9881. <table>
  9882. <caption></caption>
  9883. <thead>
  9884. <tr>
  9885. <th scope="col">문자</th>
  9886. <th scope="col">설명</th>
  9887. <th scope="col">기타</th>
  9888. </tr>
  9889. </thead>
  9890. <tbody>
  9891. <tr>
  9892. <td>L</td>
  9893. <td>윤년 여부</td>
  9894. <td>true, false</td>
  9895. </tr>
  9896. <tr>
  9897. <td>o</td>
  9898. <td>4자리 연도</td>
  9899. <td>2010</td>
  9900. </tr>
  9901. <tr>
  9902. <td>Y</td>
  9903. <td>o와 같음.</td>
  9904. <td>2010</td>
  9905. </tr>
  9906. <tr>
  9907. <td>y</td>
  9908. <td>2자리 연도</td>
  9909. <td>10</td>
  9910. </tr>
  9911. </tbody>
  9912. </table>
  9913. <table>
  9914. <caption></caption>
  9915. <thead>
  9916. <tr>
  9917. <th scope="col">문자</th>
  9918. <th scope="col">설명</th>
  9919. <th scope="col">기타</th>
  9920. </tr>
  9921. </thead>
  9922. <tbody>
  9923. <tr>
  9924. <td>a</td>
  9925. <td>소문자 오전, 오후</td>
  9926. <td>am,pm</td>
  9927. </tr>
  9928. <tr>
  9929. <td>A</td>
  9930. <td>대문자 오전,오후</td>
  9931. <td>AM,PM</td>
  9932. </tr>
  9933. <tr>
  9934. <td>g</td>
  9935. <td>(12시간 주기)0없는 두자리 시간.</td>
  9936. <td>1~12</td>
  9937. </tr>
  9938. <tr>
  9939. <td>G</td>
  9940. <td>(24시간 주기)0없는 두자리 시간.</td>
  9941. <td>0~24</td>
  9942. </tr>
  9943. <tr>
  9944. <td>h</td>
  9945. <td>(12시간 주기)0있는 두자리 시간.</td>
  9946. <td>01~12</td>
  9947. </tr>
  9948. <tr>
  9949. <td>H</td>
  9950. <td>(24시간 주기)0있는 두자리 시간.</td>
  9951. <td>00~24</td>
  9952. </tr>
  9953. <tr>
  9954. <td>i</td>
  9955. <td>0포함 2자리 .</td>
  9956. <td>00~59</td>
  9957. </tr>
  9958. <tr>
  9959. <td>s</td>
  9960. <td>0포함 2자리 </td>
  9961. <td>00~59</td>
  9962. </tr>
  9963. <tr>
  9964. <td>u</td>
  9965. <td>microseconds</td>
  9966. <td>654321</td>
  9967. </tr>
  9968. </tbody>
  9969. </table>
  9970. <table>
  9971. <caption>기타</caption>
  9972. <thead>
  9973. <tr>
  9974. <th scope="col">문자</th>
  9975. <th scope="col">설명</th>
  9976. <th scope="col">기타</th>
  9977. </tr>
  9978. </thead>
  9979. <tbody>
  9980. <tr>
  9981. <td>U</td>
  9982. <td>Unix Time(1970 00:00:00 GMT) </td>
  9983. <td></td>
  9984. </tr>
  9985. </tbody>
  9986. </table>
  9987. * @param {Date} strFormat 형식 문자열
  9988. * @returns {String} 시간을 형식 문자열에 맞추어 변환한 문자열.
  9989. * @example
  9990. var oDate = $Date("Jun 17 2009 12:02:54");
  9991. oDate.format("Y.m.d(D) A H:i") => "2009.06.17(Wed) PM 12:02"
  9992. */
  9993. jindo.$Date.prototype.format = function(strFormat){
  9994. var o = {};
  9995. var d = this._date;
  9996. var name = this.name();
  9997. var self = this;
  9998. return (strFormat||"").replace(/[a-z]/ig, function callback(m){
  9999. if (typeof o[m] != "undefined") return o[m];
  10000. switch(m) {
  10001. case"d":
  10002. case"j":
  10003. o.j = d.getDate();
  10004. o.d = (o.j>9?"":"0")+o.j;
  10005. return o[m];
  10006. case"l":
  10007. case"D":
  10008. case"w":
  10009. case"N":
  10010. o.w = d.getDay();
  10011. o.N = o.w?o.w:7;
  10012. o.D = name.s_day[o.w];
  10013. o.l = name.day[o.w];
  10014. return o[m];
  10015. case"S":
  10016. return (!!(o.S=["st","nd","rd"][d.getDate()]))?o.S:(o.S="th");
  10017. case"z":
  10018. o.z = Math.floor((d.getTime() - (new Date(d.getFullYear(),0,1)).getTime())/(3600*24*1000));
  10019. return o.z;
  10020. case"m":
  10021. case"n":
  10022. o.n = d.getMonth()+1;
  10023. o.m = (o.n>9?"":"0")+o.n;
  10024. return o[m];
  10025. case"L":
  10026. o.L = self.isLeapYear();
  10027. return o.L;
  10028. case"o":
  10029. case"Y":
  10030. case"y":
  10031. o.o = o.Y = d.getFullYear();
  10032. o.y = (o.o+"").substr(2);
  10033. return o[m];
  10034. case"a":
  10035. case"A":
  10036. case"g":
  10037. case"G":
  10038. case"h":
  10039. case"H":
  10040. o.G = d.getHours();
  10041. o.g = (o.g=o.G%12)?o.g:12;
  10042. o.A = o.G<12?name.ampm[0]:name.ampm[1];
  10043. o.a = o.A.toLowerCase();
  10044. o.H = (o.G>9?"":"0")+o.G;
  10045. o.h = (o.g>9?"":"0")+o.g;
  10046. return o[m];
  10047. case"i":
  10048. o.i = (((o.i=d.getMinutes())>9)?"":"0")+o.i;
  10049. return o.i;
  10050. case"s":
  10051. o.s = (((o.s=d.getSeconds())>9)?"":"0")+o.s;
  10052. return o.s;
  10053. case"u":
  10054. o.u = d.getMilliseconds();
  10055. return o.u;
  10056. case"U":
  10057. o.U = self.time();
  10058. return o.U;
  10059. default:
  10060. return m;
  10061. }
  10062. });
  10063. };
  10064. /**
  10065. * time 메서드는 GMT 1970/01/01 00:00:00 기준으로 경과한 시간을 설정하거나 가져온다.
  10066. * @param {Number} nTime 밀리 단위의 시간 .
  10067. * @return {$Date | Number} 인수를 지정했다면 GMT 1970/01/01 00:00:00 에서 부터 인수만큼 지난 시간을 설정한 $DAte 객체. 인수를 지정하지 않았다면 GMT 1970/01/01 00:00:00에서 부터 $Date 객체에 지정된 시각까지 경과한 시간(밀리 ).
  10068. */
  10069. jindo.$Date.prototype.time = function(nTime) {
  10070. if (typeof nTime == "number") {
  10071. this._date.setTime(nTime);
  10072. return this;
  10073. }
  10074. return this._date.getTime();
  10075. };
  10076. /**
  10077. * year 메서드는 년도를 설정하거나 가져온다.
  10078. * @param {Number} nYear 설정할 년도값
  10079. * @return {$Date | Number} 인수를 지정하였다면 새로 년도 값을 설정한 $Date 객체. 인수를 지정하지 않았다면 $Date 객체가 지정하고 있는 시각의 년도를 리턴한다.
  10080. */
  10081. jindo.$Date.prototype.year = function(nYear) {
  10082. if (typeof nYear == "number") {
  10083. this._date.setFullYear(nYear);
  10084. return this;
  10085. }
  10086. return this._date.getFullYear();
  10087. };
  10088. /**
  10089. * month 메서드는 달을 설정하거나 가져온다.
  10090. * @param {Number} nMon 설정할 달의
  10091. * @return {$Date | Number} 인수를 지정하였다면 새로 달을 설정한 $Date 객체. 인수를 지정하지 않았다면 $Date 객체가 지정하고 있는 시각의 달을 리턴한다.
  10092. * @remark 리턴 값의 범위는 0(1)에서 11(12)이다.
  10093. */
  10094. jindo.$Date.prototype.month = function(nMon) {
  10095. if (typeof nMon == "number") {
  10096. this._date.setMonth(nMon);
  10097. return this;
  10098. }
  10099. return this._date.getMonth();
  10100. };
  10101. /**
  10102. * date 메서드는 날짜를 설정하거나 가져온다.
  10103. * @param {nDate} nDate 설정할 날짜
  10104. * @return {$Date | Number} 인수를 지정하였다면 새로 날짜를 설정한 $Date 객체. 인수를 지정하지 않았다면 $Date 객체가 지정하고 있는 시각의 날짜를 리턴한다.
  10105. */
  10106. jindo.$Date.prototype.date = function(nDate) {
  10107. if (typeof nDate == "number") {
  10108. this._date.setDate(nDate);
  10109. return this;
  10110. }
  10111. return this._date.getDate();
  10112. };
  10113. /**
  10114. * day 메서드는 요일을 가져온다.
  10115. * @return {Number} 요일 . 0(일요일)에서 6(토요일) 리턴한다.
  10116. */
  10117. jindo.$Date.prototype.day = function() {
  10118. return this._date.getDay();
  10119. };
  10120. /**
  10121. * hours 메서드는 () 설정하거나 가져온다.
  10122. * @param {Number} nHour 설정할
  10123. * @return {$Date | Number} 인수를 지정하였다면 새로 값을 설정한 $Date 객체. 인수를 지정하지 않았다면 $Date 객체가 지정하고 있는 시각의 .
  10124. */
  10125. jindo.$Date.prototype.hours = function(nHour) {
  10126. if (typeof nHour == "number") {
  10127. this._date.setHours(nHour);
  10128. return this;
  10129. }
  10130. return this._date.getHours();
  10131. };
  10132. /**
  10133. * minutes 메서드는 분을 설정하거나 가져온다.
  10134. * @param {Number} nMin 설정할
  10135. * @return {Number} 인수를 지정하였다면 새로 값을 설정한 $Date 객체. 인수를 지정하지 않았다면 $Date 객체가 지정하고 있는 시각의 .
  10136. */
  10137. jindo.$Date.prototype.minutes = function(nMin) {
  10138. if (typeof nMin == "number") {
  10139. this._date.setMinutes(nMin);
  10140. return this;
  10141. }
  10142. return this._date.getMinutes();
  10143. };
  10144. /**
  10145. * seconds 메서드는 초을 설정하거나 가져온다.
  10146. * @param {Number} nSec 설정할
  10147. * @return {Number} 인수를 지정하였다면 새로 값을 설정한 $Date 객체. 인수를 지정하지 않았다면 $Date 객체가 지정하고 있는 시각의 .
  10148. */
  10149. jindo.$Date.prototype.seconds = function(nSec) {
  10150. if (typeof nSec == "number") {
  10151. this._date.setSeconds(nSec);
  10152. return this;
  10153. }
  10154. return this._date.getSeconds();
  10155. };
  10156. /**
  10157. * isLeapYear 메서드는 시각의 윤년 여부를 확인한다.
  10158. * @returns {Boolean} $Date가 가리키고 있는 시각이 윤년이면 True, 그렇지 않다면 False
  10159. */
  10160. jindo.$Date.prototype.isLeapYear = function() {
  10161. var y = this._date.getFullYear();
  10162. return !(y%4)&&!!(y%100)||!(y%400);
  10163. };
  10164. /**
  10165. * @fileOverView $Window의 생성자 메서드를 정의한 파일
  10166. * @name window.js
  10167. */
  10168. /**
  10169. * $Window 객체를 생성하고 생성한 객체를 리턴한다.
  10170. * @class $Window 객체는 브라우저가 제공하는 window 객체를 래핑하고, 이를 다루기 위한 여러가지 메서드를 제공한다.
  10171. * @param {HTMLWidnow} el
  10172. * <br>
  10173. * $Window로 래핑할 window 엘리먼트.
  10174. * @author gony
  10175. */
  10176. jindo.$Window = function(el) {
  10177. var cl = arguments.callee;
  10178. if (el instanceof cl) return el;
  10179. if (!(this instanceof cl)) return new cl(el);
  10180. this._win = el || window;
  10181. }
  10182. /**
  10183. * $value 메서드는 원래의 window 객체를 리턴한다.
  10184. * @return {HTMLWindow} window 엘리먼트
  10185. * @example
  10186. $Window().$value(); // 원래의 window 객체를 리턴한다.
  10187. */
  10188. jindo.$Window.prototype.$value = function() {
  10189. return this._win;
  10190. };
  10191. /**
  10192. * resizeTo 메서드는 창의 크기를 지정한 크기로 변경한다.<br>
  10193. * 크기는 프레임을 포함한 전체의 크기를 나타내므로 실제로 표현하는 컨텐트 사이즈는 브라우저 종류와 설정에 따라 달라질 있다.<br>
  10194. * 브라우저에 따라 보안 문제 때문에, 크기가 화면의 가시 영역을 벗어나서 커지지 못하도록 막는 경우도 있다. 경우에는 지정한 크기보다 작게 창이 커진다.<br>
  10195. * @param {Number} nWidth 창의 너비
  10196. * @param {Number} nHeight 창의 높이
  10197. * @return {$Window} $Window 객체
  10198. * @see $Window#resizeBy
  10199. * @example
  10200. * // 현재 창의 너비를 400, 높이를 300으로 변경한다.
  10201. * $Window.resizeTo(400, 300);
  10202. */
  10203. jindo.$Window.prototype.resizeTo = function(nWidth, nHeight) {
  10204. this._win.resizeTo(nWidth, nHeight);
  10205. return this;
  10206. };
  10207. /**
  10208. * resizeBy 메서드는 창의 크기를 지정한 크기만큼 변경한다.
  10209. * @param {Number} nWidth 늘어날 창의 너비
  10210. * @param {Number} nHeight 늘어날 창의 높이
  10211. * @see $Window#resizeTo
  10212. * @example
  10213. * // 현재 창의 너비를 100, 높이를 50 만큼 늘린다.
  10214. * $Window().resize(100, 50);
  10215. */
  10216. jindo.$Window.prototype.resizeBy = function(nWidth, nHeight) {
  10217. this._win.resizeBy(nWidth, nHeight);
  10218. return this;
  10219. };
  10220. /**
  10221. * moveTo 메서드는 창을 지정한 위치로 이동시킨다. 좌표는 프레임을 포함한 창의 좌측 상단을 기준으로 한다.
  10222. * @param {Number} nLeft 이동할 x좌표 (pixel 단위)
  10223. * @param {Number} nTop 이동할 y좌표 (pixel 단위)
  10224. * @see $Window#moveBy
  10225. * @example
  10226. * // 현재 창을 (15, 10) 으로 이동시킨다.
  10227. * $Window().moveTo(15, 10);
  10228. */
  10229. jindo.$Window.prototype.moveTo = function(nLeft, nTop) {
  10230. this._win.moveTo(nLeft, nTop);
  10231. return this;
  10232. };
  10233. /**
  10234. * moveBy 메서드는 창을 지정한 위치만큼 이동시킨다.
  10235. * @param {Number} nLeft x좌표로 이동할 만큼의 (pixel 단위)
  10236. * @param {Number} nTop y좌표로 이동할 만큼의 (pixel 단위)
  10237. * @see $Window#moveTo
  10238. * @example
  10239. * // 현재 창을 좌측으로 15px만큼, 아래로 10px만큼 이동시킨다.
  10240. * $Window().moveBy(15, 10);
  10241. */
  10242. jindo.$Window.prototype.moveBy = function(nLeft, nTop) {
  10243. this._win.moveBy(nLeft, nTop);
  10244. return this;
  10245. };
  10246. /**
  10247. * sizeToContent 메서드는 내부 문서의 컨텐츠 크기에 맞추어 창의 크기를 변경하며, 가지 제약 사항을 가진다. <br>
  10248. * 제약사항에 걸리는 경우 매개변수로 창의 사이즈를 지정할 있다.
  10249. <ul>
  10250. <li>메서드의 내부 문서가 완전히 로딩된 다음에 실행되어야 한다. </li>
  10251. <li>창이 내부 문서보다 경우에는 내부 문서를 구할 없으므로, 반드시 크기를 내부 문서보다 작게 만든다.</li>
  10252. <li>반드시 body에 사이즈가 있어야 한다.</li>
  10253. <li>html의 DOCTYPE이 Quirks일때 맥에서는 opera(10), 윈도우에서는 IE6+, opera(10), safari(4)에서 정상적으로 동작하지 않는다.</li>
  10254. <li>가능 하면 부모창에서 실행 시켜야 한다. 자식창이 모니터 화면을 벗어나 가려져 있을 경우, IE는 가려진 영역은 컨텐츠가 없는 것으로 판단하여 가려진 영역 만큼 줄인다.</li>
  10255. </ul>
  10256. * @param {Number} nWidth 창의 너비
  10257. * @param {Number} nHeight 창의 높이
  10258. * @example
  10259. * // 새 창을 띄우고 자동으로 창 크기를 컨텐트에 맞게 변경하는 함수
  10260. * function winopen(url) {
  10261. * try {
  10262. * win = window.open(url, "", "toolbar=0,location=0,status=0,menubar=0,scrollbars=0,resizable=0,width=250,height=300");
  10263. * win.moveTo(200, 100);
  10264. * win.focus();
  10265. * } catch(e){}
  10266. *
  10267. * setTimeout(function() {
  10268. * $Window(win).sizeToContent();
  10269. * }, 1000);
  10270. * }
  10271. *
  10272. * winopen('/samples/popup.html');
  10273. */
  10274. jindo.$Window.prototype.sizeToContent = function(nWidth, nHeight) {
  10275. if (typeof this._win.sizeToContent == "function") {
  10276. this._win.sizeToContent();
  10277. } else {
  10278. if(arguments.length != 2){
  10279. // use trick by Peter-Paul Koch
  10280. // http://www.quirksmode.org/
  10281. var innerX,innerY;
  10282. var self = this._win;
  10283. var doc = this._win.document;
  10284. if (self.innerHeight) {
  10285. // all except Explorer
  10286. innerX = self.innerWidth;
  10287. innerY = self.innerHeight;
  10288. } else if (doc.documentElement && doc.documentElement.clientHeight) {
  10289. // Explorer 6 Strict Mode
  10290. innerX = doc.documentElement.clientWidth;
  10291. innerY = doc.documentElement.clientHeight;
  10292. } else if (doc.body) {
  10293. // other Explorers
  10294. innerX = doc.body.clientWidth;
  10295. innerY = doc.body.clientHeight;
  10296. }
  10297. var pageX,pageY;
  10298. var test1 = doc.body.scrollHeight;
  10299. var test2 = doc.body.offsetHeight;
  10300. if (test1 > test2) {
  10301. // all but Explorer Mac
  10302. pageX = doc.body.scrollWidth;
  10303. pageY = doc.body.scrollHeight;
  10304. } else {
  10305. // Explorer Mac;
  10306. //would also work in Explorer 6 Strict, Mozilla and Safari
  10307. pageX = doc.body.offsetWidth;
  10308. pageY = doc.body.offsetHeight;
  10309. }
  10310. nWidth = pageX - innerX;
  10311. nHeight = pageY - innerY;
  10312. }
  10313. this.resizeBy(nWidth, nHeight);
  10314. }
  10315. return this;
  10316. };
  10317. /**
  10318. * @fileOverview 다른 프레임웍 없이 jindo만 사용할 경우 편의성을 위해 jindo 객체를 window에 붙임
  10319. */
  10320. // copy jindo objects to window
  10321. if (typeof window != "undefined") {
  10322. for (prop in jindo) {
  10323. if (jindo.hasOwnProperty(prop)) {
  10324. window[prop] = jindo[prop];
  10325. }
  10326. }
  10327. }