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.

1164 lines
41 KiB

  1. "use strict";
  2. /*
  3. * Copyright (c) 2016. tom@axisj.com
  4. * - github.com/thomasjang
  5. * - www.axisj.com
  6. */
  7. // ax5.ui.modal
  8. (function () {
  9. var UI = ax5.ui;
  10. var U = ax5.util;
  11. var MODAL = void 0;
  12. UI.addClass({
  13. className: "modal"
  14. }, function () {
  15. /**
  16. * @class ax5modal
  17. * @alias ax5.ui.modal
  18. * @author tom@axisj.com
  19. */
  20. return function () {
  21. var self = this,
  22. cfg = void 0,
  23. ENM = {
  24. mousedown: ax5.info.supportTouch ? "touchstart" : "mousedown",
  25. mousemove: ax5.info.supportTouch ? "touchmove" : "mousemove",
  26. mouseup: ax5.info.supportTouch ? "touchend" : "mouseup"
  27. },
  28. getMousePosition = function getMousePosition(e) {
  29. var mouseObj = e;
  30. if ("changedTouches" in e && e.changedTouches) {
  31. mouseObj = e.changedTouches[0];
  32. }
  33. return {
  34. clientX: mouseObj.clientX,
  35. clientY: mouseObj.clientY
  36. };
  37. };
  38. this.instanceId = ax5.getGuid();
  39. this.config = {
  40. id: "ax5-modal-" + this.instanceId,
  41. position: {
  42. left: "center",
  43. top: "middle",
  44. margin: 10
  45. },
  46. minimizePosition: "bottom-right",
  47. clickEventName: "ontouchstart" in document.documentElement ? "touchstart" : "click",
  48. theme: "default",
  49. width: 300,
  50. height: 400,
  51. closeToEsc: true,
  52. disableDrag: false,
  53. disableResize: false,
  54. animateTime: 250,
  55. iframe: false
  56. };
  57. this.activeModal = null;
  58. this.watingModal = false;
  59. this.$ = {}; // UI inside of the jQuery object store
  60. cfg = this.config; // extended config copy cfg
  61. var onStateChanged = function onStateChanged(opts, that) {
  62. var eventProcessor = {
  63. resize: function resize(that) {
  64. if (opts && opts.onResize) {
  65. opts.onResize.call(that, that);
  66. } else if (this.onResize) {
  67. this.onResize.call(that, that);
  68. }
  69. },
  70. move: function move() {}
  71. };
  72. if (that.state in eventProcessor) {
  73. eventProcessor[that.state].call(this, that);
  74. }
  75. if (opts && opts.onStateChanged) {
  76. opts.onStateChanged.call(that, that);
  77. } else if (this.onStateChanged) {
  78. this.onStateChanged.call(that, that);
  79. }
  80. return true;
  81. },
  82. getContent = function getContent(modalId, opts) {
  83. var data = {
  84. modalId: modalId,
  85. theme: opts.theme,
  86. header: opts.header,
  87. fullScreen: opts.fullScreen ? "fullscreen" : "",
  88. styles: "",
  89. iframe: opts.iframe,
  90. iframeLoadingMsg: opts.iframeLoadingMsg,
  91. disableResize: opts.disableResize
  92. };
  93. if (opts.zIndex) {
  94. data.styles += "z-index:" + opts.zIndex + ";";
  95. }
  96. if (opts.absolute) {
  97. data.styles += "position:absolute;";
  98. }
  99. if (data.iframe && typeof data.iframe.param === "string") {
  100. data.iframe.param = ax5.util.param(data.iframe.param);
  101. }
  102. return MODAL.tmpl.get.call(this, "content", data, {});
  103. },
  104. open = function open(opts, callback) {
  105. var that = void 0;
  106. jQuery(document.body).append(getContent.call(this, opts.id, opts));
  107. this.activeModal = jQuery("#" + opts.id);
  108. // 파트수집
  109. this.$ = {
  110. root: this.activeModal,
  111. header: this.activeModal.find('[data-modal-els="header"]'),
  112. body: this.activeModal.find('[data-modal-els="body"]')
  113. };
  114. if (opts.iframe) {
  115. this.$["iframe-wrap"] = this.activeModal.find('[data-modal-els="iframe-wrap"]');
  116. this.$["iframe"] = this.activeModal.find('[data-modal-els="iframe"]');
  117. this.$["iframe-form"] = this.activeModal.find('[data-modal-els="iframe-form"]');
  118. this.$["iframe-loading"] = this.activeModal.find('[data-modal-els="iframe-loading"]');
  119. } else {
  120. this.$["body-frame"] = this.activeModal.find('[data-modal-els="body-frame"]');
  121. }
  122. //- position 정렬
  123. this.align();
  124. that = {
  125. self: this,
  126. id: opts.id,
  127. theme: opts.theme,
  128. width: opts.width,
  129. height: opts.height,
  130. state: "open",
  131. $: this.$
  132. };
  133. if (opts.iframe) {
  134. this.$["iframe-wrap"].css({ height: opts.height });
  135. this.$["iframe"].css({ height: opts.height });
  136. // iframe content load
  137. this.$["iframe-form"].attr({ method: opts.iframe.method });
  138. this.$["iframe-form"].attr({ target: opts.id + "-frame" });
  139. this.$["iframe-form"].attr({ action: opts.iframe.url });
  140. this.$["iframe"].on("load", function () {
  141. that.state = "load";
  142. if (opts.iframeLoadingMsg) {
  143. this.$["iframe-loading"].hide();
  144. }
  145. onStateChanged.call(this, opts, that);
  146. }.bind(this));
  147. if (!opts.iframeLoadingMsg) {
  148. this.$["iframe"].show();
  149. }
  150. this.$["iframe-form"].submit();
  151. }
  152. if (callback) callback.call(that, that);
  153. if (!this.watingModal) {
  154. onStateChanged.call(this, opts, that);
  155. }
  156. // bind key event
  157. if (opts.closeToEsc) {
  158. jQuery(window).bind("keydown.ax-modal", function (e) {
  159. onkeyup.call(this, e || window.event);
  160. }.bind(this));
  161. }
  162. jQuery(window).bind("resize.ax-modal", function (e) {
  163. this.align(null, e || window.event);
  164. }.bind(this));
  165. this.$.header.off(ENM["mousedown"]).off("dragstart").on(ENM["mousedown"], function (e) {
  166. /// 이벤트 필터링 추가 : 버튼엘리먼트로 부터 발생된 이벤트이면 moveModal 시작하지 않도록 필터링
  167. var isButton = U.findParentNode(e.target, function (_target) {
  168. if (_target.getAttribute("data-modal-header-btn")) {
  169. return true;
  170. }
  171. });
  172. if (!opts.isFullScreen && !isButton && opts.disableDrag != true) {
  173. self.mousePosition = getMousePosition(e);
  174. moveModal.on.call(self);
  175. }
  176. if (isButton) {
  177. btnOnClick.call(self, e || window.event, opts);
  178. }
  179. }).on("dragstart", function (e) {
  180. U.stopEvent(e.originalEvent);
  181. return false;
  182. });
  183. this.activeModal.off(ENM["mousedown"]).off("dragstart").on(ENM["mousedown"], "[data-ax5modal-resizer]", function (e) {
  184. if (opts.disableDrag || opts.isFullScreen) return false;
  185. self.mousePosition = getMousePosition(e);
  186. resizeModal.on.call(self, this.getAttribute("data-ax5modal-resizer"));
  187. }).on("dragstart", function (e) {
  188. U.stopEvent(e.originalEvent);
  189. return false;
  190. });
  191. },
  192. btnOnClick = function btnOnClick(e, opts, callback, target, k) {
  193. var that = void 0;
  194. if (e.srcElement) e.target = e.srcElement;
  195. target = U.findParentNode(e.target, function (target) {
  196. if (target.getAttribute("data-modal-header-btn")) {
  197. return true;
  198. }
  199. });
  200. if (target) {
  201. k = target.getAttribute("data-modal-header-btn");
  202. that = {
  203. self: this,
  204. key: k,
  205. value: opts.header.btns[k],
  206. dialogId: opts.id,
  207. btnTarget: target
  208. };
  209. if (opts.header.btns[k].onClick) {
  210. opts.header.btns[k].onClick.call(that, k);
  211. }
  212. }
  213. that = null;
  214. opts = null;
  215. callback = null;
  216. target = null;
  217. k = null;
  218. },
  219. onkeyup = function onkeyup(e) {
  220. if (e.keyCode == ax5.info.eventKeys.ESC) {
  221. this.close();
  222. }
  223. },
  224. alignProcessor = {
  225. "top-left": function topLeft() {
  226. this.align({ left: "left", top: "top" });
  227. },
  228. "top-right": function topRight() {
  229. this.align({ left: "right", top: "top" });
  230. },
  231. "bottom-left": function bottomLeft() {
  232. this.align({ left: "left", top: "bottom" });
  233. },
  234. "bottom-right": function bottomRight() {
  235. this.align({ left: "right", top: "bottom" });
  236. },
  237. "center-middle": function centerMiddle() {
  238. this.align({ left: "center", top: "middle" });
  239. }
  240. },
  241. moveModal = {
  242. on: function on() {
  243. var modalZIndex = this.activeModal.css("z-index"),
  244. modalOffset = this.activeModal.offset(),
  245. modalBox = {
  246. width: this.activeModal.outerWidth(),
  247. height: this.activeModal.outerHeight()
  248. },
  249. windowBox = {
  250. width: jQuery(window).width(),
  251. height: jQuery(window).height(),
  252. scrollLeft: jQuery(document).scrollLeft(),
  253. scrollTop: jQuery(document).scrollTop()
  254. },
  255. getResizerPosition = function getResizerPosition(e) {
  256. self.__dx = e.clientX - self.mousePosition.clientX;
  257. self.__dy = e.clientY - self.mousePosition.clientY;
  258. /*
  259. if (minX > modalOffset.left + self.__dx) {
  260. self.__dx = -modalOffset.left;
  261. } else if (maxX < modalOffset.left + self.__dx) {
  262. self.__dx = maxX - modalOffset.left;
  263. }
  264. if (minY > modalOffset.top + self.__dy) {
  265. self.__dy = -modalOffset.top;
  266. } else if (maxY < modalOffset.top + self.__dy) {
  267. self.__dy = maxY - modalOffset.top;
  268. }
  269. */
  270. return {
  271. left: modalOffset.left + self.__dx,
  272. top: modalOffset.top + self.__dy
  273. };
  274. };
  275. var minX = 0,
  276. maxX = windowBox.width - modalBox.width,
  277. minY = 0,
  278. maxY = windowBox.height - modalBox.height;
  279. self.__dx = 0; // 변화량 X
  280. self.__dy = 0; // 변화량 Y
  281. // self.resizerBg : body 가 window보다 작을 때 문제 해결을 위한 DIV
  282. self.resizerBg = jQuery('<div class="ax5modal-resizer-background" ondragstart="return false;"></div>');
  283. self.resizer = jQuery('<div class="ax5modal-resizer" ondragstart="return false;"></div>');
  284. self.resizerBg.css({ zIndex: modalZIndex });
  285. self.resizer.css({
  286. left: modalOffset.left,
  287. top: modalOffset.top,
  288. width: modalBox.width,
  289. height: modalBox.height,
  290. zIndex: modalZIndex + 1
  291. });
  292. jQuery(document.body).append(self.resizerBg).append(self.resizer);
  293. self.activeModal.addClass("draged");
  294. jQuery(document.body).on(ENM["mousemove"] + ".ax5modal-move-" + this.instanceId, function (e) {
  295. self.resizer.css(getResizerPosition(e));
  296. }).on(ENM["mouseup"] + ".ax5modal-move-" + this.instanceId, function (e) {
  297. moveModal.off.call(self);
  298. }).on("mouseleave.ax5modal-move-" + this.instanceId, function (e) {
  299. moveModal.off.call(self);
  300. });
  301. jQuery(document.body).attr("unselectable", "on").css("user-select", "none").on("selectstart", false);
  302. },
  303. off: function off() {
  304. var setModalPosition = function setModalPosition() {
  305. var box = this.resizer.offset();
  306. if (!this.modalConfig.absolute) {
  307. box.left -= jQuery(document).scrollLeft();
  308. box.top -= jQuery(document).scrollTop();
  309. }
  310. this.activeModal.css(box);
  311. this.modalConfig.left = box.left;
  312. this.modalConfig.top = box.top;
  313. box = null;
  314. };
  315. this.activeModal.removeClass("draged");
  316. setModalPosition.call(this);
  317. this.resizer.remove();
  318. this.resizer = null;
  319. this.resizerBg.remove();
  320. this.resizerBg = null;
  321. //this.align();
  322. jQuery(document.body).off(ENM["mousemove"] + ".ax5modal-move-" + this.instanceId).off(ENM["mouseup"] + ".ax5modal-move-" + this.instanceId).off("mouseleave.ax5modal-move-" + this.instanceId);
  323. jQuery(document.body).removeAttr("unselectable").css("user-select", "auto").off("selectstart");
  324. onStateChanged.call(this, self.modalConfig, {
  325. self: this,
  326. state: "move"
  327. });
  328. }
  329. },
  330. resizeModal = {
  331. on: function on(resizerType) {
  332. var modalZIndex = this.activeModal.css("z-index"),
  333. modalOffset = this.activeModal.offset(),
  334. modalBox = {
  335. width: this.activeModal.outerWidth(),
  336. height: this.activeModal.outerHeight()
  337. },
  338. windowBox = {
  339. width: jQuery(window).width(),
  340. height: jQuery(window).height(),
  341. scrollLeft: jQuery(document).scrollLeft(),
  342. scrollTop: jQuery(document).scrollTop()
  343. },
  344. resizerProcessor = {
  345. top: function top(e) {
  346. if (minHeight > modalBox.height - self.__dy) {
  347. self.__dy = modalBox.height - minHeight;
  348. }
  349. if (e.shiftKey) {
  350. if (minHeight > modalBox.height - self.__dy * 2) {
  351. self.__dy = (modalBox.height - minHeight) / 2;
  352. }
  353. return {
  354. left: modalOffset.left,
  355. top: modalOffset.top + self.__dy,
  356. width: modalBox.width,
  357. height: modalBox.height - self.__dy * 2
  358. };
  359. } else if (e.altKey) {
  360. if (minHeight > modalBox.height - self.__dy * 2) {
  361. self.__dy = (modalBox.height - minHeight) / 2;
  362. }
  363. return {
  364. left: modalOffset.left + self.__dy,
  365. top: modalOffset.top + self.__dy,
  366. width: modalBox.width - self.__dy * 2,
  367. height: modalBox.height - self.__dy * 2
  368. };
  369. } else {
  370. return {
  371. left: modalOffset.left,
  372. top: modalOffset.top + self.__dy,
  373. width: modalBox.width,
  374. height: modalBox.height - self.__dy
  375. };
  376. }
  377. },
  378. bottom: function bottom(e) {
  379. if (minHeight > modalBox.height + self.__dy) {
  380. self.__dy = -modalBox.height + minHeight;
  381. }
  382. if (e.shiftKey) {
  383. if (minHeight > modalBox.height + self.__dy * 2) {
  384. self.__dy = (-modalBox.height + minHeight) / 2;
  385. }
  386. return {
  387. left: modalOffset.left,
  388. top: modalOffset.top - self.__dy,
  389. width: modalBox.width,
  390. height: modalBox.height + self.__dy * 2
  391. };
  392. } else if (e.altKey) {
  393. if (minHeight > modalBox.height + self.__dy * 2) {
  394. self.__dy = (-modalBox.height + minHeight) / 2;
  395. }
  396. return {
  397. left: modalOffset.left - self.__dy,
  398. top: modalOffset.top - self.__dy,
  399. width: modalBox.width + self.__dy * 2,
  400. height: modalBox.height + self.__dy * 2
  401. };
  402. } else {
  403. return {
  404. left: modalOffset.left,
  405. top: modalOffset.top,
  406. width: modalBox.width,
  407. height: modalBox.height + self.__dy
  408. };
  409. }
  410. },
  411. left: function left(e) {
  412. if (minWidth > modalBox.width - self.__dx) {
  413. self.__dx = modalBox.width - minWidth;
  414. }
  415. if (e.shiftKey) {
  416. if (minWidth > modalBox.width - self.__dx * 2) {
  417. self.__dx = (modalBox.width - minWidth) / 2;
  418. }
  419. return {
  420. left: modalOffset.left + self.__dx,
  421. top: modalOffset.top,
  422. width: modalBox.width - self.__dx * 2,
  423. height: modalBox.height
  424. };
  425. } else if (e.altKey) {
  426. if (minWidth > modalBox.width - self.__dx * 2) {
  427. self.__dx = (modalBox.width - minWidth) / 2;
  428. }
  429. return {
  430. left: modalOffset.left + self.__dx,
  431. top: modalOffset.top + self.__dx,
  432. width: modalBox.width - self.__dx * 2,
  433. height: modalBox.height - self.__dx * 2
  434. };
  435. } else {
  436. return {
  437. left: modalOffset.left + self.__dx,
  438. top: modalOffset.top,
  439. width: modalBox.width - self.__dx,
  440. height: modalBox.height
  441. };
  442. }
  443. },
  444. right: function right(e) {
  445. if (minWidth > modalBox.width + self.__dx) {
  446. self.__dx = -modalBox.width + minWidth;
  447. }
  448. if (e.shiftKey) {
  449. if (minWidth > modalBox.width + self.__dx * 2) {
  450. self.__dx = (-modalBox.width + minWidth) / 2;
  451. }
  452. return {
  453. left: modalOffset.left - self.__dx,
  454. top: modalOffset.top,
  455. width: modalBox.width + self.__dx * 2,
  456. height: modalBox.height
  457. };
  458. } else if (e.altKey) {
  459. if (minWidth > modalBox.width + self.__dx * 2) {
  460. self.__dx = (-modalBox.width + minWidth) / 2;
  461. }
  462. return {
  463. left: modalOffset.left - self.__dx,
  464. top: modalOffset.top - self.__dx,
  465. width: modalBox.width + self.__dx * 2,
  466. height: modalBox.height + self.__dx * 2
  467. };
  468. } else {
  469. return {
  470. left: modalOffset.left,
  471. top: modalOffset.top,
  472. width: modalBox.width + self.__dx,
  473. height: modalBox.height
  474. };
  475. }
  476. },
  477. "top-left": function topLeft(e) {
  478. if (minWidth > modalBox.width - self.__dx) {
  479. self.__dx = modalBox.width - minWidth;
  480. }
  481. if (minHeight > modalBox.height - self.__dy) {
  482. self.__dy = modalBox.height - minHeight;
  483. }
  484. if (e.shiftKey || e.altKey) {
  485. if (minHeight > modalBox.height - self.__dy * 2) {
  486. self.__dy = (modalBox.height - minHeight) / 2;
  487. }
  488. if (minWidth > modalBox.width - self.__dx * 2) {
  489. self.__dx = (modalBox.width - minWidth) / 2;
  490. }
  491. return {
  492. left: modalOffset.left + self.__dx,
  493. top: modalOffset.top + self.__dy,
  494. width: modalBox.width - self.__dx * 2,
  495. height: modalBox.height - self.__dy * 2
  496. };
  497. } else {
  498. if (minHeight > modalBox.height - self.__dy * 2) {
  499. self.__dy = (modalBox.height - minHeight) / 2;
  500. }
  501. if (minWidth > modalBox.width - self.__dx * 2) {
  502. self.__dx = (modalBox.width - minWidth) / 2;
  503. }
  504. return {
  505. left: modalOffset.left + self.__dx,
  506. top: modalOffset.top + self.__dy,
  507. width: modalBox.width - self.__dx,
  508. height: modalBox.height - self.__dy
  509. };
  510. }
  511. },
  512. "top-right": function topRight(e) {
  513. if (minWidth > modalBox.width + self.__dx) {
  514. self.__dx = -modalBox.width + minWidth;
  515. }
  516. if (minHeight > modalBox.height - self.__dy) {
  517. self.__dy = modalBox.height - minHeight;
  518. }
  519. if (e.shiftKey || e.altKey) {
  520. if (minHeight > modalBox.height - self.__dy * 2) {
  521. self.__dy = (modalBox.height - minHeight) / 2;
  522. }
  523. if (minWidth > modalBox.width + self.__dx * 2) {
  524. self.__dx = (-modalBox.width + minWidth) / 2;
  525. }
  526. return {
  527. left: modalOffset.left - self.__dx,
  528. top: modalOffset.top + self.__dy,
  529. width: modalBox.width + self.__dx * 2,
  530. height: modalBox.height - self.__dy * 2
  531. };
  532. } else {
  533. return {
  534. left: modalOffset.left,
  535. top: modalOffset.top + self.__dy,
  536. width: modalBox.width + self.__dx,
  537. height: modalBox.height - self.__dy
  538. };
  539. }
  540. },
  541. "bottom-left": function bottomLeft(e) {
  542. if (minWidth > modalBox.width - self.__dx) {
  543. self.__dx = modalBox.width - minWidth;
  544. }
  545. if (minHeight > modalBox.height + self.__dy) {
  546. self.__dy = -modalBox.height + minHeight;
  547. }
  548. if (e.shiftKey || e.altKey) {
  549. if (minWidth > modalBox.width - self.__dx * 2) {
  550. self.__dx = (modalBox.width - minWidth) / 2;
  551. }
  552. if (minHeight > modalBox.height + self.__dy * 2) {
  553. self.__dy = (-modalBox.height + minHeight) / 2;
  554. }
  555. return {
  556. left: modalOffset.left + self.__dx,
  557. top: modalOffset.top - self.__dy,
  558. width: modalBox.width - self.__dx * 2,
  559. height: modalBox.height + self.__dy * 2
  560. };
  561. } else {
  562. return {
  563. left: modalOffset.left + self.__dx,
  564. top: modalOffset.top,
  565. width: modalBox.width - self.__dx,
  566. height: modalBox.height + self.__dy
  567. };
  568. }
  569. },
  570. "bottom-right": function bottomRight(e) {
  571. if (minWidth > modalBox.width + self.__dx) {
  572. self.__dx = -modalBox.width + minWidth;
  573. }
  574. if (minHeight > modalBox.height + self.__dy) {
  575. self.__dy = -modalBox.height + minHeight;
  576. }
  577. if (e.shiftKey || e.altKey) {
  578. if (minWidth > modalBox.width + self.__dx * 2) {
  579. self.__dx = (-modalBox.width + minWidth) / 2;
  580. }
  581. if (minHeight > modalBox.height + self.__dy * 2) {
  582. self.__dy = (-modalBox.height + minHeight) / 2;
  583. }
  584. return {
  585. left: modalOffset.left - self.__dx,
  586. top: modalOffset.top - self.__dy,
  587. width: modalBox.width + self.__dx * 2,
  588. height: modalBox.height + self.__dy * 2
  589. };
  590. } else {
  591. return {
  592. left: modalOffset.left,
  593. top: modalOffset.top,
  594. width: modalBox.width + self.__dx,
  595. height: modalBox.height + self.__dy
  596. };
  597. }
  598. }
  599. },
  600. getResizerPosition = function getResizerPosition(e) {
  601. self.__dx = e.clientX - self.mousePosition.clientX;
  602. self.__dy = e.clientY - self.mousePosition.clientY;
  603. return resizerProcessor[resizerType](e);
  604. };
  605. var minWidth = 100,
  606. minHeight = 100;
  607. var cursorType = {
  608. top: "row-resize",
  609. bottom: "row-resize",
  610. left: "col-resize",
  611. right: "col-resize",
  612. "top-left": "nwse-resize",
  613. "top-right": "nesw-resize",
  614. "bottom-left": "nesw-resize",
  615. "bottom-right": "nwse-resize"
  616. };
  617. self.__dx = 0; // 변화량 X
  618. self.__dy = 0; // 변화량 Y
  619. // self.resizerBg : body 가 window보다 작을 때 문제 해결을 위한 DIV
  620. self.resizerBg = jQuery('<div class="ax5modal-resizer-background" ondragstart="return false;"></div>');
  621. self.resizer = jQuery('<div class="ax5modal-resizer" ondragstart="return false;"></div>');
  622. self.resizerBg.css({
  623. zIndex: modalZIndex,
  624. cursor: cursorType[resizerType]
  625. });
  626. self.resizer.css({
  627. left: modalOffset.left,
  628. top: modalOffset.top,
  629. width: modalBox.width,
  630. height: modalBox.height,
  631. zIndex: modalZIndex + 1,
  632. cursor: cursorType[resizerType]
  633. });
  634. jQuery(document.body).append(self.resizerBg).append(self.resizer);
  635. self.activeModal.addClass("draged");
  636. jQuery(document.body).bind(ENM["mousemove"] + ".ax5modal-resize-" + this.instanceId, function (e) {
  637. self.resizer.css(getResizerPosition(e));
  638. }).bind(ENM["mouseup"] + ".ax5modal-resize-" + this.instanceId, function (e) {
  639. resizeModal.off.call(self);
  640. }).bind("mouseleave.ax5modal-resize-" + this.instanceId, function (e) {
  641. resizeModal.off.call(self);
  642. });
  643. jQuery(document.body).attr("unselectable", "on").css("user-select", "none").bind("selectstart", false);
  644. },
  645. off: function off() {
  646. var setModalPosition = function setModalPosition() {
  647. var box = this.resizer.offset();
  648. jQuery.extend(box, {
  649. width: this.resizer.width(),
  650. height: this.resizer.height()
  651. });
  652. if (!this.modalConfig.absolute) {
  653. box.left -= jQuery(document).scrollLeft();
  654. box.top -= jQuery(document).scrollTop();
  655. }
  656. this.activeModal.css(box);
  657. this.modalConfig.left = box.left;
  658. this.modalConfig.top = box.top;
  659. this.modalConfig.width = box.width;
  660. this.modalConfig.height = box.height;
  661. this.$["body"].css({
  662. height: box.height - this.modalConfig.headerHeight
  663. });
  664. if (this.modalConfig.iframe) {
  665. this.$["iframe-wrap"].css({
  666. height: box.height - this.modalConfig.headerHeight
  667. });
  668. this.$["iframe"].css({
  669. height: box.height - this.modalConfig.headerHeight
  670. });
  671. }
  672. box = null;
  673. };
  674. this.activeModal.removeClass("draged");
  675. setModalPosition.call(this);
  676. this.resizer.remove();
  677. this.resizer = null;
  678. this.resizerBg.remove();
  679. this.resizerBg = null;
  680. onStateChanged.call(this, self.modalConfig, {
  681. self: this,
  682. state: "resize"
  683. });
  684. jQuery(document.body).unbind(ENM["mousemove"] + ".ax5modal-resize-" + this.instanceId).unbind(ENM["mouseup"] + ".ax5modal-resize-" + this.instanceId).unbind("mouseleave.ax5modal-resize-" + this.instanceId);
  685. jQuery(document.body).removeAttr("unselectable").css("user-select", "auto").unbind("selectstart");
  686. }
  687. };
  688. /// private end
  689. /**
  690. * Preferences of modal UI
  691. * @method ax5modal.setConfig
  692. * @param {Object} config - 클래스 속성값
  693. * @param {Number} [config.zIndex]
  694. * @param {Object} [config.position]
  695. * @param {String} [config.position.left="center"]
  696. * @param {String} [config.position.top="middle"]
  697. * @param {Number} [config.position.margin=10]
  698. * @param {String} [config.minimizePosition="bottom-right"]
  699. * @param {Number} [config.width=300]
  700. * @param {Number} [config.height=400]
  701. * @param {Boolean} [config.closeToEsc=true]
  702. * @param {Boolean} [config.absolute=false]
  703. * @param {Boolean} [config.disableDrag=false]
  704. * @param {Boolean} [config.disableResize=false]
  705. * @param {Number} [config.animateTime=250]
  706. * @param {Function} [config.fullScreen]
  707. * @param {Function} [config.onStateChanged] - `onStateChanged` function can be defined in setConfig method or new ax5.ui.modal initialization method. However, you can us to define an event function after initialization, if necessary
  708. * @param {Function} [config.onResize]
  709. * @returns {ax5modal}
  710. * @example
  711. * ```js
  712. * var modal = new ax5.ui.modal({
  713. * iframeLoadingMsg: '<i class="fa fa-spinner fa-5x fa-spin" aria-hidden="true"></i>',
  714. * header: {
  715. * title: "MODAL TITLE",
  716. * btns: {
  717. * minimize: {
  718. * label: '<i class="fa fa-minus-circle" aria-hidden="true"></i>', onClick: function () {
  719. * modal.minimize();
  720. * }
  721. * },
  722. * maximize: {
  723. * label: '<i class="fa fa-plus-circle" aria-hidden="true"></i>', onClick: function () {
  724. * modal.maximize();
  725. * }
  726. * },
  727. * close: {
  728. * label: '<i class="fa fa-times-circle" aria-hidden="true"></i>', onClick: function () {
  729. * modal.close();
  730. * }
  731. * }
  732. * }
  733. * }
  734. * });
  735. *
  736. * modal.open({
  737. * width: 800,
  738. * height: 600,
  739. * fullScreen: function(){
  740. * return ($(window).width() < 600);
  741. * },
  742. * iframe: {
  743. * method: "get",
  744. * url: "http://chequer-app:2017/html/login.html",
  745. * param: "callback=modalCallback"
  746. * },
  747. * onStateChanged: function(){
  748. * console.log(this);
  749. * },
  750. * onResize: function(){
  751. * console.log(this);
  752. * }
  753. * });
  754. * ```
  755. */
  756. //== class body start
  757. this.init = function () {
  758. this.onStateChanged = cfg.onStateChanged;
  759. this.onResize = cfg.onResize;
  760. };
  761. /**
  762. * open the modal
  763. * @method ax5modal.open
  764. * @returns {ax5modal}
  765. * @example
  766. * ```
  767. * modal.open();
  768. * modal.open({
  769. * width: 500,
  770. * height: 500
  771. * });
  772. * moaal.open({}, function(){
  773. * console.log(this);
  774. * });
  775. * ```
  776. */
  777. this.open = function (opts, callback, tryCount) {
  778. if (typeof tryCount === "undefined") tryCount = 0;
  779. if (!this.activeModal) {
  780. opts = self.modalConfig = jQuery.extend(true, {}, cfg, opts);
  781. open.call(this, opts, callback);
  782. this.watingModal = false;
  783. } else if (tryCount < 3) {
  784. // 3번까지 재 시도
  785. this.watingModal = true;
  786. setTimeout(function () {
  787. this.open(opts, callback, tryCount + 1);
  788. }.bind(this), cfg.animateTime);
  789. } else {
  790. // 열기 시도 종료
  791. this.watingModal = false;
  792. }
  793. return this;
  794. };
  795. /**
  796. * close the modal
  797. * @method ax5modal.close
  798. * @param _option
  799. * @returns {ax5modal}
  800. * @example
  801. * ```
  802. * my_modal.close();
  803. * my_modal.close({callback: function(){
  804. * // on close event
  805. * });
  806. * // close 함수에 callback을 전달하면 정확한 close 타이밍을 캐치할 수 있습니다
  807. * ```
  808. */
  809. this.close = function (_option) {
  810. var opts = void 0,
  811. that = void 0;
  812. if (this.activeModal) {
  813. opts = self.modalConfig;
  814. this.activeModal.addClass("destroy");
  815. jQuery(window).unbind("keydown.ax-modal");
  816. jQuery(window).unbind("resize.ax-modal");
  817. setTimeout(function () {
  818. // 프레임 제거
  819. if (opts.iframe) {
  820. var $iframe = this.$["iframe"]; // iframe jQuery Object
  821. if ($iframe) {
  822. var iframeObject = $iframe.get(0),
  823. idoc = iframeObject.contentDocument ? iframeObject.contentDocument : iframeObject.contentWindow.document;
  824. try {
  825. $(idoc.body).children().each(function () {
  826. $(this).remove();
  827. });
  828. } catch (e) {}
  829. idoc.innerHTML = "";
  830. $iframe.attr("src", "about:blank").remove();
  831. // force garbarge collection for IE only
  832. window.CollectGarbage && window.CollectGarbage();
  833. }
  834. }
  835. this.activeModal.remove();
  836. this.activeModal = null;
  837. // 모달 오픈 대기중이면 닫기 상태 전달 안함.
  838. if (!this.watingModal) {
  839. onStateChanged.call(this, opts, {
  840. self: this,
  841. state: "close"
  842. });
  843. }
  844. if (_option && U.isFunction(_option.callback)) {
  845. that = {
  846. self: this,
  847. id: opts.id,
  848. theme: opts.theme,
  849. width: opts.width,
  850. height: opts.height,
  851. state: "close",
  852. $: this.$
  853. };
  854. _option.callback.call(that, that);
  855. }
  856. }.bind(this), cfg.animateTime);
  857. }
  858. this.minimized = false; // hoksi
  859. return this;
  860. };
  861. /**
  862. * @method ax5modal.minimize
  863. * @returns {ax5modal}
  864. */
  865. this.minimize = function () {
  866. return function (minimizePosition) {
  867. if (this.minimized !== true) {
  868. var opts = self.modalConfig;
  869. if (typeof minimizePosition === "undefined") minimizePosition = cfg.minimizePosition;
  870. this.minimized = true;
  871. this.$.body.hide();
  872. self.modalConfig.originalHeight = opts.height;
  873. self.modalConfig.height = 0;
  874. alignProcessor[minimizePosition].call(this);
  875. onStateChanged.call(this, opts, {
  876. self: this,
  877. state: "minimize"
  878. });
  879. }
  880. return this;
  881. };
  882. }();
  883. /**
  884. * @method ax5modal.restore
  885. * @returns {ax5modal}
  886. */
  887. this.restore = function () {
  888. var opts = self.modalConfig;
  889. if (this.minimized) {
  890. this.minimized = false;
  891. this.$.body.show();
  892. self.modalConfig.height = self.modalConfig.originalHeight;
  893. self.modalConfig.originalHeight = undefined;
  894. this.align({ left: "center", top: "middle" });
  895. onStateChanged.call(this, opts, {
  896. self: this,
  897. state: "restore"
  898. });
  899. }
  900. return this;
  901. };
  902. /**
  903. * setCSS
  904. * @method ax5modal.css
  905. * @param {Object} css -
  906. * @returns {ax5modal}
  907. */
  908. this.css = function (css) {
  909. if (this.activeModal && !self.fullScreen) {
  910. this.activeModal.css(css);
  911. if (typeof css.width !== "undefined") {
  912. self.modalConfig.width = css.width;
  913. }
  914. if (typeof css.height !== "undefined") {
  915. self.modalConfig.height = css.height;
  916. }
  917. this.align();
  918. }
  919. return this;
  920. };
  921. /**
  922. * @method ax5modal.setModalConfig
  923. * @param _config
  924. * @returns {ax5.ui.ax5modal}
  925. */
  926. this.setModalConfig = function (_config) {
  927. self.modalConfig = jQuery.extend({}, self.modalConfig, _config);
  928. this.align();
  929. return this;
  930. };
  931. /**
  932. * @method ax5modal.align
  933. * @param position
  934. * @param e
  935. * @returns {ax5modal}
  936. * @example
  937. * ```js
  938. * modal.align({left:"center", top:"middle"});
  939. * modal.align({left:"left", top:"top", margin: 20});
  940. * ```
  941. */
  942. this.align = function () {
  943. return function (position, e) {
  944. if (!this.activeModal) return this;
  945. var opts = self.modalConfig,
  946. box = {
  947. width: opts.width,
  948. height: opts.height
  949. };
  950. var fullScreen = opts.isFullScreen = function (_fullScreen) {
  951. if (typeof _fullScreen === "undefined") {
  952. return false;
  953. } else if (U.isFunction(_fullScreen)) {
  954. return _fullScreen();
  955. }
  956. }(opts.fullScreen);
  957. if (fullScreen) {
  958. if (opts.header) this.$.header.show();
  959. if (opts.header) {
  960. opts.headerHeight = this.$.header.outerHeight();
  961. box.height += opts.headerHeight;
  962. } else {
  963. opts.headerHeight = 0;
  964. }
  965. box.width = jQuery(window).width();
  966. box.height = opts.height;
  967. box.left = 0;
  968. box.top = 0;
  969. } else {
  970. if (opts.header) this.$.header.show();
  971. if (position) {
  972. jQuery.extend(true, opts.position, position);
  973. }
  974. if (opts.header) {
  975. opts.headerHeight = this.$.header.outerHeight();
  976. box.height += opts.headerHeight;
  977. } else {
  978. opts.headerHeight = 0;
  979. }
  980. //- position 정렬
  981. if (opts.position.left == "left") {
  982. box.left = opts.position.margin || 0;
  983. } else if (opts.position.left == "right") {
  984. // window.innerWidth;
  985. box.left = jQuery(window).width() - box.width - (opts.position.margin || 0);
  986. } else if (opts.position.left == "center") {
  987. box.left = jQuery(window).width() / 2 - box.width / 2;
  988. } else {
  989. box.left = opts.position.left || 0;
  990. }
  991. if (opts.position.top == "top") {
  992. box.top = opts.position.margin || 0;
  993. } else if (opts.position.top == "bottom") {
  994. box.top = jQuery(window).height() - box.height - (opts.position.margin || 0);
  995. } else if (opts.position.top == "middle") {
  996. box.top = jQuery(window).height() / 2 - box.height / 2;
  997. } else {
  998. box.top = opts.position.top || 0;
  999. }
  1000. if (box.left < 0) box.left = 0;
  1001. if (box.top < 0) box.top = 0;
  1002. if (opts.absolute) {
  1003. box.top += jQuery(window).scrollTop();
  1004. box.left += jQuery(window).scrollLeft();
  1005. }
  1006. }
  1007. this.activeModal.css(box);
  1008. this.$["body"].css({
  1009. height: box.height - (opts.headerHeight || 0)
  1010. });
  1011. if (opts.iframe) {
  1012. this.$["iframe-wrap"].css({
  1013. height: box.height - opts.headerHeight
  1014. });
  1015. this.$["iframe"].css({ height: box.height - opts.headerHeight });
  1016. } else {}
  1017. return this;
  1018. };
  1019. }();
  1020. // 클래스 생성자
  1021. this.main = function () {
  1022. UI.modal_instance = UI.modal_instance || [];
  1023. UI.modal_instance.push(this);
  1024. if (arguments && U.isObject(arguments[0])) {
  1025. this.setConfig(arguments[0]);
  1026. }
  1027. }.apply(this, arguments);
  1028. };
  1029. }());
  1030. MODAL = ax5.ui.modal;
  1031. })();
  1032. // ax5.ui.modal.tmpl
  1033. (function () {
  1034. var MODAL = ax5.ui.modal;
  1035. var content = function content() {
  1036. return " \n <div id=\"{{modalId}}\" data-modal-els=\"root\" class=\"ax5modal {{theme}} {{fullscreen}}\" style=\"{{styles}}\">\n {{#header}}\n <div class=\"ax-modal-header\" data-modal-els=\"header\">\n {{{title}}}\n {{#btns}}\n <div class=\"ax-modal-header-addon\">\n {{#@each}}\n <button tabindex=\"-1\" data-modal-header-btn=\"{{@key}}\" class=\"{{@value.theme}}\">{{{@value.label}}}</button>\n {{/@each}}\n </div>\n {{/btns}}\n </div>\n {{/header}}\n <div class=\"ax-modal-body\" data-modal-els=\"body\">\n {{#iframe}}\n <div data-modal-els=\"iframe-wrap\" style=\"-webkit-overflow-scrolling: touch; overflow: auto;position: relative;\">\n <table data-modal-els=\"iframe-loading\" style=\"width:100%;height:100%;\"><tr><td style=\"text-align: center;vertical-align: middle\">{{{iframeLoadingMsg}}}</td></tr></table>\n <iframe name=\"{{modalId}}-frame\" src=\"\" width=\"100%\" height=\"100%\" frameborder=\"0\" data-modal-els=\"iframe\" style=\"position: absolute;left:0;top:0;\"></iframe>\n </div>\n <form name=\"{{modalId}}-form\" data-modal-els=\"iframe-form\">\n <input type=\"hidden\" name=\"modalId\" value=\"{{modalId}}\" />\n {{#param}}\n {{#@each}}\n <input type=\"hidden\" name=\"{{@key}}\" value=\"{{@value}}\" />\n {{/@each}}\n {{/param}}\n </form>\n {{/iframe}}\n {{^iframe}}\n <div data-modal-els=\"body-frame\" style=\"position: absolute;left:0;top:0;width:100%;height:100%;\"></div>\n {{/iframe}}\n </div>\n {{^disableResize}}\n <div data-ax5modal-resizer=\"top\"></div>\n <div data-ax5modal-resizer=\"right\"></div>\n <div data-ax5modal-resizer=\"bottom\"></div>\n <div data-ax5modal-resizer=\"left\"></div>\n <div data-ax5modal-resizer=\"top-left\"></div>\n <div data-ax5modal-resizer=\"top-right\"></div>\n <div data-ax5modal-resizer=\"bottom-left\"></div>\n <div data-ax5modal-resizer=\"bottom-right\"></div>\n {{/disableResize}}\n </div>\n ";
  1037. };
  1038. MODAL.tmpl = {
  1039. "content": content,
  1040. get: function get(tmplName, data, columnKeys) {
  1041. return ax5.mustache.render(MODAL.tmpl[tmplName].call(this, columnKeys), data);
  1042. }
  1043. };
  1044. })();