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.

3847 lines
136 KiB

  1. 'use strict';
  2. var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
  3. (function () {
  4. 'use strict';
  5. // root of function
  6. var root = this,
  7. win = this,
  8. doc = win ? win.document : null,
  9. docElem = win ? win.document.documentElement : null,
  10. reIsJson = /^(["'](\\.|[^"\\\n\r])*?["']|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/,
  11. reMs = /^-ms-/,
  12. reSnakeCase = /[\-_]([\da-z])/gi,
  13. reCamelCase = /([A-Z])/g,
  14. reDot = /\./,
  15. reInt = /[-|+]?[\D]/gi,
  16. reNotNum = /\D/gi,
  17. reMoneySplit = new RegExp('([0-9])([0-9][0-9][0-9][,.])'),
  18. reAmp = /&/g,
  19. reEq = /=/,
  20. reClassNameSplit = /[ ]+/g,
  21. /** @namespace {Object} ax5 */
  22. ax5 = {},
  23. info = void 0,
  24. U = void 0,
  25. dom = void 0;
  26. /**
  27. * guid
  28. * @member {Number} ax5.guid
  29. */
  30. ax5.guid = 1;
  31. /**
  32. * ax5.guid를 구하고 증가시킵니다.
  33. * @method ax5.getGuid
  34. * @returns {Number} guid
  35. */
  36. ax5.getGuid = function () {
  37. return ax5.guid++;
  38. };
  39. /**
  40. * 상수모음
  41. * @namespace ax5.info
  42. */
  43. ax5.info = info = function () {
  44. var _arguments = arguments;
  45. /**
  46. * ax5 version
  47. * @member {String} ax5.info.version
  48. */
  49. var version = "1.4.126";
  50. /**
  51. * ax5 library path
  52. * @member {String} ax5.info.baseUrl
  53. */
  54. var baseUrl = "";
  55. /**
  56. * ax5 에러 출력메세지 사용자 정의
  57. * @member {Object} ax5.info.onerror
  58. * @examples
  59. * ```
  60. * ax5.info.onerror = function(){
  61. * console.log(arguments);
  62. * }
  63. * ```
  64. */
  65. var onerror = function onerror() {
  66. console.error(U.toArray(_arguments).join(":"));
  67. };
  68. /**
  69. * event keyCodes
  70. * @member {Object} ax5.info.eventKeys
  71. * @example
  72. * ```
  73. * {
  74. * BACKSPACE: 8, TAB: 9,
  75. * RETURN: 13, ESC: 27, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, DELETE: 46,
  76. * HOME: 36, END: 35, PAGEUP: 33, PAGEDOWN: 34, INSERT: 45, SPACE: 32
  77. * }
  78. * ```
  79. */
  80. var eventKeys = {
  81. BACKSPACE: 8, TAB: 9,
  82. RETURN: 13, ESC: 27, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, DELETE: 46,
  83. HOME: 36, END: 35, PAGEUP: 33, PAGEDOWN: 34, INSERT: 45, SPACE: 32
  84. };
  85. /**
  86. * week names
  87. * @member {Object[]} weekNames
  88. * @member {string} weekNames[].label
  89. *
  90. * @example
  91. * ```
  92. * [
  93. * {label: "SUN"},{label: "MON"},{label: "TUE"},{label: "WED"},{label: "THU"},{label: "FRI"},{label: "SAT"}
  94. * ]
  95. * console.log( weekNames[0] );
  96. * console.log( ax5.info.weekNames[(new Date()).getDay()].label )
  97. * ```
  98. */
  99. var weekNames = [{ label: "SUN" }, { label: "MON" }, { label: "TUE" }, { label: "WED" }, { label: "THU" }, { label: "FRI" }, { label: "SAT" }];
  100. /**
  101. * 사용자 브라우저 식별용 오브젝트
  102. * @member {Object} ax5.info.browser
  103. * @example
  104. * ```
  105. * console.log( ax5.info.browser );
  106. * //Object {name: "chrome", version: "39.0.2171.71", mobile: false}
  107. * ```
  108. */
  109. var browser = function (ua, mobile, browserName, match, browser, browserVersion) {
  110. if (!win || !win.navigator) return {};
  111. ua = navigator.userAgent.toLowerCase(), mobile = ua.search(/mobile/g) != -1, browserName, match, browser, browserVersion;
  112. if (ua.search(/iphone/g) != -1) {
  113. return { name: "iphone", version: 0, mobile: true };
  114. } else if (ua.search(/ipad/g) != -1) {
  115. return { name: "ipad", version: 0, mobile: true };
  116. } else if (ua.search(/android/g) != -1) {
  117. match = /(android)[ \/]([\w.]+)/.exec(ua) || [];
  118. browserVersion = match[2] || "0";
  119. return { name: "android", version: browserVersion, mobile: mobile };
  120. } else {
  121. browserName = "";
  122. match = /(opr)[ \/]([\w.]+)/.exec(ua) || /(chrome)[ \/]([\w.]+)/.exec(ua) || /(webkit)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || [];
  123. browser = match[1] || "";
  124. browserVersion = match[2] || "0";
  125. if (browser == "msie") browser = "ie";
  126. return {
  127. name: browser,
  128. version: browserVersion,
  129. mobile: mobile
  130. };
  131. }
  132. ua = null, mobile = null, browserName = null, match = null, browser = null, browserVersion = null;
  133. }();
  134. /**
  135. * 브라우저 여부
  136. * @member {Boolean} ax5.info.isBrowser
  137. */
  138. var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && win.document);
  139. /**
  140. * 브라우저에 따른 마우스 이벤트이름
  141. * @member {Object} ax5.info.wheelEnm
  142. */
  143. var wheelEnm = win && /Firefox/i.test(navigator.userAgent) ? "DOMMouseScroll" : "mousewheel";
  144. /**
  145. * 첫번째 자리수 동사 - (필요한것이 없을때 : 4, 실행오류 : 5)
  146. * 두번째 자리수 목적어 - 문자열 0, 숫자 1, 배열 2, 오브젝트 3, 함수 4, DOM 5, 파일 6, 기타 7
  147. * 세번째 자리수 옵션
  148. * @member {Object} ax5.info.errorMsg
  149. */
  150. var errorMsg = {};
  151. /**
  152. * 현재 페이지의 Url 정보를 리턴합니다.
  153. * @method ax5.info.urlUtil
  154. * @returns {Object}
  155. * @example
  156. * ```
  157. * console.log( ax5.util.toJson( ax5.info.urlUtil() ) );
  158. * {
  159. * "baseUrl": "http://ax5:2018",
  160. * "href": "http://ax5:2018/samples/index.html?a=1&b=1#abc",
  161. * "param": "a=1&b=1",
  162. * "referrer": "",
  163. * "pathname": "/samples/index.html",
  164. * "hostname": "ax5",
  165. * "port": "2018",
  166. * "url": "http://ax5:2018/samples/index.html",
  167. * "hashdata": "abc"
  168. * }
  169. * ```
  170. */
  171. function urlUtil(url, urls) {
  172. url = {
  173. href: win.location.href,
  174. param: win.location.search,
  175. referrer: doc.referrer,
  176. pathname: win.location.pathname,
  177. hostname: win.location.hostname,
  178. port: win.location.port
  179. }, urls = url.href.split(/[\?#]/);
  180. url.param = url.param.replace("?", "");
  181. url.url = urls[0];
  182. if (url.href.search("#") > -1) {
  183. url.hashdata = U.last(urls);
  184. }
  185. urls = null;
  186. url.baseUrl = U.left(url.href, "?").replace(url.pathname, "");
  187. return url;
  188. }
  189. /**
  190. * ax5-error-msg.js 정의된 ax5 error를 반환합니다.
  191. * @method ax5.info.getError
  192. * @returns {Object}
  193. * @example
  194. * ```
  195. * console.log( ax5.info.getError("single-uploader", "460", "upload") );
  196. *
  197. * if(!this.selectedFile){
  198. * if (cfg.onEvent) {
  199. * var that = {
  200. * action: "error",
  201. * error: ax5.info.getError("single-uploader", "460", "upload")
  202. * };
  203. * cfg.onEvent.call(that, that);
  204. * }
  205. * return this;
  206. * }
  207. * ```
  208. */
  209. function getError(className, errorCode, methodName) {
  210. if (info.errorMsg && info.errorMsg[className]) {
  211. return {
  212. className: className,
  213. errorCode: errorCode,
  214. methodName: methodName,
  215. msg: info.errorMsg[className][errorCode]
  216. };
  217. } else {
  218. return { className: className, errorCode: errorCode, methodName: methodName };
  219. }
  220. }
  221. /**
  222. * 브라우져의 터치 기능 유무를 확인합니다.
  223. * @method ax5.info.supportTouch
  224. * @returns {boolean}
  225. * @example
  226. * ```
  227. * var chkFlag = ax5.info.supportTouch;
  228. */
  229. var supportTouch = win ? 'ontouchstart' in win || navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0 : false;
  230. var supportFileApi = win ? win.FileReader && win.File && win.FileList && win.Blob : false;
  231. return {
  232. errorMsg: errorMsg,
  233. version: version,
  234. baseUrl: baseUrl,
  235. onerror: onerror,
  236. eventKeys: eventKeys,
  237. weekNames: weekNames,
  238. browser: browser,
  239. isBrowser: isBrowser,
  240. supportTouch: supportTouch,
  241. supportFileApi: supportFileApi,
  242. wheelEnm: wheelEnm,
  243. urlUtil: urlUtil,
  244. getError: getError
  245. };
  246. }();
  247. /**
  248. * Refer to this by {@link ax5}.
  249. * @namespace ax5.util
  250. */
  251. ax5['util'] = U = function () {
  252. var _toString = Object.prototype.toString;
  253. /**
  254. * Object나 Array의 아이템으로 사용자 함수를 호출합니다.
  255. * @method ax5.util.each
  256. * @param {Object|Array} O
  257. * @param {Function} _fn
  258. * @example
  259. * ```js
  260. * var axf = ax5.util;
  261. * axf.each([0,1,2], function(){
  262. * // with this
  263. * });
  264. * axf.each({a:1, b:2}, function(){
  265. * // with this
  266. * });
  267. * ```
  268. */
  269. function each(O, _fn) {
  270. if (isNothing(O)) return [];
  271. var key = void 0,
  272. i = 0,
  273. l = O.length,
  274. isObj = l === undefined || typeof O === "function";
  275. if (isObj) {
  276. for (key in O) {
  277. if (typeof O[key] != "undefined") if (_fn.call(O[key], key, O[key]) === false) break;
  278. }
  279. } else {
  280. for (; i < l;) {
  281. if (typeof O[i] != "undefined") if (_fn.call(O[i], i, O[i++]) === false) break;
  282. }
  283. }
  284. return O;
  285. }
  286. // In addition to using the http://underscorejs.org : map, reduce, reduceRight, find
  287. /**
  288. * 원본 아이템들을 이용하여 사용자 함수의 리턴값으로 이루어진 새로운 배열을 만듭니다.
  289. * @method ax5.util.map
  290. * @param {Object|Array} O
  291. * @param {Function} _fn
  292. * @returns {Array}
  293. * @example
  294. * ```js
  295. * var myArray = [0,1,2,3,4];
  296. * var myObject = {a:1, b:"2", c:{axj:"what", arrs:[0,2,"3"]},
  297. * fn: function(abcdd){
  298. * return abcdd;
  299. * }
  300. * };
  301. *
  302. * var _arr = ax5.util.map( myArray, function(index, I){
  303. * return index+1;
  304. * });
  305. * console.log(_arr);
  306. * // [1, 2, 3, 4, 5]
  307. *
  308. * var _arr = ax5.util.map( myObject, function(k, v){
  309. * return v * 2;
  310. * });
  311. * console.log(_arr);
  312. * // [2, 4, NaN, NaN]
  313. * ```
  314. */
  315. function map(O, _fn) {
  316. if (isNothing(O)) return [];
  317. var key = void 0,
  318. i = 0,
  319. l = O.length,
  320. results = [],
  321. fnResult = void 0;
  322. if (isObject(O)) {
  323. for (key in O) {
  324. if (typeof O[key] != "undefined") {
  325. fnResult = undefined;
  326. if ((fnResult = _fn.call(O[key], key, O[key])) === false) break;else results.push(fnResult);
  327. }
  328. }
  329. } else {
  330. for (; i < l;) {
  331. if (typeof O[i] != "undefined") {
  332. fnResult = undefined;
  333. if ((fnResult = _fn.call(O[i], i, O[i++])) === false) break;else results.push(fnResult);
  334. }
  335. }
  336. }
  337. return results;
  338. }
  339. /**
  340. * 원본 아이템들을 이용하여 사용자 함수의 리턴값이 참인 아이템의 위치나 키값을 반환합니다.
  341. * @method ax5.util.search
  342. * @param {Object|Array} O
  343. * @param {Function|String|Number} _fn - 함수 또는
  344. * @returns {Number|String}
  345. * @example
  346. * ```js
  347. * var myArray = [0,1,2,3,4,5,6];
  348. * var myObject = {a:"123","b":"123",c:123};
  349. *
  350. * ax5.util.search(myArray, function(){
  351. * return this > 3;
  352. * });
  353. * // 4
  354. * ax5.util.search(myObject, function(k, v){
  355. * return v === 123;
  356. * });
  357. * // "c"
  358. * ax5.util.search([1,2,3,4], 3);
  359. * // 2
  360. * ax5.util.search([1,2], 4);
  361. * // -1
  362. * ax5.util.search(["name","value"], "value");
  363. * // 1
  364. * ax5.util.search(["name","value"], "values");
  365. * // -1
  366. * ax5.util.search({k1:"name",k2:"value"}, "value2");
  367. * // -1
  368. * ax5.util.search({k1:"name",k2:"value"}, "value");
  369. * // "k2"
  370. * ```
  371. */
  372. function search(O, _fn) {
  373. if (isNothing(O)) return -1;
  374. if (isObject(O)) {
  375. for (var key in O) {
  376. if (typeof O[key] != "undefined" && isFunction(_fn) && _fn.call(O[key], key, O[key])) {
  377. return key;
  378. break;
  379. } else if (O[key] == _fn) {
  380. return key;
  381. break;
  382. }
  383. }
  384. } else {
  385. for (var i = 0, l = O.length; i < l; i++) {
  386. if (typeof O[i] != "undefined" && isFunction(_fn) && _fn.call(O[i], i, O[i])) {
  387. return i;
  388. break;
  389. } else if (O[i] == _fn) {
  390. return i;
  391. break;
  392. }
  393. }
  394. }
  395. return -1;
  396. }
  397. /**
  398. * @method ax5.util.sum
  399. * @param {Array|Object} O
  400. * @param {Number} [defaultValue]
  401. * @param {Function} _fn
  402. * @returns {Number}
  403. * @example
  404. * ```js
  405. * var arr = [
  406. * {name: "122", value: 9},
  407. * {name: "122", value: 10},
  408. * {name: "123", value: 11}
  409. * ];
  410. *
  411. * var rs = ax5.util.sum(arr, function () {
  412. * if(this.name == "122") {
  413. * return this.value;
  414. * }
  415. * });
  416. * console.log(rs); // 19
  417. *
  418. * console.log(ax5.util.sum(arr, 10, function () {
  419. * return this.value;
  420. * }));
  421. * // 40
  422. * ```
  423. */
  424. function sum(O, defaultValue, _fn) {
  425. var i = void 0,
  426. l = void 0,
  427. tokenValue = void 0;
  428. if (isFunction(defaultValue) && typeof _fn === "undefined") {
  429. _fn = defaultValue;
  430. defaultValue = 0;
  431. }
  432. if (typeof defaultValue === "undefined") defaultValue = 0;
  433. if (isArray(O)) {
  434. i = 0;
  435. l = O.length;
  436. for (; i < l; i++) {
  437. if (typeof O[i] !== "undefined") {
  438. if ((tokenValue = _fn.call(O[i], O[i])) === false) break;else if (typeof tokenValue !== "undefined") defaultValue += tokenValue;
  439. }
  440. }
  441. return defaultValue;
  442. } else if (isObject(O)) {
  443. for (i in O) {
  444. if (typeof O[i] != "undefined") {
  445. if ((tokenValue = _fn.call(O[i], O[i])) === false) break;else if (typeof tokenValue !== "undefined") defaultValue += tokenValue;
  446. }
  447. }
  448. return defaultValue;
  449. } else {
  450. console.error("argument error : ax5.util.sum - use Array or Object");
  451. return defaultValue;
  452. }
  453. }
  454. /**
  455. * @method ax5.util.avg
  456. * @param {Array|Object} O
  457. * @param {Number} [defaultValue]
  458. * @param {Function} _fn
  459. * @returns {Number}
  460. * @example
  461. * ```js
  462. * var arr = [
  463. * {name: "122", value: 9},
  464. * {name: "122", value: 10},
  465. * {name: "123", value: 11}
  466. * ];
  467. *
  468. * var rs = ax5.util.avg(arr, function () {
  469. * return this.value;
  470. * });
  471. *
  472. * console.log(rs); // 10
  473. * ```
  474. */
  475. function avg(O, defaultValue, _fn) {
  476. var i = void 0,
  477. l = void 0,
  478. tokenValue = void 0;
  479. if (isFunction(defaultValue) && typeof _fn === "undefined") {
  480. _fn = defaultValue;
  481. defaultValue = 0;
  482. }
  483. if (typeof defaultValue === "undefined") defaultValue = 0;
  484. if (isArray(O)) {
  485. i = 0;
  486. l = O.length;
  487. for (; i < l; i++) {
  488. if (typeof O[i] !== "undefined") {
  489. if ((tokenValue = _fn.call(O[i], O[i])) === false) break;else if (typeof tokenValue !== "undefined") defaultValue += tokenValue;
  490. }
  491. }
  492. return defaultValue / l;
  493. } else if (isObject(O)) {
  494. l = 0;
  495. for (i in O) {
  496. if (typeof O[i] != "undefined") {
  497. if ((tokenValue = _fn.call(O[i], O[i])) === false) break;else if (typeof tokenValue !== "undefined") defaultValue += tokenValue;++l;
  498. }
  499. }
  500. return defaultValue / l;
  501. } else {
  502. console.error("argument error : ax5.util.sum - use Array or Object");
  503. return defaultValue;
  504. }
  505. }
  506. /**
  507. * 배열의 왼쪽에서 오른쪽으로 연산을 진행하는데 수행한 결과가 왼쪽 값으로 반영되어 최종 왼쪽 값을 반환합니다.
  508. * @method ax5.util.reduce
  509. * @param {Array|Object} O
  510. * @param {Function} _fn
  511. * @returns {Alltypes}
  512. * @example
  513. * ```js
  514. * var aarray = [5,4,3,2,1];
  515. * result = ax5.util.reduce( aarray, function(p, n){
  516. * return p * n;
  517. * });
  518. * console.log(result, aarray);
  519. * // 120 [5, 4, 3, 2, 1]
  520. *
  521. * ax5.util.reduce({a:1, b:2}, function(p, n){
  522. * return parseInt(p|0) + parseInt(n);
  523. * });
  524. * // 3
  525. * ```
  526. */
  527. function reduce(O, _fn) {
  528. var i, l, tokenItem;
  529. if (isArray(O)) {
  530. i = 0, l = O.length, tokenItem = O[i];
  531. for (; i < l - 1;) {
  532. if (typeof O[i] != "undefined") {
  533. if ((tokenItem = _fn.call(root, tokenItem, O[++i])) === false) break;
  534. }
  535. }
  536. return tokenItem;
  537. } else if (isObject(O)) {
  538. for (i in O) {
  539. if (typeof O[i] != "undefined") {
  540. if ((tokenItem = _fn.call(root, tokenItem, O[i])) === false) break;
  541. }
  542. }
  543. return tokenItem;
  544. } else {
  545. console.error("argument error : ax5.util.reduce - use Array or Object");
  546. return null;
  547. }
  548. }
  549. /**
  550. * 배열의 오른쪽에서 왼쪽으로 연산을 진행하는데 수행한 결과가 오른쪽 값으로 반영되어 최종 오른쪽 값을 반환합니다.
  551. * @method ax5.util.reduceRight
  552. * @param {Array} O
  553. * @param {Function} _fn
  554. * @returns {Alltypes}
  555. * @example
  556. * ```js
  557. * var aarray = [5,4,3,2,1];
  558. * result = ax5.util.reduceRight( aarray, function(p, n){
  559. * console.log( n );
  560. * return p * n;
  561. * });
  562. * console.log(result, aarray);
  563. * 120 [5, 4, 3, 2, 1]
  564. * ```
  565. */
  566. function reduceRight(O, _fn) {
  567. var i = O.length - 1,
  568. tokenItem = O[i];
  569. for (; i > 0;) {
  570. if (typeof O[i] != "undefined") {
  571. if ((tokenItem = _fn.call(root, tokenItem, O[--i])) === false) break;
  572. }
  573. }
  574. return tokenItem;
  575. }
  576. /**
  577. * 배열또는 오브젝트의 아이템을 인자로 하는 사용자 함수의 결과가 참인 아이템들의 배열을 반환합니다.
  578. * @method ax5.util.filter
  579. * @param {Object|Array} O
  580. * @param {Function} _fn
  581. * @returns {Array}
  582. * @example
  583. * ```js
  584. * var aarray = [5,4,3,2,1];
  585. * result = ax5.util.filter( aarray, function(){
  586. * return this % 2;
  587. * });
  588. * console.log(result);
  589. * // [5, 3, 1]
  590. *
  591. * var filObject = {a:1, s:"string", oa:{pickup:true, name:"AXISJ"}, os:{pickup:true, name:"AX5"}};
  592. * result = ax5.util.filter( filObject, function(){
  593. * return this.pickup;
  594. * });
  595. * console.log( ax5.util.toJson(result) );
  596. * // [{"pickup": , "name": "AXISJ"}, {"pickup": , "name": "AX5"}]
  597. * ```
  598. */
  599. function filter(O, _fn) {
  600. if (isNothing(O)) return [];
  601. var k,
  602. i = 0,
  603. l = O.length,
  604. results = [],
  605. fnResult;
  606. if (isObject(O)) {
  607. for (k in O) {
  608. if (typeof O[k] != "undefined") {
  609. if (fnResult = _fn.call(O[k], k, O[k])) results.push(O[k]);
  610. }
  611. }
  612. } else {
  613. for (; i < l;) {
  614. if (typeof O[i] != "undefined") {
  615. if (fnResult = _fn.call(O[i], i, O[i])) results.push(O[i]);
  616. i++;
  617. }
  618. }
  619. }
  620. return results;
  621. }
  622. /**
  623. * Object를 JSONString 으로 반환합니다.
  624. * @method ax5.util.toJson
  625. * @param {Object|Array} O
  626. * @returns {String} JSON
  627. * @example
  628. * ```js
  629. * var ax = ax5.util;
  630. * var myObject = {
  631. * a:1, b:"2", c:{axj:"what", arrs:[0,2,"3"]},
  632. * fn: function(abcdd){
  633. * return abcdd;
  634. * }
  635. * };
  636. * console.log( ax.toJson(myObject) );
  637. * ```
  638. */
  639. function toJson(O) {
  640. var jsonString = "";
  641. if (ax5.util.isArray(O)) {
  642. var i = 0,
  643. l = O.length;
  644. jsonString += "[";
  645. for (; i < l; i++) {
  646. if (i > 0) jsonString += ",";
  647. jsonString += toJson(O[i]);
  648. }
  649. jsonString += "]";
  650. } else if (ax5.util.isObject(O)) {
  651. jsonString += "{";
  652. var jsonObjectBody = [];
  653. each(O, function (key, value) {
  654. jsonObjectBody.push('"' + key + '": ' + toJson(value));
  655. });
  656. jsonString += jsonObjectBody.join(", ");
  657. jsonString += "}";
  658. } else if (ax5.util.isString(O)) {
  659. jsonString = '"' + O + '"';
  660. } else if (ax5.util.isNumber(O)) {
  661. jsonString = O;
  662. } else if (ax5.util.isUndefined(O)) {
  663. jsonString = "undefined";
  664. } else if (ax5.util.isFunction(O)) {
  665. jsonString = '"{Function}"';
  666. } else {
  667. jsonString = O;
  668. }
  669. return jsonString;
  670. }
  671. /**
  672. * 관용의 JSON Parser
  673. * @method ax5.util.parseJson
  674. * @param {String} JSONString
  675. * @param {Boolean} [force] - 강제 적용 여부 (json 문자열 검사를 무시하고 오브젝트 변환을 시도합니다.)
  676. * @returns {Object}
  677. * @example
  678. * ```
  679. * console.log(ax5.util.parseJson('{"a":1}'));
  680. * // Object {a: 1}
  681. * console.log(ax5.util.parseJson("{'a':1, 'b':'b'}"));
  682. * // Object {a: 1, b: "b"}
  683. * console.log(ax5.util.parseJson("{'a':1, 'b':function(){return 1;}}", true));
  684. * // Object {a: 1, b: function}
  685. * console.log(ax5.util.parseJson("{a:1}"));
  686. * // Object {a: 1}
  687. * console.log(ax5.util.parseJson("[1,2,3]"));
  688. * // [1, 2, 3]
  689. * console.log(ax5.util.parseJson("['1','2','3']"));
  690. * // ["1", "2", "3"]
  691. * console.log(ax5.util.parseJson("[{'a':'99'},'2','3']"));
  692. * // [Object, "2", "3"]
  693. * ```
  694. */
  695. function parseJson(str, force) {
  696. if (force || reIsJson.test(str)) {
  697. try {
  698. return new Function('', 'return ' + str)();
  699. } catch (e) {
  700. return { error: 500, msg: 'syntax error' };
  701. }
  702. } else {
  703. return { error: 500, msg: 'syntax error' };
  704. }
  705. }
  706. /**
  707. * 인자의 타입을 반환합니다.
  708. * @method ax5.util.getType
  709. * @param {Object|Array|String|Number|Element|Etc} O
  710. * @returns {String} window|element|object|array|function|string|number|undefined|nodelist
  711. * @example
  712. * ```js
  713. * var axf = ax5.util;
  714. * var a = 11;
  715. * var b = "11";
  716. * console.log( axf.getType(a) );
  717. * console.log( axf.getType(b) );
  718. * ```
  719. */
  720. function getType(O) {
  721. var typeName;
  722. if (O != null && O == O.window) {
  723. typeName = "window";
  724. } else if (!!(O && O.nodeType == 1)) {
  725. typeName = "element";
  726. } else if (!!(O && O.nodeType == 11)) {
  727. typeName = "fragment";
  728. } else if (O === null) {
  729. typeName = "null";
  730. } else if (typeof O === "undefined") {
  731. typeName = "undefined";
  732. } else if (_toString.call(O) == "[object Object]") {
  733. typeName = "object";
  734. } else if (_toString.call(O) == "[object Array]") {
  735. typeName = "array";
  736. } else if (_toString.call(O) == "[object String]") {
  737. typeName = "string";
  738. } else if (_toString.call(O) == "[object Number]") {
  739. typeName = "number";
  740. } else if (_toString.call(O) == "[object NodeList]") {
  741. typeName = "nodelist";
  742. } else if (typeof O === "function") {
  743. typeName = "function";
  744. }
  745. return typeName;
  746. }
  747. /**
  748. * 오브젝트가 window 인지 판단합니다.
  749. * @method ax5.util.isWindow
  750. * @param {Object} O
  751. * @returns {Boolean}
  752. */
  753. function isWindow(O) {
  754. return O != null && O == O.window;
  755. }
  756. /**
  757. * 오브젝트가 HTML 엘리먼트여부인지 판단합니다.
  758. * @method ax5.util.isElement
  759. * @param {Object} O
  760. * @returns {Boolean}
  761. */
  762. function isElement(O) {
  763. return !!(O && (O.nodeType == 1 || O.nodeType == 11));
  764. }
  765. /**
  766. * 오브젝트가 Object인지 판단합니다.
  767. * @method ax5.util.isObject
  768. * @param {Object} O
  769. * @returns {Boolean}
  770. */
  771. function isObject(O) {
  772. return _toString.call(O) == "[object Object]";
  773. }
  774. /**
  775. * 오브젝트가 Array인지 판단합니다.
  776. * @method ax5.util.isArray
  777. * @param {Object} O
  778. * @returns {Boolean}
  779. */
  780. function isArray(O) {
  781. return _toString.call(O) == "[object Array]";
  782. }
  783. /**
  784. * 오브젝트가 Function인지 판단합니다.
  785. * @method ax5.util.isFunction
  786. * @param {Object} O
  787. * @returns {Boolean}
  788. */
  789. function isFunction(O) {
  790. return typeof O === "function";
  791. }
  792. /**
  793. * 오브젝트가 String인지 판단합니다.
  794. * @method ax5.util.isString
  795. * @param {Object} O
  796. * @returns {Boolean}
  797. */
  798. function isString(O) {
  799. return _toString.call(O) == "[object String]";
  800. }
  801. /**
  802. * 오브젝트가 Number인지 판단합니다.
  803. * @method ax5.util.isNumber
  804. * @param {Object} O
  805. * @returns {Boolean}
  806. */
  807. function isNumber(O) {
  808. return _toString.call(O) == "[object Number]";
  809. }
  810. /**
  811. * 오브젝트가 NodeList인지 판단합니다.
  812. * @method ax5.util.isNodelist
  813. * @param {Object} O
  814. * @returns {Boolean}
  815. */
  816. function isNodelist(O) {
  817. return !!(_toString.call(O) == "[object NodeList]" || typeof O !== "undefined" && O && O[0] && O[0].nodeType == 1);
  818. }
  819. /**
  820. * 오브젝트가 undefined인지 판단합니다.
  821. * @method ax5.util.isUndefined
  822. * @param {Object} O
  823. * @returns {Boolean}
  824. */
  825. function isUndefined(O) {
  826. return typeof O === "undefined";
  827. }
  828. /**
  829. * 오브젝트가 undefined이거나 null이거나 빈값인지 판단합니다.
  830. * @method ax5.util.isNothing
  831. * @param {Object} O
  832. * @returns {Boolean}
  833. */
  834. function isNothing(O) {
  835. return typeof O === "undefined" || O === null || O === "";
  836. }
  837. /**
  838. * 오브젝트가 날자값인지 판단합니다.
  839. * @method ax5.util.isDate
  840. * @param {Date} O
  841. * @returns {Boolean}
  842. * @example
  843. * ```js
  844. * ax5.util.isDate('2016-09-30');
  845. * // false
  846. * ax5.util.isDate( new Date('2016-09-30') );
  847. * // true
  848. * ```
  849. */
  850. function isDate(O) {
  851. return O instanceof Date && !isNaN(O.valueOf());
  852. }
  853. function isDateFormat(O) {
  854. var result = false;
  855. if (!O) {} else if (O instanceof Date && !isNaN(O.valueOf())) {
  856. result = true;
  857. } else {
  858. if (O.length > 7) {
  859. if (date(O) instanceof Date) {
  860. return true;
  861. }
  862. }
  863. O = O.replace(/\D/g, '');
  864. if (O.length > 7) {
  865. var mm = O.substr(4, 2),
  866. dd = O.substr(6, 2);
  867. O = date(O);
  868. if (O.getMonth() == mm - 1 && O.getDate() == dd) {
  869. result = true;
  870. }
  871. }
  872. }
  873. return result;
  874. }
  875. /**
  876. * 오브젝트의 첫번째 아이템을 반환합니다.
  877. * @method ax5.util.first
  878. * @param {Object|Array} O
  879. * @returns {Object}
  880. * @example
  881. * ```js
  882. * ax5.util.first({a:1, b:2});
  883. * // Object {a: 1}
  884. * ax5.util.first([1,2,3,4]);
  885. * // 1
  886. * ```
  887. */
  888. function first(O) {
  889. if (isObject(O)) {
  890. var keys = Object.keys(O);
  891. var item = {};
  892. item[keys[0]] = O[keys[0]];
  893. return item;
  894. } else if (isArray(O)) {
  895. return O[0];
  896. } else {
  897. console.error("ax5.util.object.first", "argument type error");
  898. return undefined;
  899. }
  900. }
  901. /**
  902. * 오브젝트의 마지막 아이템을 반환합니다.
  903. * @method ax5.util.last
  904. * @param {Object|Array} O
  905. * @returns {Object}
  906. * @example
  907. * ```js
  908. * ax5.util.last({a:1, b:2});
  909. * // Object {b: 2}
  910. * ax5.util.last([1,2,3,4]);
  911. * // 4
  912. * ```
  913. */
  914. function last(O) {
  915. if (isObject(O)) {
  916. var keys = Object.keys(O);
  917. var item = {};
  918. item[keys[keys.length - 1]] = O[keys[keys.length - 1]];
  919. return item;
  920. } else if (isArray(O)) {
  921. return O[O.length - 1];
  922. } else {
  923. console.error("ax5.util.object.last", "argument type error");
  924. return undefined;
  925. }
  926. }
  927. /**
  928. * 쿠키를 설정합니다.
  929. * @method ax5.util.setCookie
  930. * @param {String} cname - 쿠키이름
  931. * @param {String} cvalue - 쿠키값
  932. * @param {Number} [exdays] - 쿠키 유지일수
  933. * @param {Object} [opts] - path, domain 설정 옵션
  934. * @example
  935. * ```js
  936. * ax5.util.setCookie("jslib", "AX5");
  937. * ax5.util.setCookie("jslib", "AX5", 3);
  938. * ax5.util.setCookie("jslib", "AX5", 3, {path:"/", domain:".axisj.com"});
  939. * ```
  940. */
  941. function setCookie(cn, cv, exdays, opts) {
  942. var expire;
  943. if (typeof exdays === "number") {
  944. expire = new Date();
  945. expire.setDate(expire.getDate() + exdays);
  946. }
  947. opts = opts || {};
  948. return doc.cookie = [escape(cn), '=', escape(cv), expire ? "; expires=" + expire.toUTCString() : "", // use expires attribute, max-age is not supported by IE
  949. opts.path ? "; path=" + opts.path : "", opts.domain ? "; domain=" + opts.domain : "", opts.secure ? "; secure" : ""].join("");
  950. }
  951. /**
  952. * 쿠키를 가져옵니다.
  953. * @method ax5.util.getCookie
  954. * @param {String} cname
  955. * @returns {String} cookie value
  956. * @example
  957. * ```js
  958. * ax5.util.getCookie("jslib");
  959. * ```
  960. */
  961. function getCookie(cname) {
  962. var name = cname + "=";
  963. var ca = doc.cookie.split(';'),
  964. i = 0,
  965. l = ca.length;
  966. for (; i < l; i++) {
  967. var c = ca[i];
  968. while (c.charAt(0) == ' ') {
  969. c = c.substring(1);
  970. }if (c.indexOf(name) != -1) return unescape(c.substring(name.length, c.length));
  971. }
  972. return "";
  973. }
  974. /**
  975. * jsonString 으로 alert 합니다.
  976. * @method ax5.util.alert
  977. * @param {Object|Array|String|Number} O
  978. * @returns {Object|Array|String|Number} O
  979. * @example ```js
  980. * ax5.util.alert({a:1,b:2});
  981. * ax5.util.alert("정말?");
  982. * ```
  983. */
  984. function alert(O) {
  985. win.alert(toJson(O));
  986. return O;
  987. }
  988. /**
  989. * 문자열의 특정 문자열까지 잘라주거나 원하는 포지션까지 잘라줍니다.
  990. * @method ax5.util.left
  991. * @param {String} str - 문자열
  992. * @param {String|Number} pos - 찾을 문자열 또는 포지션
  993. * @returns {String}
  994. * @example
  995. * ```js
  996. * ax5.util.left("abcd.efd", 3);
  997. * // abc
  998. * ax5.util.left("abcd.efd", ".");
  999. * // abcd
  1000. * ```
  1001. */
  1002. function left(str, pos) {
  1003. if (typeof str === "undefined" || typeof pos === "undefined") return "";
  1004. if (isString(pos)) {
  1005. return str.indexOf(pos) > -1 ? str.substr(0, str.indexOf(pos)) : "";
  1006. } else if (isNumber(pos)) {
  1007. return str.substr(0, pos);
  1008. } else {
  1009. return "";
  1010. }
  1011. }
  1012. /**
  1013. * 문자열의 특정 문자열까지 잘라주거나 원하는 포지션까지 잘라줍니다.
  1014. * @method ax5.util.right
  1015. * @param {String} str - 문자열
  1016. * @param {String|Number} pos - 찾을 문자열 또는 포지션
  1017. * @returns {String}
  1018. * @example
  1019. * ```js
  1020. * ax5.util.right("abcd.efd", 3);
  1021. * // efd
  1022. * ax5.util.right("abcd.efd", ".");
  1023. * // efd
  1024. * ```
  1025. */
  1026. function right(str, pos) {
  1027. if (typeof str === "undefined" || typeof pos === "undefined") return "";
  1028. str = '' + str;
  1029. if (isString(pos)) {
  1030. return str.lastIndexOf(pos) > -1 ? str.substr(str.lastIndexOf(pos) + 1) : "";
  1031. } else if (isNumber(pos)) {
  1032. return str.substr(str.length - pos);
  1033. } else {
  1034. return "";
  1035. }
  1036. }
  1037. /**
  1038. * css형 문자열이나 특수문자가 포함된 문자열을 카멜케이스로 바꾸어 반환합니다.
  1039. * @method ax5.util.camelCase
  1040. * @param {String} str
  1041. * @returns {String}
  1042. * @example
  1043. * ```js
  1044. * ax5.util.camelCase("inner-width");
  1045. * ax5.util.camelCase("innerWidth");
  1046. * // innerWidth
  1047. * ```
  1048. */
  1049. function camelCase(str) {
  1050. return str.replace(reMs, "ms-").replace(reSnakeCase, function (all, letter) {
  1051. return letter.toUpperCase();
  1052. });
  1053. }
  1054. /**
  1055. * css형 문자열이나 카멜케이스문자열을 스네이크 케이스 문자열로 바꾸어 반환합니다.
  1056. * @method ax5.util.snakeCase
  1057. * @param {String} str
  1058. * @returns {String}
  1059. * @example
  1060. * ```js
  1061. * ax5.util.snakeCase("innerWidth");
  1062. * ax5.util.snakeCase("inner-Width");
  1063. * ax5.util.snakeCase("innerWidth");
  1064. * // inner-width
  1065. * ```
  1066. */
  1067. function snakeCase(str) {
  1068. return camelCase(str).replace(reCamelCase, function (all, letter) {
  1069. return "-" + letter.toLowerCase();
  1070. });
  1071. }
  1072. /**
  1073. * 문자열에서 -. 제외한 모든 문자열을 제거하고 숫자로 반환합니다. 옵션에 따라 원하는 형식의 숫자로 변환 있습니다.
  1074. * @method ax5.util.number
  1075. * @param {String|Number} str
  1076. * @param {Object} cond - 옵션
  1077. * @returns {String|Number}
  1078. * @example
  1079. * ```js
  1080. * var cond = {
  1081. * round: {Number|Boolean} - 반올림할 자릿수,
  1082. * money: {Boolean} - 통화,
  1083. * abs: {Boolean} - 절대값,
  1084. * byte: {Boolean} - 바이트
  1085. * }
  1086. *
  1087. * console.log(ax5.util.number(123456789.678, {round:1}));
  1088. * console.log(ax5.util.number(123456789.678, {round:1, money:true}));
  1089. * console.log(ax5.util.number(123456789.678, {round:2, byte:true}));
  1090. * console.log(ax5.util.number(-123456789.8888, {abs:true, round:2, money:true}));
  1091. * console.log(ax5.util.number("A-1234~~56789.8~888PX", {abs:true, round:2, money:true}));
  1092. *
  1093. * //123456789.7
  1094. * //123,456,789.7
  1095. * //117.7MB
  1096. * //123,456,789.89
  1097. * //123,456,789.89
  1098. * ```
  1099. */
  1100. function number(str, cond) {
  1101. var result,
  1102. pair = ('' + str).split(reDot),
  1103. isMinus,
  1104. returnValue;
  1105. isMinus = Number(pair[0].replace(/,/g, "")) < 0 || pair[0] == "-0";
  1106. returnValue = 0.0;
  1107. pair[0] = pair[0].replace(reInt, "");
  1108. if (pair[1]) {
  1109. pair[1] = pair[1].replace(reNotNum, "");
  1110. returnValue = Number(pair[0] + "." + pair[1]) || 0;
  1111. } else {
  1112. returnValue = Number(pair[0]) || 0;
  1113. }
  1114. result = isMinus ? -returnValue : returnValue;
  1115. each(cond, function (k, c) {
  1116. if (k == "round") {
  1117. if (isNumber(c)) {
  1118. if (c < 0) {
  1119. result = +(Math.round(result + "e-" + Math.abs(c)) + "e+" + Math.abs(c));
  1120. } else {
  1121. result = +(Math.round(result + "e+" + c) + "e-" + c);
  1122. }
  1123. } else {
  1124. result = Math.round(result);
  1125. }
  1126. }
  1127. if (k == "floor") {
  1128. result = Math.floor(result);
  1129. }
  1130. if (k == "ceil") {
  1131. result = Math.ceil(result);
  1132. } else if (k == "money") {
  1133. result = function (val) {
  1134. var txtNumber = '' + val;
  1135. if (isNaN(txtNumber) || txtNumber == "") {
  1136. return "";
  1137. } else {
  1138. var arrNumber = txtNumber.split('.');
  1139. arrNumber[0] += '.';
  1140. do {
  1141. arrNumber[0] = arrNumber[0].replace(reMoneySplit, '$1,$2');
  1142. } while (reMoneySplit.test(arrNumber[0]));
  1143. if (arrNumber.length > 1) {
  1144. return arrNumber.join('');
  1145. } else {
  1146. return arrNumber[0].split('.')[0];
  1147. }
  1148. }
  1149. }(result);
  1150. } else if (k == "abs") {
  1151. result = Math.abs(Number(result));
  1152. } else if (k == "byte") {
  1153. result = function (val) {
  1154. val = Number(result);
  1155. var nUnit = "KB";
  1156. var myByte = val / 1024;
  1157. if (myByte / 1024 > 1) {
  1158. nUnit = "MB";
  1159. myByte = myByte / 1024;
  1160. }
  1161. if (myByte / 1024 > 1) {
  1162. nUnit = "GB";
  1163. myByte = myByte / 1024;
  1164. }
  1165. return number(myByte, { round: 1 }) + nUnit;
  1166. }(result);
  1167. }
  1168. });
  1169. return result;
  1170. }
  1171. /**
  1172. * 배열 비슷한 오브젝트를 배열로 변환해줍니다.
  1173. * @method ax5.util.toArray
  1174. * @param {Object|Elements|Arguments} O
  1175. * @returns {Array}
  1176. * @example
  1177. * ```js
  1178. * ax5.util.toArray(arguments);
  1179. * //
  1180. * ```
  1181. */
  1182. function toArray(O) {
  1183. if (typeof O.length != "undefined") return Array.prototype.slice.call(O);
  1184. return [];
  1185. }
  1186. /**
  1187. * 첫번째 인자에 두번째 인자 아이템을 합쳐줍니다. concat과 같은 역할을 하지만. 인자가 Array타입이 아니어도 됩니다.
  1188. * @method ax5.util.merge
  1189. * @param {Array|ArrayLike} first
  1190. * @param {Array|ArrayLike} second
  1191. * @returns {Array} first
  1192. * @example
  1193. * ```
  1194. *
  1195. * ```
  1196. */
  1197. function merge(first, second) {
  1198. var l = second.length,
  1199. i = first.length,
  1200. j = 0;
  1201. if (typeof l === "number") {
  1202. for (; j < l; j++) {
  1203. first[i++] = second[j];
  1204. }
  1205. } else {
  1206. while (second[j] !== undefined) {
  1207. first[i++] = second[j++];
  1208. }
  1209. }
  1210. first.length = i;
  1211. return first;
  1212. }
  1213. /**
  1214. * 오브젝트를 파라미터형식으로 또는 파라미터를 오브젝트 형식으로 변환합니다.
  1215. * @method ax5.util.param
  1216. * @param {Object|Array|String} O
  1217. * @param {String} [cond] - param|object
  1218. * @returns {Object|String}
  1219. * @example
  1220. * ```
  1221. * ax5.util.param({a:1,b:'1232'}, "param");
  1222. * ax5.util.param("a=1&b=1232", "param");
  1223. * // "a=1&b=1232"
  1224. * ax5.util.param("a=1&b=1232");
  1225. * // {a: "1", b: "1232"}
  1226. * ```
  1227. */
  1228. function param(O, cond) {
  1229. var p;
  1230. if (isString(O) && typeof cond !== "undefined" && cond == "param") {
  1231. return O;
  1232. } else if (isString(O) && typeof cond !== "undefined" && cond == "object" || isString(O) && typeof cond === "undefined") {
  1233. p = {};
  1234. each(O.split(reAmp), function () {
  1235. var item = this.split(reEq);
  1236. if (!p[item[0]]) p[item[0]] = item[1];else {
  1237. if (isString(p[item[0]])) p[item[0]] = [p[item[0]]];
  1238. p[item[0]].push(item[1]);
  1239. }
  1240. });
  1241. return p;
  1242. } else {
  1243. p = [];
  1244. each(O, function (k, v) {
  1245. p.push(k + "=" + escape(v));
  1246. });
  1247. return p.join('&');
  1248. }
  1249. }
  1250. function encode(s) {
  1251. return encodeURIComponent(s);
  1252. }
  1253. function decode(s) {
  1254. return decodeURIComponent(s);
  1255. }
  1256. function error() {
  1257. ax5.info.onerror.apply(this, arguments);
  1258. }
  1259. function localDate(yy, mm, dd, hh, mi, ss) {
  1260. var utcD, localD;
  1261. localD = new Date();
  1262. if (mm < 0) mm = 0;
  1263. if (typeof hh === "undefined") hh = 12;
  1264. if (typeof mi === "undefined") mi = 0;
  1265. utcD = new Date(Date.UTC(yy, mm, dd || 1, hh, mi, ss || 0));
  1266. if (mm == 0 && dd == 1 && utcD.getUTCHours() + utcD.getTimezoneOffset() / 60 < 0) {
  1267. utcD.setUTCHours(0);
  1268. } else {
  1269. utcD.setUTCHours(utcD.getUTCHours() + utcD.getTimezoneOffset() / 60);
  1270. }
  1271. return utcD;
  1272. }
  1273. /**
  1274. * 날짜 형식의 문자열이나 Date객체를 조건에 맞게 처리 원하는 return 값으로 반환합니다.
  1275. * @method ax5.util.date
  1276. * @param {String|Date} d
  1277. * @param {Object} cond
  1278. * @returns {Date|String}
  1279. * @example
  1280. * ```js
  1281. * ax5.util.date('2013-01-01'); // Tue Jan 01 2013 23:59:00 GMT+0900 (KST)
  1282. * ax5.util.date((new Date()), {add:{d:10}, return:'yyyy/MM/dd'}); // "2015/07/01"
  1283. * ax5.util.date('1919-03-01', {add:{d:10}, return:'yyyy/MM/dd hh:mm:ss'}); // "1919/03/11 23:59:00"
  1284. * ```
  1285. */
  1286. function date(d, cond) {
  1287. var yy = void 0,
  1288. mm = void 0,
  1289. dd = void 0,
  1290. hh = void 0,
  1291. mi = void 0,
  1292. aDateTime = void 0,
  1293. aTimes = void 0,
  1294. aTime = void 0,
  1295. aDate = void 0,
  1296. va = void 0,
  1297. ISO_8601 = /^\d{4}(-\d\d(-\d\d(T\d\d:\d\d(:\d\d)?(\.\d+)?(([+-]\d\d:\d\d)|Z)?)?)?)?$/i,
  1298. ISO_8601_FULL = /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?(([+-]\d\d:\d\d)|Z)?$/i;
  1299. if (isString(d)) {
  1300. if (d.length == 0) {
  1301. d = new Date();
  1302. } else if (d.length > 15) {
  1303. if (ISO_8601_FULL.test(d) || ISO_8601.test(d)) {
  1304. d = new Date(d);
  1305. } else {
  1306. aDateTime = d.split(/ /g), aTimes, aTime, aDate = aDateTime[0].split(/\D/g), yy = aDate[0];
  1307. mm = parseFloat(aDate[1]);
  1308. dd = parseFloat(aDate[2]);
  1309. aTime = aDateTime[1] || "09:00";
  1310. aTimes = aTime.substring(0, 5).split(":");
  1311. hh = parseFloat(aTimes[0]);
  1312. mi = parseFloat(aTimes[1]);
  1313. if (right(aTime, 2) === "AM" || right(aTime, 2) === "PM") hh += 12;
  1314. d = localDate(yy, mm - 1, dd, hh, mi);
  1315. }
  1316. } else if (d.length == 14) {
  1317. va = d.replace(/\D/g, "");
  1318. d = localDate(va.substr(0, 4), va.substr(4, 2) - 1, number(va.substr(6, 2)), number(va.substr(8, 2)), number(va.substr(10, 2)), number(va.substr(12, 2)));
  1319. } else if (d.length > 7) {
  1320. va = d.replace(/\D/g, "");
  1321. d = localDate(va.substr(0, 4), va.substr(4, 2) - 1, number(va.substr(6, 2)));
  1322. } else if (d.length > 4) {
  1323. va = d.replace(/\D/g, "");
  1324. d = localDate(va.substr(0, 4), va.substr(4, 2) - 1, 1);
  1325. } else if (d.length > 2) {
  1326. va = d.replace(/\D/g, "");
  1327. return localDate(va.substr(0, 4), va.substr(4, 2) - 1, 1);
  1328. } else {
  1329. d = new Date();
  1330. }
  1331. }
  1332. if (typeof cond === "undefined" || typeof d === "undefined") {
  1333. return d;
  1334. } else {
  1335. if ("add" in cond) {
  1336. d = function (_d, opts) {
  1337. var yy = void 0,
  1338. mm = void 0,
  1339. dd = void 0,
  1340. mxdd = void 0,
  1341. DyMilli = 1000 * 60 * 60 * 24;
  1342. if (typeof opts["d"] !== "undefined") {
  1343. _d.setTime(_d.getTime() + opts["d"] * DyMilli);
  1344. } else if (typeof opts["m"] !== "undefined") {
  1345. yy = _d.getFullYear();
  1346. mm = _d.getMonth();
  1347. dd = _d.getDate();
  1348. yy = yy + parseInt(opts["m"] / 12);
  1349. mm += opts["m"] % 12;
  1350. mxdd = daysOfMonth(yy, mm);
  1351. if (mxdd < dd) dd = mxdd;
  1352. _d = new Date(yy, mm, dd, 12);
  1353. } else if (typeof opts["y"] !== "undefined") {
  1354. _d.setTime(_d.getTime() + opts["y"] * 365 * DyMilli);
  1355. } else if (typeof opts["h"] !== "undefined") {
  1356. _d.setTime(_d.getTime() + opts["h"] * 1000 * 60 * 60);
  1357. }
  1358. return _d;
  1359. }(new Date(d), cond["add"]);
  1360. }
  1361. if ("set" in cond) {
  1362. d = function (_d, opts) {
  1363. var yy = void 0,
  1364. mm = void 0,
  1365. dd = void 0,
  1366. processor = {
  1367. "firstDayOfMonth": function firstDayOfMonth(date) {
  1368. yy = date.getFullYear();
  1369. mm = date.getMonth();
  1370. dd = 1;
  1371. return new Date(yy, mm, dd, 12);
  1372. },
  1373. "lastDayOfMonth": function lastDayOfMonth(date) {
  1374. yy = date.getFullYear();
  1375. mm = date.getMonth();
  1376. dd = daysOfMonth(yy, mm);
  1377. return new Date(yy, mm, dd, 12);
  1378. }
  1379. };
  1380. if (opts in processor) {
  1381. return processor[opts](_d);
  1382. } else {
  1383. return _d;
  1384. }
  1385. }(new Date(d), cond["set"]);
  1386. }
  1387. if ("return" in cond) {
  1388. return function () {
  1389. var fStr = cond["return"],
  1390. nY = void 0,
  1391. nM = void 0,
  1392. nD = void 0,
  1393. nH = void 0,
  1394. nMM = void 0,
  1395. nS = void 0,
  1396. nDW = void 0,
  1397. yre = void 0,
  1398. regY = void 0,
  1399. mre = void 0,
  1400. regM = void 0,
  1401. dre = void 0,
  1402. regD = void 0,
  1403. hre = void 0,
  1404. regH = void 0,
  1405. mire = void 0,
  1406. regMI = void 0,
  1407. sre = void 0,
  1408. regS = void 0,
  1409. dwre = void 0,
  1410. regDW = void 0;
  1411. nY = d.getUTCFullYear();
  1412. nM = setDigit(d.getMonth() + 1, 2);
  1413. nD = setDigit(d.getDate(), 2);
  1414. nH = setDigit(d.getHours(), 2);
  1415. nMM = setDigit(d.getMinutes(), 2);
  1416. nS = setDigit(d.getSeconds(), 2);
  1417. nDW = d.getDay();
  1418. yre = /[^y]*(yyyy)[^y]*/gi;
  1419. yre.exec(fStr);
  1420. regY = RegExp.$1;
  1421. mre = /[^m]*(MM)[^m]*/g;
  1422. mre.exec(fStr);
  1423. regM = RegExp.$1;
  1424. dre = /[^d]*(dd)[^d]*/gi;
  1425. dre.exec(fStr);
  1426. regD = RegExp.$1;
  1427. hre = /[^h]*(hh)[^h]*/gi;
  1428. hre.exec(fStr);
  1429. regH = RegExp.$1;
  1430. mire = /[^m]*(mm)[^i]*/g;
  1431. mire.exec(fStr);
  1432. regMI = RegExp.$1;
  1433. sre = /[^s]*(ss)[^s]*/gi;
  1434. sre.exec(fStr);
  1435. regS = RegExp.$1;
  1436. dwre = /[^d]*(dw)[^w]*/gi;
  1437. dwre.exec(fStr);
  1438. regDW = RegExp.$1;
  1439. if (regY === "yyyy") {
  1440. fStr = fStr.replace(regY, right(nY, regY.length));
  1441. }
  1442. if (regM === "MM") {
  1443. if (regM.length == 1) nM = d.getMonth() + 1;
  1444. fStr = fStr.replace(regM, nM);
  1445. }
  1446. if (regD === "dd") {
  1447. if (regD.length == 1) nD = d.getDate();
  1448. fStr = fStr.replace(regD, nD);
  1449. }
  1450. if (regH === "hh") {
  1451. fStr = fStr.replace(regH, nH);
  1452. }
  1453. if (regMI === "mm") {
  1454. fStr = fStr.replace(regMI, nMM);
  1455. }
  1456. if (regS === "ss") {
  1457. fStr = fStr.replace(regS, nS);
  1458. }
  1459. if (regDW == "dw") {
  1460. fStr = fStr.replace(regDW, info.weekNames[nDW].label);
  1461. }
  1462. return fStr;
  1463. }();
  1464. } else {
  1465. return d;
  1466. }
  1467. }
  1468. }
  1469. /**
  1470. * 인자인 날짜가 오늘부터 몇일전인지 반환합니다. 또는 인자인 날짜가 가까운 미래에 몇일 후인지 반환합니다.
  1471. * @method ax5.util.dday
  1472. * @param {String|Data} d
  1473. * @param {Object} cond
  1474. * @returns {Number}
  1475. * @example
  1476. * ```js
  1477. * ax5.util.dday('2016-01-29');
  1478. * // 1
  1479. * ax5.util.dday('2016-01-29', {today:'2016-01-28'});
  1480. * // 1
  1481. * ax5.util.dday('1977-03-29', {today:'2016-01-28', age:true});
  1482. * // 39
  1483. * ```
  1484. */
  1485. function dday(d, cond) {
  1486. var memoryDay = date(d),
  1487. DyMilli = 1000 * 60 * 60 * 24,
  1488. today = new Date(),
  1489. diffnum,
  1490. thisYearMemoryDay;
  1491. function getDayTime(_d) {
  1492. return Math.floor(_d.getTime() / DyMilli) * DyMilli;
  1493. }
  1494. if (typeof cond === "undefined") {
  1495. diffnum = number((getDayTime(memoryDay) - getDayTime(today)) / DyMilli, { floor: true });
  1496. return diffnum;
  1497. } else {
  1498. diffnum = number((getDayTime(memoryDay) - getDayTime(today)) / DyMilli, { floor: true });
  1499. if (cond["today"]) {
  1500. today = date(cond.today);
  1501. diffnum = number((getDayTime(memoryDay) - getDayTime(today)) / DyMilli, { floor: true });
  1502. }
  1503. if (cond["thisYear"]) {
  1504. thisYearMemoryDay = new Date(today.getFullYear(), memoryDay.getMonth(), memoryDay.getDate());
  1505. diffnum = number((getDayTime(thisYearMemoryDay) - getDayTime(today)) / DyMilli, { floor: true });
  1506. if (diffnum < 0) {
  1507. thisYearMemoryDay = new Date(today.getFullYear() + 1, memoryDay.getMonth(), memoryDay.getDate());
  1508. diffnum = number((getDayTime(thisYearMemoryDay) - getDayTime(today)) / DyMilli, { floor: true });
  1509. }
  1510. }
  1511. if (cond["age"]) {
  1512. thisYearMemoryDay = new Date(today.getFullYear(), memoryDay.getMonth(), memoryDay.getDate());
  1513. diffnum = thisYearMemoryDay.getFullYear() - memoryDay.getFullYear();
  1514. }
  1515. return diffnum;
  1516. }
  1517. }
  1518. /**
  1519. * 인자인 날짜가 몇년 몇월의 몇번째 주차인지 반환합니다.
  1520. * @method ax5.util.weeksOfMonth
  1521. * @param {String|Data} d
  1522. * @returns {Object}
  1523. * @example
  1524. * ```js
  1525. * ax5.util.weeksOfMonth("2015-10-01"); // {year: 2015, month: 10, count: 1}
  1526. * ax5.util.weeksOfMonth("2015-09-19"); // {year: 2015, month: 9, count: 3}
  1527. * ```
  1528. */
  1529. function weeksOfMonth(d) {
  1530. var myDate = date(d);
  1531. return {
  1532. year: myDate.getFullYear(),
  1533. month: myDate.getMonth() + 1,
  1534. count: parseInt(myDate.getDate() / 7 + 1)
  1535. };
  1536. }
  1537. /**
  1538. * 년월에 맞는 날자수를 반환합니다.
  1539. * (new Date()).getMonth() 기준으로 월값을 보냅니다. "2월" 인경우 "1" 넘기게 됩니다.
  1540. * @method ax5.util.daysOfMonth
  1541. * @param {Number} y
  1542. * @param {Number} m
  1543. * @returns {Number}
  1544. * @examples
  1545. * ```js
  1546. * ax5.util.daysOfMonth(2015, 11); // 31
  1547. * ax5.util.daysOfMonth(2015, 1); // 28
  1548. * ```
  1549. */
  1550. function daysOfMonth(y, m) {
  1551. if (m == 3 || m == 5 || m == 8 || m == 10) {
  1552. return 30;
  1553. } else if (m == 1) {
  1554. return y % 4 == 0 && y % 100 != 0 || y % 400 == 0 ? 29 : 28;
  1555. } else {
  1556. return 31;
  1557. }
  1558. }
  1559. /**
  1560. * 원하는 횟수 만큼 자릿수 맞춤 문자열을 포함한 문자열을 반환합니다.
  1561. * 문자열 길이보다 작은값을 보내면 무시됩니다.
  1562. * @method ax5.util.setDigit
  1563. * @param {String|Number} num
  1564. * @param {Number} length
  1565. * @param {String} [padder=0]
  1566. * @param {Number} [radix]
  1567. * @returns {String}
  1568. * @example
  1569. * ```
  1570. * ax5.util.setDigit(2016, 6)
  1571. * // "002016"
  1572. * ax5.util.setDigit(2016, 2)
  1573. * // "2016"
  1574. * ```
  1575. */
  1576. function setDigit(num, length, padder, radix) {
  1577. var s = num.toString(radix || 10);
  1578. return times(padder || '0', length - s.length) + s;
  1579. }
  1580. /**
  1581. * 문자열을 지정된 수만큼 반복 합니다.
  1582. * @param {String} s
  1583. * @param {Number} count
  1584. * @returns {string}
  1585. * @example
  1586. * ```
  1587. * ax5.util.times(2016, 2)
  1588. * //"20162016"
  1589. * ```
  1590. */
  1591. function times(s, count) {
  1592. return count < 1 ? '' : new Array(count + 1).join(s);
  1593. }
  1594. /**
  1595. * 타겟엘리먼트의 부모 엘리멘트 트리에서 원하는 조건의 엘리먼트를 얻습니다.
  1596. * @method ax5.util.findParentNode
  1597. * @param {Element} _target - target element
  1598. * @param {Object|Function} cond - 원하는 element를 찾을 조건
  1599. * @returns {Element}
  1600. * @example
  1601. * ```
  1602. * // cond 속성정의
  1603. * var cond = {
  1604. * tagname: {String} - 태그명 (ex. a, div, span..),
  1605. * clazz: {String} - 클래스명
  1606. * [, 찾고 싶은 attribute명들]
  1607. * };
  1608. * console.log(
  1609. * console.log(
  1610. * ax5.util.findParentNode(e.target, {tagname:"a", clazz:"ax-menu-handel", "data-custom-attr":"attr_value"})
  1611. * );
  1612. * // cond 함수로 처리하기
  1613. * jQuery('#id').bind("click.app_expand", function(e){
  1614. * var target = ax5.util.findParentNode(e.target, function(target){
  1615. * if($(target).hasClass("aside")){
  1616. * return true;
  1617. * }
  1618. * else{
  1619. * return true;
  1620. * }
  1621. * });
  1622. * //client-aside
  1623. * if(target.id !== "client-aside"){
  1624. * // some action
  1625. * }
  1626. * });
  1627. * ```
  1628. */
  1629. function findParentNode(_target, cond) {
  1630. if (_target) {
  1631. while (function () {
  1632. var result = true;
  1633. if (typeof cond === "undefined") {
  1634. _target = _target.parentNode ? _target.parentNode : false;
  1635. } else if (isFunction(cond)) {
  1636. result = cond(_target);
  1637. } else if (isObject(cond)) {
  1638. for (var k in cond) {
  1639. if (k === "tagname") {
  1640. if (_target.tagName.toLocaleLowerCase() != cond[k]) {
  1641. result = false;
  1642. break;
  1643. }
  1644. } else if (k === "clazz" || k === "class_name") {
  1645. if ("className" in _target) {
  1646. var klasss = _target.className.split(reClassNameSplit);
  1647. var hasClass = false;
  1648. for (var a = 0; a < klasss.length; a++) {
  1649. if (klasss[a] == cond[k]) {
  1650. hasClass = true;
  1651. break;
  1652. }
  1653. }
  1654. result = hasClass;
  1655. } else {
  1656. result = false;
  1657. break;
  1658. }
  1659. } else {
  1660. // 그외 속성값들.
  1661. if (_target.getAttribute) {
  1662. if (_target.getAttribute(k) != cond[k]) {
  1663. result = false;
  1664. break;
  1665. }
  1666. } else {
  1667. result = false;
  1668. break;
  1669. }
  1670. }
  1671. }
  1672. }
  1673. return !result;
  1674. }()) {
  1675. if (_target.parentNode && _target.parentNode.parentNode) {
  1676. _target = _target.parentNode;
  1677. } else {
  1678. _target = false;
  1679. break;
  1680. }
  1681. }
  1682. }
  1683. return _target;
  1684. }
  1685. /**
  1686. * @method ax5.util.cssNumber
  1687. * @param {String|Number} val
  1688. * @returns {String}
  1689. * @example
  1690. * ```
  1691. * console.log(ax5.util.cssNumber("100px"))
  1692. * console.log(ax5.util.cssNumber("100%"))
  1693. * console.log(ax5.util.cssNumber("100"))
  1694. * console.log(ax5.util.cssNumber(100))
  1695. * console.log(ax5.util.cssNumber("!!100@#"))
  1696. * ```
  1697. */
  1698. function cssNumber(val) {
  1699. var re = /\D?(\d+)([a-zA-Z%]*)/i,
  1700. found = ('' + val).match(re),
  1701. unit = found[2] || "px";
  1702. return found[1] + unit;
  1703. }
  1704. /**
  1705. * css string object 넘기면 object string 으로 변환되어 리턴됩니다.
  1706. * @method ax5.util.css
  1707. * @param {Object|String} val - CSS String or CSS Object
  1708. * @returns {String|Object}
  1709. * @example
  1710. * ```
  1711. * console.log(ax5.util.css({background: "#ccc", padding: "50px", width: "100px"}));
  1712. * //"background:#ccc;padding:50px;width:100px;"
  1713. * console.log(ax5.util.css('width:100px;padding: 50px; background: #ccc'));
  1714. * // object {width: "100px", padding: "50px", background: "#ccc"}
  1715. * ```
  1716. */
  1717. function css(val) {
  1718. var returns;
  1719. if (isObject(val)) {
  1720. returns = '';
  1721. for (var k in val) {
  1722. returns += k + ':' + val[k] + ';';
  1723. }
  1724. return returns;
  1725. } else if (isString(val)) {
  1726. returns = {};
  1727. var valSplited = val.split(/[ ]*;[ ]*/g);
  1728. valSplited.forEach(function (v) {
  1729. if ((v = v.trim()) !== "") {
  1730. var vSplited = v.split(/[ ]*:[ ]*/g);
  1731. returns[vSplited[0]] = vSplited[1];
  1732. }
  1733. });
  1734. return returns;
  1735. }
  1736. }
  1737. /**
  1738. * @method ax5.util.stopEvent
  1739. * @param {Event} e
  1740. * @example
  1741. * ```
  1742. * ax5.util.stopEvent(e);
  1743. * ```
  1744. */
  1745. function stopEvent(e) {
  1746. // 이벤트 중지 구문
  1747. if (!e) var e = window.event;
  1748. //e.cancelBubble is supported by IE -
  1749. // this will kill the bubbling process.
  1750. e.cancelBubble = true;
  1751. e.returnValue = false;
  1752. //e.stopPropagation works only in Firefox.
  1753. if (e.stopPropagation) e.stopPropagation();
  1754. if (e.preventDefault) e.preventDefault();
  1755. return false;
  1756. // 이벤트 중지 구문 끝
  1757. }
  1758. /**
  1759. * @method ax5.util.selectRange
  1760. * @param {Element} el
  1761. * @param {Element} offset
  1762. * @example
  1763. * ```
  1764. * ax5.util.selectRange($("#select-test-0")); // selectAll
  1765. * ax5.util.selectRange($("#select-test-0"), "selectAll"); //selectAll
  1766. * ax5.util.selectRange($("#select-test-0"), "start"); // focus on start
  1767. * ax5.util.selectRange($("#select-test-0"), "end"); // focus on end
  1768. * ax5.util.selectRange($("#select-test-0"), [1, 5]); // select 1~5
  1769. * ```
  1770. */
  1771. var selectRange = function () {
  1772. var processor = {
  1773. 'textRange': {
  1774. 'selectAll': function selectAll(el, range, offset) {},
  1775. 'arr': function arr(el, range, offset) {
  1776. range.moveStart("character", offset[0]); // todo ie node select 체크필요
  1777. range.collapse();
  1778. range.moveEnd("character", offset[1]);
  1779. },
  1780. 'start': function start(el, range, offset) {
  1781. range.moveStart("character", 0);
  1782. range.collapse();
  1783. },
  1784. 'end': function end(el, range, offset) {
  1785. range.moveStart("character", range.text.length);
  1786. range.collapse();
  1787. }
  1788. },
  1789. 'range': {
  1790. 'selectAll': function selectAll(el, range, offset) {
  1791. range.selectNodeContents(el);
  1792. },
  1793. 'arr': function arr(el, range, offset) {
  1794. if (isObject(offset[0])) {
  1795. range.setStart(offset[0].node, offset[0].offset);
  1796. range.setEnd(offset[1].node, offset[1].offset);
  1797. } else {
  1798. range.setStart(el.firstChild, offset[0]);
  1799. range.setEnd(el.firstChild, offset[1]);
  1800. }
  1801. },
  1802. 'start': function start(el, range, offset) {
  1803. range.selectNodeContents(el);
  1804. range.collapse(true);
  1805. },
  1806. 'end': function end(el, range, offset) {
  1807. range.selectNodeContents(el);
  1808. range.collapse(false);
  1809. }
  1810. }
  1811. };
  1812. return function (el, offset) {
  1813. var range, rangeType, selection;
  1814. if (el instanceof jQuery) {
  1815. el = el.get(0);
  1816. }
  1817. if (!el) return;
  1818. // 레인지 타입 선택
  1819. if (doc.body.createTextRange) {
  1820. range = document.body.createTextRange();
  1821. range.moveToElementText(el);
  1822. rangeType = "textRange";
  1823. } else if (window.getSelection) {
  1824. selection = window.getSelection();
  1825. range = document.createRange();
  1826. rangeType = "range";
  1827. }
  1828. // range 적용
  1829. if (typeof offset == "undefined") {
  1830. processor[rangeType].selectAll.call(this, el, range, offset);
  1831. } else if (isArray(offset)) {
  1832. processor[rangeType].arr.call(this, el, range, offset);
  1833. } else {
  1834. for (var key in processor[rangeType]) {
  1835. if (offset == key) {
  1836. processor[rangeType][key].call(this, el, range, offset);
  1837. break;
  1838. }
  1839. }
  1840. }
  1841. // 포커스 및 셀렉트
  1842. if (doc.body.createTextRange) {
  1843. range.select();
  1844. el.focus();
  1845. } else if (window.getSelection) {
  1846. el.focus();
  1847. selection.removeAllRanges();
  1848. selection.addRange(range);
  1849. }
  1850. };
  1851. }();
  1852. /**
  1853. * 지정한 시간을 지연시켜 함수를 실행합니다.
  1854. * @method ax5.util.debounce
  1855. * @param {Function} func
  1856. * @param {Number} wait
  1857. * @param {Object} options
  1858. * @returns {debounced}
  1859. * @example
  1860. * ```js
  1861. * var debounceFn = ax5.util.debounce(function( val ) { console.log(val); }, 300);
  1862. * $(document.body).click(function(){
  1863. * debounceFn(new Date());
  1864. * });
  1865. * ```
  1866. */
  1867. // https://github.com/lodash/lodash/blob/master/debounce.js
  1868. function debounce(func, wait, options) {
  1869. var lastArgs = void 0,
  1870. lastThis = void 0,
  1871. maxWait = void 0,
  1872. result = void 0,
  1873. timerId = void 0,
  1874. lastCallTime = void 0;
  1875. var lastInvokeTime = 0;
  1876. var leading = false;
  1877. var maxing = false;
  1878. var trailing = true;
  1879. if (typeof func != 'function') {
  1880. throw new TypeError('Expected a function');
  1881. }
  1882. wait = +wait || 0;
  1883. if (isObject(options)) {
  1884. leading = !!options.leading;
  1885. maxing = 'maxWait' in options;
  1886. maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait;
  1887. trailing = 'trailing' in options ? !!options.trailing : trailing;
  1888. }
  1889. function invokeFunc(time) {
  1890. var args = lastArgs;
  1891. var thisArg = lastThis;
  1892. lastArgs = lastThis = undefined;
  1893. lastInvokeTime = time;
  1894. result = func.apply(thisArg, args);
  1895. return result;
  1896. }
  1897. function leadingEdge(time) {
  1898. // Reset any `maxWait` timer.
  1899. lastInvokeTime = time;
  1900. // Start the timer for the trailing edge.
  1901. timerId = setTimeout(timerExpired, wait);
  1902. // Invoke the leading edge.
  1903. return leading ? invokeFunc(time) : result;
  1904. }
  1905. function remainingWait(time) {
  1906. var timeSinceLastCall = time - lastCallTime;
  1907. var timeSinceLastInvoke = time - lastInvokeTime;
  1908. var result = wait - timeSinceLastCall;
  1909. return maxing ? Math.min(result, maxWait - timeSinceLastInvoke) : result;
  1910. }
  1911. function shouldInvoke(time) {
  1912. var timeSinceLastCall = time - lastCallTime;
  1913. var timeSinceLastInvoke = time - lastInvokeTime;
  1914. // Either this is the first call, activity has stopped and we're at the
  1915. // trailing edge, the system time has gone backwards and we're treating
  1916. // it as the trailing edge, or we've hit the `maxWait` limit.
  1917. return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
  1918. }
  1919. function timerExpired() {
  1920. var time = Date.now();
  1921. if (shouldInvoke(time)) {
  1922. return trailingEdge(time);
  1923. }
  1924. // Restart the timer.
  1925. timerId = setTimeout(timerExpired, remainingWait(time));
  1926. }
  1927. function trailingEdge(time) {
  1928. timerId = undefined;
  1929. // Only invoke if we have `lastArgs` which means `func` has been
  1930. // debounced at least once.
  1931. if (trailing && lastArgs) {
  1932. return invokeFunc(time);
  1933. }
  1934. lastArgs = lastThis = undefined;
  1935. return result;
  1936. }
  1937. function cancel() {
  1938. if (timerId !== undefined) {
  1939. clearTimeout(timerId);
  1940. }
  1941. lastInvokeTime = 0;
  1942. lastArgs = lastCallTime = lastThis = timerId = undefined;
  1943. }
  1944. function flush() {
  1945. return timerId === undefined ? result : trailingEdge(Date.now());
  1946. }
  1947. function debounced() {
  1948. var time = Date.now();
  1949. var isInvoking = shouldInvoke(time);
  1950. for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
  1951. args[_key] = arguments[_key];
  1952. }
  1953. lastArgs = args;
  1954. lastThis = this;
  1955. lastCallTime = time;
  1956. if (isInvoking) {
  1957. if (timerId === undefined) {
  1958. return leadingEdge(lastCallTime);
  1959. }
  1960. if (maxing) {
  1961. // Handle invocations in a tight loop.
  1962. timerId = setTimeout(timerExpired, wait);
  1963. return invokeFunc(lastCallTime);
  1964. }
  1965. }
  1966. if (timerId === undefined) {
  1967. timerId = setTimeout(timerExpired, wait);
  1968. }
  1969. return result;
  1970. }
  1971. debounced.cancel = cancel;
  1972. debounced.flush = flush;
  1973. return debounced;
  1974. }
  1975. /**
  1976. * @method ax5.util.throttle
  1977. * @param func
  1978. * @param wait
  1979. * @param options
  1980. * @return {debounced}
  1981. */
  1982. //https://github.com/lodash/lodash/blob/master/throttle.js
  1983. function throttle(func, wait, options) {
  1984. var leading = true;
  1985. var trailing = true;
  1986. if (typeof func != 'function') {
  1987. throw new TypeError('Expected a function');
  1988. }
  1989. if (isObject(options)) {
  1990. leading = 'leading' in options ? !!options.leading : leading;
  1991. trailing = 'trailing' in options ? !!options.trailing : trailing;
  1992. }
  1993. return debounce(func, wait, {
  1994. 'leading': leading,
  1995. 'maxWait': wait,
  1996. 'trailing': trailing
  1997. });
  1998. }
  1999. /**
  2000. * @method ax5.util.deepCopy
  2001. * @param {Object} obj
  2002. * @returns {Object}
  2003. * @example
  2004. * ```js
  2005. * var obj = [
  2006. * {name:"A", child:[{name:"a-1"}]},
  2007. * {name:"B", child:[{name:"b-1"}], callBack: function(){ console.log('callBack'); }}
  2008. * ];
  2009. * var copiedObj = ax5.util.deepCopy(obj)
  2010. * ```
  2011. */
  2012. function deepCopy(obj) {
  2013. var r, l;
  2014. if ((typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) == 'object') {
  2015. if (U.isArray(obj)) {
  2016. l = obj.length;
  2017. r = new Array(l);
  2018. for (var i = 0; i < l; i++) {
  2019. r[i] = deepCopy(obj[i]);
  2020. }
  2021. return r;
  2022. } else {
  2023. return jQuery.extend({}, obj);
  2024. }
  2025. }
  2026. return obj;
  2027. }
  2028. /**
  2029. * HTML 문자열을 escape 처리합니다.
  2030. * "&lt;" represents the < sign.
  2031. * "&gt;" represents the > sign.
  2032. * "&amp;" represents the & sign.
  2033. * "&quot; represents the " mark.
  2034. * [Character entity references](https://www.w3.org/TR/html401/charset.html#h-5.3)
  2035. * @method ax5.util.escapeHtml
  2036. * @param {String} s
  2037. * @returns {string}
  2038. * @example
  2039. * ```
  2040. * ax5.util.escapeHtml('HTML <span>string</span> & "escape"')
  2041. * //"HTML &lt;span&gt;string&lt;/span&gt; &amp; &quot;escape&quot;"
  2042. * ```
  2043. */
  2044. function escapeHtml(s) {
  2045. if (_toString.call(s) != "[object String]") return s;
  2046. if (!s) return "";
  2047. return s.replace(/[\<\>\&\"]/gm, function (match) {
  2048. switch (match) {
  2049. case "<":
  2050. return "&lt;";
  2051. case ">":
  2052. return "&gt;";
  2053. case "&":
  2054. return "&amp;";
  2055. case "\"":
  2056. return "&quot;";
  2057. default:
  2058. return match;
  2059. }
  2060. });
  2061. }
  2062. /**
  2063. * HTML 문자열을 unescape 처리합니다.
  2064. * escapeHtml를 참고하세요.
  2065. * @method ax5.util.unescapeHtml
  2066. * @param {String} s
  2067. * @returns {string}
  2068. * @example
  2069. * ```
  2070. * ax5.util.unescapeHtml('HTML &lt;span&gt;string&lt;/span&gt; &amp; &quot;escape&quot;')
  2071. * //"HTML <span>string</span> & "escape""
  2072. * ```
  2073. */
  2074. function unescapeHtml(s) {
  2075. if (_toString.call(s) != "[object String]") return s;
  2076. if (!s) return "";
  2077. return s.replace(/(&lt;)|(&gt;)|(&amp;)|(&quot;)/gm, function (match) {
  2078. switch (match) {
  2079. case "&lt;":
  2080. return "<";
  2081. case "&gt;":
  2082. return ">";
  2083. case "&amp;":
  2084. return "&";
  2085. case "&quot;":
  2086. return "\"";
  2087. default:
  2088. return match;
  2089. }
  2090. });
  2091. }
  2092. /**
  2093. * @method ax5.util.string
  2094. * @param {String} tmpl
  2095. * @param {*} args
  2096. * @return {ax5string}
  2097. * @example
  2098. * ```js
  2099. * ax5.util.string("{0} is dead, but {1} is alive! {0} {2}").format("ASP", "ASP.NET");
  2100. * ax5.util.string("{0} is dead, but {1} is alive! {0} {2}").format(["ASP", "ASP.NET"]);
  2101. * ax5.util.stinrg("{0} counts").format(100);
  2102. * ```
  2103. */
  2104. function string(_string) {
  2105. return new function (_string) {
  2106. this.value = _string;
  2107. this.toString = function () {
  2108. return this.value;
  2109. };
  2110. /**
  2111. * @method ax5.util.string.format
  2112. * @returns {*}
  2113. */
  2114. this.format = function () {
  2115. var args = [];
  2116. for (var i = 0, l = arguments.length; i < l; i++) {
  2117. args = args.concat(arguments[i]);
  2118. }
  2119. return this.value.replace(/{(\d+)}/g, function (match, number) {
  2120. return typeof args[number] != 'undefined' ? args[number] : match;
  2121. });
  2122. };
  2123. /**
  2124. * @method ax5.util.string.escape
  2125. * @returns {*}
  2126. */
  2127. this.escape = function () {
  2128. return escapeHtml(this.value);
  2129. };
  2130. /**
  2131. * @method ax5.util.string.unescape
  2132. * @returns {*}
  2133. */
  2134. this.unescape = function () {
  2135. return unescapeHtml(this.value);
  2136. };
  2137. /**
  2138. * @method ax5.util.string.encode
  2139. * @returns {*}
  2140. */
  2141. this.encode = function () {
  2142. return encode(this.value);
  2143. };
  2144. /**
  2145. * @method ax5.util.string.decode
  2146. * @returns {*}
  2147. */
  2148. this.decode = function () {
  2149. return decode(this.value);
  2150. };
  2151. /**
  2152. * @method ax5.util.string.left
  2153. * @param {String|Number} pos - 찾을 문자열 또는 포지션
  2154. * @returns {*}
  2155. */
  2156. this.left = function (_pos) {
  2157. return left(this.value, _pos);
  2158. };
  2159. /**
  2160. * @method ax5.util.string.right
  2161. * @param {String|Number} pos - 찾을 문자열 또는 포지션
  2162. * @returns {*}
  2163. */
  2164. this.right = function (_pos) {
  2165. return right(this.value, _pos);
  2166. };
  2167. /**
  2168. * @method ax5.util.string.camelCase
  2169. * @returns {*}
  2170. */
  2171. this.camelCase = function () {
  2172. return camelCase(this.value);
  2173. };
  2174. /**
  2175. * @method ax5.util.string.snakeCase
  2176. * @returns {*}
  2177. */
  2178. this.snakeCase = function () {
  2179. return snakeCase(this.value);
  2180. };
  2181. }(_string);
  2182. }
  2183. /**
  2184. * @method ax5.util.color
  2185. * @param _hexColor
  2186. * @return {ax5color}
  2187. * @example
  2188. * ```js
  2189. * ax5.util.color("#ff3300").lighten(10).getHexValue()
  2190. * console.log(ax5.util.color("#ff3300").darken(10).getHexValue());
  2191. * ```
  2192. */
  2193. function color(_hexColor) {
  2194. var matchers = function () {
  2195. // <http://www.w3.org/TR/css3-values/#integers>
  2196. var CSS_INTEGER = "[-\\+]?\\d+%?";
  2197. // <http://www.w3.org/TR/css3-values/#number-value>
  2198. var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
  2199. // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
  2200. var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
  2201. // Actual matching.
  2202. // Parentheses and commas are optional, but not required.
  2203. // Whitespace can take the place of commas or opening paren
  2204. var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
  2205. var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
  2206. return {
  2207. CSS_UNIT: new RegExp(CSS_UNIT),
  2208. rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
  2209. rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
  2210. hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
  2211. hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
  2212. hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
  2213. hsva: new RegExp("hsva" + PERMISSIVE_MATCH4),
  2214. hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
  2215. hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
  2216. hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
  2217. hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
  2218. };
  2219. }();
  2220. var convertObject = function convertObject(_color) {
  2221. var match = void 0;
  2222. if (match = matchers.rgb.exec(_color)) {
  2223. return { r: match[1], g: match[2], b: match[3] };
  2224. }
  2225. if (match = matchers.rgba.exec(_color)) {
  2226. return { r: match[1], g: match[2], b: match[3], a: match[4] };
  2227. }
  2228. if (match = matchers.hsl.exec(_color)) {
  2229. return { h: match[1], s: match[2], l: match[3] };
  2230. }
  2231. if (match = matchers.hsla.exec(_color)) {
  2232. return { h: match[1], s: match[2], l: match[3], a: match[4] };
  2233. }
  2234. if (match = matchers.hsv.exec(_color)) {
  2235. return { h: match[1], s: match[2], v: match[3] };
  2236. }
  2237. if (match = matchers.hsva.exec(_color)) {
  2238. return { h: match[1], s: match[2], v: match[3], a: match[4] };
  2239. }
  2240. if (match = matchers.hex8.exec(_color)) {
  2241. return {
  2242. r: parseInt(match[1], 16),
  2243. g: parseInt(match[2], 16),
  2244. b: parseInt(match[3], 16),
  2245. a: parseInt(match[4] / 255, 16),
  2246. format: "hex8"
  2247. };
  2248. }
  2249. if (match = matchers.hex6.exec(_color)) {
  2250. return {
  2251. r: parseInt(match[1], 16),
  2252. g: parseInt(match[2], 16),
  2253. b: parseInt(match[3], 16),
  2254. format: "hex"
  2255. };
  2256. }
  2257. if (match = matchers.hex4.exec(_color)) {
  2258. return {
  2259. r: parseInt(match[1] + '' + match[1], 16),
  2260. g: parseInt(match[2] + '' + match[2], 16),
  2261. b: parseInt(match[3] + '' + match[3], 16),
  2262. a: parseInt(match[4] + '' + match[4], 16),
  2263. format: "hex8"
  2264. };
  2265. }
  2266. if (match = matchers.hex3.exec(_color)) {
  2267. return {
  2268. r: parseInt(match[1] + '' + match[1], 16),
  2269. g: parseInt(match[2] + '' + match[2], 16),
  2270. b: parseInt(match[3] + '' + match[3], 16),
  2271. format: "hex"
  2272. };
  2273. }
  2274. return false;
  2275. };
  2276. function isOnePointZero(n) {
  2277. return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
  2278. }
  2279. function isPercentage(n) {
  2280. return typeof n === "string" && n.indexOf('%') != -1;
  2281. }
  2282. function convertToPercentage(n) {
  2283. if (n <= 1) {
  2284. n = n * 100 + "%";
  2285. }
  2286. return n;
  2287. }
  2288. function convertTo255(n) {
  2289. return ax5.util.number(Math.min(255, Math.max(n, 0)), { 'round': 2 });
  2290. }
  2291. function convertToHex(n) {
  2292. return setDigit(Math.round(n).toString(16), 2);
  2293. }
  2294. function bound01(n, max) {
  2295. if (isOnePointZero(n)) {
  2296. n = "100%";
  2297. }
  2298. var processPercent = isPercentage(n);
  2299. n = Math.min(max, Math.max(0, parseFloat(n)));
  2300. // Automatically convert percentage into number
  2301. if (processPercent) {
  2302. n = parseInt(n * max, 10) / 100;
  2303. }
  2304. // Handle floating point rounding errors
  2305. if (Math.abs(n - max) < 0.000001) {
  2306. return 1;
  2307. }
  2308. // Convert into [0, 1] range if it isn't already
  2309. return n % max / parseFloat(max);
  2310. }
  2311. function rgbToHsl(r, g, b) {
  2312. r = bound01(r, 255);
  2313. g = bound01(g, 255);
  2314. b = bound01(b, 255);
  2315. var max = Math.max(r, g, b),
  2316. min = Math.min(r, g, b);
  2317. var h,
  2318. s,
  2319. l = (max + min) / 2;
  2320. if (max == min) {
  2321. h = s = 0; // achromatic
  2322. } else {
  2323. var d = max - min;
  2324. s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
  2325. switch (max) {
  2326. case r:
  2327. h = (g - b) / d + (g < b ? 6 : 0);
  2328. break;
  2329. case g:
  2330. h = (b - r) / d + 2;
  2331. break;
  2332. case b:
  2333. h = (r - g) / d + 4;
  2334. break;
  2335. }
  2336. h /= 6;
  2337. }
  2338. return { h: h, s: s, l: l };
  2339. }
  2340. function hslToRgb(h, s, l) {
  2341. var r = void 0,
  2342. g = void 0,
  2343. b = void 0;
  2344. h = bound01(h, 360);
  2345. s = bound01(s, 100);
  2346. l = bound01(l, 100);
  2347. function hue2rgb(p, q, t) {
  2348. if (t < 0) t += 1;
  2349. if (t > 1) t -= 1;
  2350. if (t < 1 / 6) return p + (q - p) * 6 * t;
  2351. if (t < 1 / 2) return q;
  2352. if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
  2353. return p;
  2354. }
  2355. if (s === 0) {
  2356. r = g = b = l; // achromatic
  2357. } else {
  2358. var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  2359. var p = 2 * l - q;
  2360. r = hue2rgb(p, q, h + 1 / 3);
  2361. g = hue2rgb(p, q, h);
  2362. b = hue2rgb(p, q, h - 1 / 3);
  2363. }
  2364. return { r: r * 255, g: g * 255, b: b * 255 };
  2365. }
  2366. return new function (_color) {
  2367. this._originalValue = _color;
  2368. _color = convertObject(_color);
  2369. this.r = _color.r;
  2370. this.g = _color.g;
  2371. this.b = _color.b;
  2372. this.a = _color.a || 1;
  2373. this._format = _color.format;
  2374. this._hex = convertToHex(this.r) + convertToHex(this.g) + convertToHex(this.b);
  2375. this.getHexValue = function () {
  2376. return this._hex;
  2377. };
  2378. this.lighten = function (amount) {
  2379. amount = amount === 0 ? 0 : amount || 10;
  2380. var hsl = rgbToHsl(this.r, this.g, this.b),
  2381. rgb = {};
  2382. hsl.l += amount / 100;
  2383. hsl.l = Math.min(1, Math.max(0, hsl.l));
  2384. hsl.h = hsl.h * 360;
  2385. rgb = hslToRgb(hsl.h, convertToPercentage(hsl.s), convertToPercentage(hsl.l));
  2386. return color('rgba(' + convertTo255(rgb.r) + ', ' + convertTo255(rgb.g) + ', ' + convertTo255(rgb.b) + ', ' + this.a + ')');
  2387. };
  2388. this.darken = function (amount) {
  2389. amount = amount === 0 ? 0 : amount || 10;
  2390. var hsl = rgbToHsl(this.r, this.g, this.b),
  2391. rgb = {};
  2392. hsl.l -= amount / 100;
  2393. hsl.l = Math.min(1, Math.max(0, hsl.l));
  2394. hsl.h = hsl.h * 360;
  2395. rgb = hslToRgb(hsl.h, convertToPercentage(hsl.s), convertToPercentage(hsl.l));
  2396. return color('rgba(' + convertTo255(rgb.r) + ', ' + convertTo255(rgb.g) + ', ' + convertTo255(rgb.b) + ', ' + this.a + ')');
  2397. };
  2398. this.getBrightness = function () {
  2399. return (this.r * 299 + this.g * 587 + this.b * 114) / 1000;
  2400. };
  2401. this.isDark = function () {
  2402. return this.getBrightness() < 128;
  2403. };
  2404. this.isLight = function () {
  2405. return !this.isDark();
  2406. };
  2407. this.getHsl = function () {
  2408. var hsl = rgbToHsl(this.r, this.g, this.b);
  2409. hsl.l = Math.min(1, Math.max(0, hsl.l));
  2410. hsl.h = hsl.h * 360;
  2411. return {
  2412. h: hsl.h,
  2413. s: hsl.s,
  2414. l: hsl.l
  2415. };
  2416. };
  2417. }(_hexColor);
  2418. }
  2419. return {
  2420. alert: alert,
  2421. each: each,
  2422. map: map,
  2423. search: search,
  2424. reduce: reduce,
  2425. reduceRight: reduceRight,
  2426. filter: filter,
  2427. sum: sum,
  2428. avg: avg,
  2429. toJson: toJson,
  2430. parseJson: parseJson,
  2431. first: first,
  2432. last: last,
  2433. deepCopy: deepCopy,
  2434. left: left,
  2435. right: right,
  2436. getType: getType,
  2437. isWindow: isWindow,
  2438. isElement: isElement,
  2439. isObject: isObject,
  2440. isArray: isArray,
  2441. isFunction: isFunction,
  2442. isString: isString,
  2443. isNumber: isNumber,
  2444. isNodelist: isNodelist,
  2445. isUndefined: isUndefined,
  2446. isNothing: isNothing,
  2447. setCookie: setCookie,
  2448. getCookie: getCookie,
  2449. camelCase: camelCase,
  2450. snakeCase: snakeCase,
  2451. number: number,
  2452. toArray: toArray,
  2453. merge: merge,
  2454. param: param,
  2455. error: error,
  2456. date: date,
  2457. dday: dday,
  2458. daysOfMonth: daysOfMonth,
  2459. weeksOfMonth: weeksOfMonth,
  2460. setDigit: setDigit,
  2461. times: times,
  2462. findParentNode: findParentNode,
  2463. cssNumber: cssNumber,
  2464. css: css,
  2465. isDate: isDate,
  2466. isDateFormat: isDateFormat,
  2467. stopEvent: stopEvent,
  2468. selectRange: selectRange,
  2469. debounce: debounce,
  2470. throttle: throttle,
  2471. escapeHtml: escapeHtml,
  2472. unescapeHtml: unescapeHtml,
  2473. string: string,
  2474. color: color
  2475. };
  2476. }();
  2477. if ((typeof module === 'undefined' ? 'undefined' : _typeof(module)) === "object" && _typeof(module.exports) === "object") {
  2478. module.exports = ax5;
  2479. } else {
  2480. root.ax5 = function () {
  2481. return ax5;
  2482. }(); // ax5.ui에 연결
  2483. }
  2484. }).call(typeof window !== "undefined" ? window : undefined);
  2485. ax5.def = {};
  2486. ax5.info.errorMsg["ax5dialog"] = {
  2487. "501": "Duplicate call error"
  2488. };
  2489. ax5.info.errorMsg["ax5picker"] = {
  2490. "401": "Can not find target element",
  2491. "402": "Can not find boundID",
  2492. "501": "Can not find content key"
  2493. };
  2494. ax5.info.errorMsg["single-uploader"] = {
  2495. "460": "There are no files to be uploaded.",
  2496. "461": "There is no uploaded files."
  2497. };
  2498. ax5.info.errorMsg["ax5calendar"] = {
  2499. "401": "Can not find target element"
  2500. };
  2501. ax5.info.errorMsg["ax5formatter"] = {
  2502. "401": "Can not find target element",
  2503. "402": "Can not find boundID",
  2504. "501": "Can not find pattern"
  2505. };
  2506. ax5.info.errorMsg["ax5menu"] = {
  2507. "501": "Can not find menu item"
  2508. };
  2509. ax5.info.errorMsg["ax5select"] = {
  2510. "401": "Can not find target element",
  2511. "402": "Can not find boundID",
  2512. "501": "Can not find option"
  2513. };
  2514. ax5.info.errorMsg["ax5combobox"] = {
  2515. "401": "Can not find target element",
  2516. "402": "Can not find boundID",
  2517. "501": "Can not find option"
  2518. };
  2519. // 필수 Ployfill 확장 구문
  2520. (function () {
  2521. 'use strict';
  2522. var root = this,
  2523. re_trim = /^\s*|\s*$/g;
  2524. // From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
  2525. if (!Object.keys) {
  2526. Object.keys = function () {
  2527. var hwp = Object.prototype.hasOwnProperty,
  2528. hdeb = !{ toString: null }.propertyIsEnumerable('toString'),
  2529. de = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor'],
  2530. del = de.length;
  2531. return function (obj) {
  2532. if ((typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) !== 'object' && (typeof obj !== 'function' || obj === null)) throw new TypeError('type err');
  2533. var r = [],
  2534. prop,
  2535. i;
  2536. for (prop in obj) {
  2537. if (hwp.call(obj, prop)) r.push(prop);
  2538. }if (hdeb) {
  2539. for (i = 0; i < del; i++) {
  2540. if (hwp.call(obj, de[i])) r.push(de[i]);
  2541. }
  2542. }
  2543. return r;
  2544. };
  2545. }();
  2546. }
  2547. // ES5 15.4.4.18 Array.prototype.forEach ( callbackfn [ , thisArg ] )
  2548. // From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach
  2549. if (!Array.prototype.forEach) {
  2550. Array.prototype.forEach = function (fun /*, thisp */) {
  2551. if (this === void 0 || this === null) {
  2552. throw TypeError();
  2553. }
  2554. var t = Object(this);
  2555. var len = t.length >>> 0;
  2556. if (typeof fun !== "function") {
  2557. throw TypeError();
  2558. }
  2559. var thisp = arguments[1],
  2560. i;
  2561. for (i = 0; i < len; i++) {
  2562. if (i in t) {
  2563. fun.call(thisp, t[i], i, t);
  2564. }
  2565. }
  2566. };
  2567. }
  2568. // ES5 15.3.4.5 Function.prototype.bind ( thisArg [, arg1 [, arg2, ... ]] )
  2569. // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
  2570. if (!Function.prototype.bind) {
  2571. Function.prototype.bind = function (o) {
  2572. if (typeof this !== 'function') {
  2573. throw TypeError("function");
  2574. }
  2575. var slice = [].slice,
  2576. args = slice.call(arguments, 1),
  2577. self = this,
  2578. bound = function bound() {
  2579. return self.apply(this instanceof nop ? this : o, args.concat(slice.call(arguments)));
  2580. };
  2581. function nop() {}
  2582. nop.prototype = self.prototype;
  2583. bound.prototype = new nop();
  2584. return bound;
  2585. };
  2586. }
  2587. /*global document */
  2588. /**
  2589. * define document.querySelector & document.querySelectorAll for IE7
  2590. *
  2591. * A not very fast but small hack. The approach is taken from
  2592. * http://weblogs.asp.net/bleroy/archive/2009/08/31/queryselectorall-on-old-ie-versions-something-that-doesn-t-work.aspx
  2593. *
  2594. */
  2595. (function () {
  2596. if (document.querySelectorAll || document.querySelector) {
  2597. return;
  2598. }
  2599. if (!document.createStyleSheet) return;
  2600. var style = document.createStyleSheet(),
  2601. select = function select(selector, maxCount) {
  2602. var all = document.all,
  2603. l = all.length,
  2604. i,
  2605. resultSet = [];
  2606. style.addRule(selector, "foo:bar");
  2607. for (i = 0; i < l; i += 1) {
  2608. if (all[i].currentStyle.foo === "bar") {
  2609. resultSet.push(all[i]);
  2610. if (resultSet.length > maxCount) {
  2611. break;
  2612. }
  2613. }
  2614. }
  2615. style.removeRule(0);
  2616. return resultSet;
  2617. };
  2618. document.querySelectorAll = function (selector) {
  2619. return select(selector, Infinity);
  2620. };
  2621. document.querySelector = function (selector) {
  2622. return select(selector, 1)[0] || null;
  2623. };
  2624. })();
  2625. if (!String.prototype.trim) {
  2626. (function () {
  2627. String.prototype.trim = function () {
  2628. return this.replace(re_trim, '');
  2629. };
  2630. })();
  2631. }
  2632. if (!window.JSON) {
  2633. window.JSON = {
  2634. parse: function parse(sJSON) {
  2635. return new Function('', 'return ' + sJSON)();
  2636. },
  2637. stringify: function () {
  2638. var r = /["]/g,
  2639. _f;
  2640. return _f = function f(vContent) {
  2641. var result, i, j;
  2642. switch (result = typeof vContent === 'undefined' ? 'undefined' : _typeof(vContent)) {
  2643. case 'string':
  2644. return '"' + vContent.replace(r, '\\"') + '"';
  2645. case 'number':
  2646. case 'boolean':
  2647. return vContent.toString();
  2648. case 'undefined':
  2649. return 'undefined';
  2650. case 'function':
  2651. return '""';
  2652. case 'object':
  2653. if (!vContent) return 'null';
  2654. result = '';
  2655. if (vContent.splice) {
  2656. for (i = 0, j = vContent.length; i < j; i++) {
  2657. result += ',' + _f(vContent[i]);
  2658. }return '[' + result.substr(1) + ']';
  2659. } else {
  2660. for (i in vContent) {
  2661. if (vContent.hasOwnProperty(i) && vContent[i] !== undefined && typeof vContent[i] != 'function') result += ',"' + i + '":' + _f(vContent[i]);
  2662. }return '{' + result.substr(1) + '}';
  2663. }
  2664. }
  2665. };
  2666. }()
  2667. };
  2668. }
  2669. // splice ie8 <= polyfill
  2670. (function () {
  2671. if (!document.documentMode || document.documentMode >= 9) return false;
  2672. var _splice = Array.prototype.splice;
  2673. Array.prototype.splice = function () {
  2674. var args = Array.prototype.slice.call(arguments);
  2675. if (typeof args[1] === "undefined") args[1] = this.length - args[0];
  2676. return _splice.apply(this, args);
  2677. };
  2678. })();
  2679. /**
  2680. * Shim for "fixing" IE's lack of support (IE < 9) for applying slice
  2681. * on host objects like NamedNodeMap, NodeList, and HTMLCollection
  2682. * (technically, since host objects have been implementation-dependent,
  2683. * at least before ES6, IE hasn't needed to work this way).
  2684. * Also works on strings, fixes IE < 9 to allow an explicit undefined
  2685. * for the 2nd argument (as in Firefox), and prevents errors when
  2686. * called on other DOM objects.
  2687. */
  2688. (function () {
  2689. 'use strict';
  2690. var _slice = Array.prototype.slice;
  2691. try {
  2692. // Can't be used with DOM elements in IE < 9
  2693. _slice.call(document.documentElement);
  2694. } catch (e) {
  2695. // Fails in IE < 9
  2696. // This will work for genuine arrays, array-like objects,
  2697. // NamedNodeMap (attributes, entities, notations),
  2698. // NodeList (e.g., getElementsByTagName), HTMLCollection (e.g., childNodes),
  2699. // and will not fail on other DOM objects (as do DOM elements in IE < 9)
  2700. Array.prototype.slice = function (begin, end) {
  2701. // IE < 9 gets unhappy with an undefined end argument
  2702. end = typeof end !== 'undefined' ? end : this.length;
  2703. // For native Array objects, we use the native slice function
  2704. if (Object.prototype.toString.call(this) === '[object Array]') {
  2705. return _slice.call(this, begin, end);
  2706. }
  2707. // For array like object we handle it ourselves.
  2708. var i,
  2709. cloned = [],
  2710. size,
  2711. len = this.length;
  2712. // Handle negative value for "begin"
  2713. var start = begin || 0;
  2714. start = start >= 0 ? start : Math.max(0, len + start);
  2715. // Handle negative value for "end"
  2716. var upTo = typeof end == 'number' ? Math.min(end, len) : len;
  2717. if (end < 0) {
  2718. upTo = len + end;
  2719. }
  2720. // Actual expected size of the slice
  2721. size = upTo - start;
  2722. if (size > 0) {
  2723. cloned = new Array(size);
  2724. if (this.charAt) {
  2725. for (i = 0; i < size; i++) {
  2726. cloned[i] = this.charAt(start + i);
  2727. }
  2728. } else {
  2729. for (i = 0; i < size; i++) {
  2730. cloned[i] = this[start + i];
  2731. }
  2732. }
  2733. }
  2734. return cloned;
  2735. };
  2736. }
  2737. })();
  2738. // Console-polyfill. MIT license. https://github.com/paulmillr/console-polyfill
  2739. // Make it safe to do console.log() always.
  2740. (function (con) {
  2741. var prop, method;
  2742. var empty = {};
  2743. var dummy = function dummy() {};
  2744. var properties = 'memory'.split(',');
  2745. var methods = ('assert,clear,count,debug,dir,dirxml,error,exception,group,' + 'groupCollapsed,groupEnd,info,log,markTimeline,profile,profiles,profileEnd,' + 'show,table,time,timeEnd,timeline,timelineEnd,timeStamp,trace,warn').split(',');
  2746. while (prop = properties.pop()) {
  2747. con[prop] = con[prop] || empty;
  2748. }while (method = methods.pop()) {
  2749. con[method] = con[method] || dummy;
  2750. }
  2751. })(window.console || {}); // Using `this` for web workers.
  2752. // Modernizr style test
  2753. if (!(window.webkitMatchMedia || window.mozMatchMedia || window.oMatchMedia || window.msMatchMedia || window.matchMedia)) {
  2754. var root = document.getElementsByTagName('html')[0];
  2755. root.className += ' no-matchmedia';
  2756. }
  2757. /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */
  2758. window.matchMedia || (window.matchMedia = function () {
  2759. "use strict";
  2760. // For browsers that support matchMedium api such as IE 9 and webkit
  2761. var styleMedia = window.styleMedia || window.media;
  2762. // For those that don't support matchMedium
  2763. if (!styleMedia) {
  2764. var style = document.createElement('style'),
  2765. script = document.getElementsByTagName('script')[0],
  2766. info = null;
  2767. style.type = 'text/css';
  2768. style.id = 'matchmediajs-test';
  2769. script.parentNode.insertBefore(style, script);
  2770. // 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers
  2771. info = 'getComputedStyle' in window && window.getComputedStyle(style, null) || style.currentStyle;
  2772. styleMedia = {
  2773. matchMedium: function matchMedium(media) {
  2774. var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }';
  2775. // 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers
  2776. if (style.styleSheet) {
  2777. style.styleSheet.cssText = text;
  2778. } else {
  2779. style.textContent = text;
  2780. }
  2781. // Test if media query is true or false
  2782. return info.width === '1px';
  2783. }
  2784. };
  2785. }
  2786. return function (media) {
  2787. return {
  2788. matches: styleMedia.matchMedium(media || 'all'),
  2789. media: media || 'all'
  2790. };
  2791. };
  2792. }());
  2793. /*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */
  2794. (function () {
  2795. // Bail out for browsers that have addListener support
  2796. if (window.matchMedia && window.matchMedia('all').addListener) {
  2797. return false;
  2798. }
  2799. var localMatchMedia = window.matchMedia,
  2800. hasMediaQueries = localMatchMedia('only all').matches,
  2801. isListening = false,
  2802. timeoutID = 0,
  2803. // setTimeout for debouncing 'handleChange'
  2804. queries = [],
  2805. // Contains each 'mql' and associated 'listeners' if 'addListener' is used
  2806. handleChange = function handleChange(evt) {
  2807. // Debounce
  2808. clearTimeout(timeoutID);
  2809. timeoutID = setTimeout(function () {
  2810. for (var i = 0, il = queries.length; i < il; i++) {
  2811. var mql = queries[i].mql,
  2812. listeners = queries[i].listeners || [],
  2813. matches = localMatchMedia(mql.media).matches;
  2814. // Update mql.matches value and call listeners
  2815. // Fire listeners only if transitioning to or from matched state
  2816. if (matches !== mql.matches) {
  2817. mql.matches = matches;
  2818. for (var j = 0, jl = listeners.length; j < jl; j++) {
  2819. listeners[j].call(window, mql);
  2820. }
  2821. }
  2822. }
  2823. }, 30);
  2824. };
  2825. window.matchMedia = function (media) {
  2826. var mql = localMatchMedia(media),
  2827. listeners = [],
  2828. index = 0;
  2829. mql.addListener = function (listener) {
  2830. // Changes would not occur to css media type so return now (Affects IE <= 8)
  2831. if (!hasMediaQueries) {
  2832. return;
  2833. }
  2834. // Set up 'resize' listener for browsers that support CSS3 media queries (Not for IE <= 8)
  2835. // There should only ever be 1 resize listener running for performance
  2836. if (!isListening) {
  2837. isListening = true;
  2838. window.addEventListener('resize', handleChange, true);
  2839. }
  2840. // Push object only if it has not been pushed already
  2841. if (index === 0) {
  2842. index = queries.push({
  2843. mql: mql,
  2844. listeners: listeners
  2845. });
  2846. }
  2847. listeners.push(listener);
  2848. };
  2849. mql.removeListener = function (listener) {
  2850. for (var i = 0, il = listeners.length; i < il; i++) {
  2851. if (listeners[i] === listener) {
  2852. listeners.splice(i, 1);
  2853. }
  2854. }
  2855. };
  2856. return mql;
  2857. };
  2858. })();
  2859. // extend innerWidth ..
  2860. var html = document.getElementsByTagName('html')[0];
  2861. var body = document.getElementsByTagName('body')[0];
  2862. /*
  2863. if (!window.innerWidth) window.innerWidth = html.clientWidth;
  2864. if (!window.innerHeight) window.innerHeight = html.clientHeight;
  2865. if (!window.scrollX) window.scrollX = window.pageXOffset || html.scrollLeft;
  2866. if (!window.scrollY) window.scrollY = window.pageYOffset || html.scrollTop;
  2867. */
  2868. }).call(window);
  2869. /**
  2870. * Refer to this by {@link ax5}.
  2871. * @namespace ax5.ui
  2872. */
  2873. /**
  2874. * @class ax5.ui.root
  2875. * @classdesc ax5 ui class
  2876. * @author tom@axisj.com
  2877. * @example
  2878. * ```
  2879. * var myui = new ax5.ui.root();
  2880. * ```
  2881. */
  2882. ax5.ui = function () {
  2883. function axUi() {
  2884. this.config = {};
  2885. this.name = "root";
  2886. /**
  2887. * 클래스의 속성 정의 메소드 속성 확장후에 내부에 init 함수를 호출합니다.
  2888. * @method ax5.ui.root.setConfig
  2889. * @param {Object} config - 클래스 속성값
  2890. * @param {Boolean} [callInit=true] - init 함수 호출 여부
  2891. * @returns {ax5.ui.axUi}
  2892. * @example
  2893. * ```
  2894. * var myui = new ax5.ui.root();
  2895. * myui.setConfig({
  2896. * id:"abcd"
  2897. * });
  2898. * ```
  2899. */
  2900. this.setConfig = function (cfg, callInit) {
  2901. jQuery.extend(true, this.config, cfg);
  2902. if (typeof callInit == "undefined" || callInit === true) {
  2903. this.init();
  2904. }
  2905. return this;
  2906. };
  2907. this.init = function () {
  2908. console.log(this.config);
  2909. };
  2910. this.bindWindowResize = function (callBack) {
  2911. setTimeout(function () {
  2912. jQuery(window).resize(function () {
  2913. if (this.bindWindowResize__) clearTimeout(this.bindWindowResize__);
  2914. this.bindWindowResize__ = setTimeout(function () {
  2915. callBack.call(this);
  2916. }.bind(this), 10);
  2917. }.bind(this));
  2918. }.bind(this), 100);
  2919. };
  2920. this.stopEvent = function (e) {
  2921. if (e.preventDefault) e.preventDefault();
  2922. if (e.stopPropagation) e.stopPropagation();
  2923. e.cancelBubble = true;
  2924. return false;
  2925. };
  2926. this.toString = function () {
  2927. return this.name + '@' + this.version;
  2928. };
  2929. // instance init
  2930. this.main = function () {}.apply(this, arguments);
  2931. }
  2932. /**
  2933. * @method ax5.ui.addClass
  2934. * @param {Object} config
  2935. * @param {String} config.className - name of Class
  2936. * @param {Object} [config.classStore=ax5.ui] - 클래스가 저장될 경로
  2937. * @param {Function} [config.superClass=ax5.ui.root]
  2938. * @param {Function} cls - Class Function
  2939. */
  2940. function addClass(config, cls) {
  2941. if (!config || !config.className) throw 'invalid call';
  2942. var classStore = config.classStore ? config.classStore : ax5.ui;
  2943. if (!classStore) throw 'invalid classStore';
  2944. // make ui definition variable
  2945. ax5.def[config.className] = {
  2946. version: ax5.info.version
  2947. };
  2948. var factory = function factory(cls, arg) {
  2949. switch (arg.length) {
  2950. case 0:
  2951. return new cls();
  2952. break;
  2953. case 1:
  2954. return new cls(arg[0]);
  2955. break;
  2956. case 2:
  2957. return new cls(arg[0], arg[1]);
  2958. break;
  2959. case 3:
  2960. return new cls(arg[0], arg[1], arg[2]);
  2961. break;
  2962. }
  2963. };
  2964. var initInstance = function initInstance(name, version, instance) {
  2965. instance.name = name;
  2966. instance.version = version;
  2967. instance.instanceId = ax5.getGuid();
  2968. return instance;
  2969. };
  2970. var initPrototype = function initPrototype(cls) {
  2971. var superClass = config.superClass ? config.superClass : ax5.ui.root;
  2972. if (!ax5.util.isFunction(superClass)) throw 'invalid superClass';
  2973. superClass.call(this); // 부모호출
  2974. cls.prototype = new superClass(); // 상속
  2975. };
  2976. var wrapper = function wrapper() {
  2977. if (!this || !(this instanceof wrapper)) throw 'invalid call';
  2978. var instance = factory(cls, arguments);
  2979. return initInstance(config.className, config.version || "", instance);
  2980. };
  2981. initPrototype.call(this, cls);
  2982. classStore[config.className] = wrapper;
  2983. }
  2984. return {
  2985. root: axUi,
  2986. addClass: addClass
  2987. };
  2988. }();
  2989. /*!
  2990. * mustache.js - Logic-less {{mustache}} templates with JavaScript
  2991. * http://github.com/janl/mustache.js
  2992. * https://github.com/thomasJang/mustache.js -- imporove some variables
  2993. */
  2994. (function defineMustache(global, factory) {
  2995. factory(global.mustache = {});
  2996. })(window.ax5, function mustacheFactory(mustache) {
  2997. var objectToString = Object.prototype.toString;
  2998. var isArray = Array.isArray || function isArrayPolyfill(object) {
  2999. return objectToString.call(object) === '[object Array]';
  3000. };
  3001. function isFunction(object) {
  3002. return typeof object === 'function';
  3003. }
  3004. /**
  3005. * More correct typeof string handling array
  3006. * which normally returns typeof 'object'
  3007. */
  3008. function typeStr(obj) {
  3009. return isArray(obj) ? 'array' : typeof obj === 'undefined' ? 'undefined' : _typeof(obj);
  3010. }
  3011. function escapeRegExp(string) {
  3012. return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
  3013. }
  3014. /**
  3015. * Null safe way of checking whether or not an object,
  3016. * including its prototype, has a given property
  3017. */
  3018. function hasProperty(obj, propName) {
  3019. return obj != null && (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' && propName in obj;
  3020. }
  3021. // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
  3022. // See https://github.com/janl/mustache.js/issues/189
  3023. var regExpTest = RegExp.prototype.test;
  3024. function testRegExp(re, string) {
  3025. return regExpTest.call(re, string);
  3026. }
  3027. var nonSpaceRe = /\S/;
  3028. function isWhitespace(string) {
  3029. return !testRegExp(nonSpaceRe, string);
  3030. }
  3031. var entityMap = {
  3032. '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;', '/': '&#x2F;'
  3033. };
  3034. function escapeHtml(string) {
  3035. return String(string).replace(/[&<>"'\/]/g, function fromEntityMap(s) {
  3036. return entityMap[s];
  3037. });
  3038. }
  3039. var whiteRe = /\s*/;
  3040. var spaceRe = /\s+/;
  3041. var equalsRe = /\s*=/;
  3042. var curlyRe = /\s*\}/;
  3043. var tagRe = /#|\^|\/|>|\{|&|=|!/;
  3044. /**
  3045. * Breaks up the given `template` string into a tree of tokens. If the `tags`
  3046. * argument is given here it must be an array with two string values: the
  3047. * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
  3048. * course, the default is to use mustaches (i.e. mustache.tags).
  3049. *
  3050. * A token is an array with at least 4 elements. The first element is the
  3051. * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
  3052. * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
  3053. * all text that appears outside a symbol this element is "text".
  3054. *
  3055. * The second element of a token is its "value". For mustache tags this is
  3056. * whatever else was inside the tag besides the opening symbol. For text tokens
  3057. * this is the text itself.
  3058. *
  3059. * The third and fourth elements of the token are the start and end indices,
  3060. * respectively, of the token in the original template.
  3061. *
  3062. * Tokens that are the root node of a subtree contain two more elements: 1) an
  3063. * array of tokens in the subtree and 2) the index in the original template at
  3064. * which the closing tag for that section begins.
  3065. */
  3066. function parseTemplate(template, tags) {
  3067. if (!template) return [];
  3068. var sections = []; // Stack to hold section tokens
  3069. var tokens = []; // Buffer to hold the tokens
  3070. var spaces = []; // Indices of whitespace tokens on the current line
  3071. var hasTag = false; // Is there a {{tag}} on the current line?
  3072. var nonSpace = false; // Is there a non-space char on the current line?
  3073. // Strips all whitespace tokens array for the current line
  3074. // if there was a {{#tag}} on it and otherwise only space.
  3075. function stripSpace() {
  3076. if (hasTag && !nonSpace) {
  3077. while (spaces.length) {
  3078. delete tokens[spaces.pop()];
  3079. }
  3080. } else {
  3081. spaces = [];
  3082. }
  3083. hasTag = false;
  3084. nonSpace = false;
  3085. }
  3086. var openingTagRe, closingTagRe, closingCurlyRe;
  3087. function compileTags(tagsToCompile) {
  3088. if (typeof tagsToCompile === 'string') tagsToCompile = tagsToCompile.split(spaceRe, 2);
  3089. if (!isArray(tagsToCompile) || tagsToCompile.length !== 2) throw new Error('Invalid tags: ' + tagsToCompile);
  3090. openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*');
  3091. closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1]));
  3092. closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1]));
  3093. }
  3094. compileTags(tags || mustache.tags);
  3095. var scanner = new Scanner(template);
  3096. var start, type, value, chr, token, openSection;
  3097. while (!scanner.eos()) {
  3098. start = scanner.pos;
  3099. // Match any text between tags.
  3100. value = scanner.scanUntil(openingTagRe);
  3101. if (value) {
  3102. for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
  3103. chr = value.charAt(i);
  3104. if (isWhitespace(chr)) {
  3105. spaces.push(tokens.length);
  3106. } else {
  3107. nonSpace = true;
  3108. }
  3109. tokens.push(['text', chr, start, start + 1]);
  3110. start += 1;
  3111. // Check for whitespace on the current line.
  3112. if (chr === '\n') stripSpace();
  3113. }
  3114. }
  3115. // Match the opening tag.
  3116. if (!scanner.scan(openingTagRe)) break;
  3117. hasTag = true;
  3118. // Get the tag type.
  3119. type = scanner.scan(tagRe) || 'name';
  3120. scanner.scan(whiteRe);
  3121. // Get the tag value.
  3122. if (type === '=') {
  3123. value = scanner.scanUntil(equalsRe);
  3124. scanner.scan(equalsRe);
  3125. scanner.scanUntil(closingTagRe);
  3126. } else if (type === '{') {
  3127. value = scanner.scanUntil(closingCurlyRe);
  3128. scanner.scan(curlyRe);
  3129. scanner.scanUntil(closingTagRe);
  3130. type = '&';
  3131. } else {
  3132. value = scanner.scanUntil(closingTagRe);
  3133. }
  3134. // Match the closing tag.
  3135. if (!scanner.scan(closingTagRe)) throw new Error('Unclosed tag at ' + scanner.pos);
  3136. token = [type, value, start, scanner.pos];
  3137. tokens.push(token);
  3138. if (type === '#' || type === '^') {
  3139. sections.push(token);
  3140. } else if (type === '/') {
  3141. // Check section nesting.
  3142. openSection = sections.pop();
  3143. if (!openSection) throw new Error('Unopened section "' + value + '" at ' + start);
  3144. if (openSection[1] !== value) throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
  3145. } else if (type === 'name' || type === '{' || type === '&') {
  3146. nonSpace = true;
  3147. } else if (type === '=') {
  3148. // Set the tags for the next time around.
  3149. compileTags(value);
  3150. }
  3151. }
  3152. // Make sure there are no open sections when we're done.
  3153. openSection = sections.pop();
  3154. if (openSection) throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
  3155. return nestTokens(squashTokens(tokens));
  3156. }
  3157. /**
  3158. * Combines the values of consecutive text tokens in the given `tokens` array
  3159. * to a single token.
  3160. */
  3161. function squashTokens(tokens) {
  3162. var squashedTokens = [];
  3163. var token, lastToken;
  3164. for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
  3165. token = tokens[i];
  3166. if (token) {
  3167. if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
  3168. lastToken[1] += token[1];
  3169. lastToken[3] = token[3];
  3170. } else {
  3171. squashedTokens.push(token);
  3172. lastToken = token;
  3173. }
  3174. }
  3175. }
  3176. return squashedTokens;
  3177. }
  3178. /**
  3179. * Forms the given array of `tokens` into a nested tree structure where
  3180. * tokens that represent a section have two additional items: 1) an array of
  3181. * all tokens that appear in that section and 2) the index in the original
  3182. * template that represents the end of that section.
  3183. */
  3184. function nestTokens(tokens) {
  3185. var nestedTokens = [];
  3186. var collector = nestedTokens;
  3187. var sections = [];
  3188. var token, section;
  3189. for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
  3190. token = tokens[i];
  3191. switch (token[0]) {
  3192. case '#':
  3193. case '^':
  3194. collector.push(token);
  3195. sections.push(token);
  3196. collector = token[4] = [];
  3197. break;
  3198. case '/':
  3199. section = sections.pop();
  3200. section[5] = token[2];
  3201. collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
  3202. break;
  3203. default:
  3204. collector.push(token);
  3205. }
  3206. }
  3207. return nestedTokens;
  3208. }
  3209. /**
  3210. * A simple string scanner that is used by the template parser to find
  3211. * tokens in template strings.
  3212. */
  3213. function Scanner(string) {
  3214. this.string = string;
  3215. this.tail = string;
  3216. this.pos = 0;
  3217. }
  3218. /**
  3219. * Returns `true` if the tail is empty (end of string).
  3220. */
  3221. Scanner.prototype.eos = function eos() {
  3222. return this.tail === '';
  3223. };
  3224. /**
  3225. * Tries to match the given regular expression at the current position.
  3226. * Returns the matched text if it can match, the empty string otherwise.
  3227. */
  3228. Scanner.prototype.scan = function scan(re) {
  3229. var match = this.tail.match(re);
  3230. if (!match || match.index !== 0) return '';
  3231. var string = match[0];
  3232. this.tail = this.tail.substring(string.length);
  3233. this.pos += string.length;
  3234. return string;
  3235. };
  3236. /**
  3237. * Skips all text until the given regular expression can be matched. Returns
  3238. * the skipped string, which is the entire tail if no match can be made.
  3239. */
  3240. Scanner.prototype.scanUntil = function scanUntil(re) {
  3241. var index = this.tail.search(re),
  3242. match;
  3243. switch (index) {
  3244. case -1:
  3245. match = this.tail;
  3246. this.tail = '';
  3247. break;
  3248. case 0:
  3249. match = '';
  3250. break;
  3251. default:
  3252. match = this.tail.substring(0, index);
  3253. this.tail = this.tail.substring(index);
  3254. }
  3255. this.pos += match.length;
  3256. return match;
  3257. };
  3258. /**
  3259. * Represents a rendering context by wrapping a view object and
  3260. * maintaining a reference to the parent context.
  3261. */
  3262. function Context(view, parentContext) {
  3263. this.view = view;
  3264. this.cache = {
  3265. '.': this.view,
  3266. '@each': function each() {
  3267. var returns = [];
  3268. for (var k in this) {
  3269. returns.push({ '@key': k, '@value': this[k] });
  3270. }
  3271. return returns;
  3272. }
  3273. };
  3274. this.parent = parentContext;
  3275. }
  3276. /**
  3277. * Creates a new context using the given view with this context
  3278. * as the parent.
  3279. */
  3280. Context.prototype.push = function push(view) {
  3281. return new Context(view, this);
  3282. };
  3283. /**
  3284. * Returns the value of the given name in this context, traversing
  3285. * up the context hierarchy if the value is absent in this context's view.
  3286. */
  3287. Context.prototype.lookup = function lookup(name) {
  3288. var cache = this.cache;
  3289. var value;
  3290. if (cache.hasOwnProperty(name)) {
  3291. value = cache[name];
  3292. } else {
  3293. var context = this,
  3294. names,
  3295. index,
  3296. lookupHit = false;
  3297. while (context) {
  3298. if (name.indexOf('.') > 0) {
  3299. value = context.view;
  3300. names = name.split('.');
  3301. index = 0;
  3302. /**
  3303. * Using the dot notion path in `name`, we descend through the
  3304. * nested objects.
  3305. *
  3306. * To be certain that the lookup has been successful, we have to
  3307. * check if the last object in the path actually has the property
  3308. * we are looking for. We store the result in `lookupHit`.
  3309. *
  3310. * This is specially necessary for when the value has been set to
  3311. * `undefined` and we want to avoid looking up parent contexts.
  3312. **/
  3313. while (value != null && index < names.length) {
  3314. if (index === names.length - 1) lookupHit = hasProperty(value, names[index]);
  3315. value = value[names[index++]];
  3316. }
  3317. } else {
  3318. value = context.view[name];
  3319. lookupHit = hasProperty(context.view, name);
  3320. }
  3321. if (lookupHit) break;
  3322. context = context.parent;
  3323. }
  3324. cache[name] = value;
  3325. }
  3326. if (isFunction(value)) value = value.call(this.view);
  3327. return value;
  3328. };
  3329. /**
  3330. * A Writer knows how to take a stream of tokens and render them to a
  3331. * string, given a context. It also maintains a cache of templates to
  3332. * avoid the need to parse the same template twice.
  3333. */
  3334. function Writer() {
  3335. this.cache = {};
  3336. }
  3337. /**
  3338. * Clears all cached templates in this writer.
  3339. */
  3340. Writer.prototype.clearCache = function clearCache() {
  3341. this.cache = {};
  3342. };
  3343. /**
  3344. * Parses and caches the given `template` and returns the array of tokens
  3345. * that is generated from the parse.
  3346. */
  3347. Writer.prototype.parse = function parse(template, tags) {
  3348. var cache = this.cache;
  3349. var tokens = cache[template];
  3350. if (tokens == null) tokens = cache[template] = parseTemplate(template, tags);
  3351. return tokens;
  3352. };
  3353. /**
  3354. * High-level method that is used to render the given `template` with
  3355. * the given `view`.
  3356. *
  3357. * The optional `partials` argument may be an object that contains the
  3358. * names and templates of partials that are used in the template. It may
  3359. * also be a function that is used to load partial templates on the fly
  3360. * that takes a single argument: the name of the partial.
  3361. */
  3362. Writer.prototype.render = function render(template, view, partials) {
  3363. var tokens = this.parse(template);
  3364. var context = view instanceof Context ? view : new Context(view);
  3365. return this.renderTokens(tokens, context, partials, template);
  3366. };
  3367. /**
  3368. * Low-level method that renders the given array of `tokens` using
  3369. * the given `context` and `partials`.
  3370. *
  3371. * Note: The `originalTemplate` is only ever used to extract the portion
  3372. * of the original template that was contained in a higher-order section.
  3373. * If the template doesn't use higher-order sections, this argument may
  3374. * be omitted.
  3375. */
  3376. Writer.prototype.renderTokens = function renderTokens(tokens, context, partials, originalTemplate) {
  3377. var buffer = '';
  3378. var token, symbol, value;
  3379. for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
  3380. value = undefined;
  3381. token = tokens[i];
  3382. symbol = token[0];
  3383. if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate);else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate);else if (symbol === '>') value = this.renderPartial(token, context, partials, originalTemplate);else if (symbol === '&') value = this.unescapedValue(token, context);else if (symbol === 'name') value = this.escapedValue(token, context);else if (symbol === 'text') value = this.rawValue(token);
  3384. if (value !== undefined) buffer += value;
  3385. }
  3386. return buffer;
  3387. };
  3388. Writer.prototype.renderSection = function renderSection(token, context, partials, originalTemplate) {
  3389. var self = this;
  3390. var buffer = '';
  3391. var value = context.lookup(token[1]);
  3392. // This function is used to render an arbitrary template
  3393. // in the current context by higher-order sections.
  3394. function subRender(template) {
  3395. return self.render(template, context, partials);
  3396. }
  3397. if (!value) return;
  3398. if (isArray(value)) {
  3399. for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
  3400. if (value[j]) {
  3401. if (_typeof(value[j]) === 'object') {
  3402. value[j]['@i'] = j;
  3403. value[j]['@first'] = j === 0;
  3404. }
  3405. buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
  3406. }
  3407. }
  3408. } else if ((typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' || typeof value === 'string' || typeof value === 'number') {
  3409. buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
  3410. } else if (isFunction(value)) {
  3411. if (typeof originalTemplate !== 'string') throw new Error('Cannot use higher-order sections without the original template');
  3412. // Extract the portion of the original template that the section contains.
  3413. value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
  3414. if (value != null) buffer += value;
  3415. } else {
  3416. buffer += this.renderTokens(token[4], context, partials, originalTemplate);
  3417. }
  3418. return buffer;
  3419. };
  3420. Writer.prototype.renderInverted = function renderInverted(token, context, partials, originalTemplate) {
  3421. var value = context.lookup(token[1]);
  3422. // Use JavaScript's definition of falsy. Include empty arrays.
  3423. // See https://github.com/janl/mustache.js/issues/186
  3424. if (!value || isArray(value) && value.length === 0) return this.renderTokens(token[4], context, partials, originalTemplate);
  3425. };
  3426. Writer.prototype.renderPartial = function renderPartial(token, context, partials) {
  3427. if (!partials) return;
  3428. var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
  3429. if (value != null) return this.renderTokens(this.parse(value), context, partials, value);
  3430. };
  3431. Writer.prototype.unescapedValue = function unescapedValue(token, context) {
  3432. var value = context.lookup(token[1]);
  3433. if (value != null) return value;
  3434. };
  3435. Writer.prototype.escapedValue = function escapedValue(token, context) {
  3436. var value = context.lookup(token[1]);
  3437. if (value != null) return mustache.escape(value);
  3438. };
  3439. Writer.prototype.rawValue = function rawValue(token) {
  3440. return token[1];
  3441. };
  3442. mustache.name = 'mustache.js';
  3443. mustache.version = '2.1.3';
  3444. mustache.tags = ['{{', '}}'];
  3445. // All high-level mustache.* functions use this writer.
  3446. var defaultWriter = new Writer();
  3447. /**
  3448. * Clears all cached templates in the default writer.
  3449. */
  3450. mustache.clearCache = function clearCache() {
  3451. return defaultWriter.clearCache();
  3452. };
  3453. /**
  3454. * Parses and caches the given template in the default writer and returns the
  3455. * array of tokens it contains. Doing this ahead of time avoids the need to
  3456. * parse templates on the fly as they are rendered.
  3457. */
  3458. mustache.parse = function parse(template, tags) {
  3459. return defaultWriter.parse(template, tags);
  3460. };
  3461. /**
  3462. * Renders the `template` with the given `view` and `partials` using the
  3463. * default writer.
  3464. */
  3465. mustache.render = function render(template, view, partials) {
  3466. if (typeof template !== 'string') {
  3467. throw new TypeError('Invalid template! Template should be a "string" ' + 'but "' + typeStr(template) + '" was given as the first ' + 'argument for mustache#render(template, view, partials)');
  3468. }
  3469. return defaultWriter.render(template, view, partials);
  3470. };
  3471. // This is here for backwards compatibility with 0.4.x.,
  3472. /*eslint-disable */ // eslint wants camel cased function name
  3473. mustache.to_html = function to_html(template, view, partials, send) {
  3474. /*eslint-enable*/
  3475. var result = mustache.render(template, view, partials);
  3476. if (isFunction(send)) {
  3477. send(result);
  3478. } else {
  3479. return result;
  3480. }
  3481. };
  3482. // Export the escaping function so that the user may override it.
  3483. // See https://github.com/janl/mustache.js/issues/244
  3484. mustache.escape = escapeHtml;
  3485. // Export these mainly for testing, but also for advanced usage.
  3486. mustache.Scanner = Scanner;
  3487. mustache.Context = Context;
  3488. mustache.Writer = Writer;
  3489. });