Top
craft-uikit
craft-widget-

UI/ModalViewController.js

  1. import { View } from './View.js';
  2. import { Transition } from '../Core/Transition.js';
  3. /**
  4. * ViewController for Modal.
  5. *
  6. * If you put full page content,
  7. * you have to set content background color by yourself to fill the safe area.
  8. *
  9. * ```
  10. * modalViewController.setContent(modal_page);
  11. * modalViewController.content.style['background-color'] = '#fff';
  12. * ```
  13. *
  14. * @packagename Craft.UI.ModalViewController
  15. *
  16. * @example
  17. *
  18. * const modalViewController = new Craft.UI.ModalViewController();
  19. * modalViewController.loadView();
  20. *
  21. * const dialog = new Dialog({
  22. * closeHandler : () => {
  23. * modalViewController.hideContent( () => {
  24. * dialog.unloadView();
  25. * modalViewController.unloadView();
  26. * });
  27. * }
  28. * });
  29. * dialog.loadView();
  30. *
  31. * modalViewController.setContent(dialog);
  32. *
  33. * Craft.Core.Context.getRootViewController().appendView(modalViewController);
  34. * modalViewController.showContent();
  35. *
  36. */
  37. export class ModalViewController extends View {
  38. /**
  39. * ModalViewController Constructor
  40. *
  41. * You can customize modal behaviour via `this.MaskConfig` and `this.AnimationConfig`.
  42. * See the code if needed.
  43. */
  44. constructor(){
  45. super();
  46. this.packagename = 'Craft.UI.ModalViewController';
  47. this.MaskConfig = {};
  48. this.MaskConfig.color = '#000';
  49. this.MaskConfig.opacity = 0.5;
  50. this.AnimationConfig = {};
  51. this.AnimationConfig.duration = 150;
  52. this.AnimationConfig.delayShow = 0;
  53. this.AnimationConfig.delayHide = 150;
  54. this.mask = '';
  55. this.container = '';
  56. this.content = '';
  57. this.viewController = '';
  58. }
  59. /**
  60. * override viewDidLoad:
  61. * @override
  62. * @param {Function} callback - callback
  63. */
  64. viewDidLoad(callback){
  65. this.mask = this.shadow.getElementById('mask');
  66. this.container = this.shadow.getElementById('container');
  67. this.view.addEventListener('touchmove',(e) => { e.preventDefault(); });
  68. this.mask.addEventListener('touchmove',(e) => { e.preventDefault(); });
  69. }
  70. /**
  71. * Set modal content
  72. * @param {Craft.Core.Component} component - component
  73. */
  74. setContent(component){
  75. if( !component.isViewLoaded ){
  76. component.loadView();
  77. }
  78. this.content = component;
  79. this.content.setViewController(this);
  80. this.container.style['margin-top'] = String(window.screen.height)+'px';
  81. this.container.innerHTML = '';
  82. this.content.viewWillAppear();
  83. this.container.appendChild(this.content.view);
  84. }
  85. /**
  86. * Show mask
  87. * @param {Function} callback - callback
  88. */
  89. showMask(callback){
  90. this.mask.style['display'] = 'block';
  91. this.mask.style['opacity'] = this.MaskConfig.opacity;
  92. this.mask.style['background-color'] = this.MaskConfig.color;
  93. if( callback ){ callback(); }
  94. }
  95. /**
  96. * Hide mask
  97. * @param {Function} callback - callback
  98. */
  99. hideMask(callback){
  100. Transition.animate({
  101. element : this.mask,
  102. properties : { 'opacity': 0 },
  103. duration : this.AnimationConfig.duration,
  104. delay : this.AnimationConfig.delayHide,
  105. callback : () => {
  106. this.mask.style['display'] = 'none';
  107. if( callback ){ callback(); }
  108. },
  109. });
  110. }
  111. /**
  112. * Show modal content
  113. * @param {Function} callback - callback
  114. */
  115. showContent(callback){
  116. this.showMask();
  117. this.content.viewDidAppear();
  118. Transition.animate({
  119. element : this.container,
  120. properties : { 'margin-top': '0px' },
  121. duration : this.AnimationConfig.duration,
  122. delay : this.AnimationConfig.delayShow,
  123. callback : callback,
  124. });
  125. }
  126. /**
  127. * Hide modal content
  128. * @param {Function} callback - callback
  129. */
  130. hideContent(callback){
  131. this.hideMask();
  132. this.content.viewWillDisappear();
  133. Transition.animate({
  134. element : this.container,
  135. properties : { 'margin-top': String(window.screen.height)+'px' },
  136. duration : this.AnimationConfig.duration,
  137. delay : this.AnimationConfig.delay,
  138. callback : () => {
  139. this.content.viewDidDisappear();
  140. this.hideMask(callback);
  141. }
  142. });
  143. }
  144. /**
  145. * style
  146. * @protected
  147. */
  148. style(){
  149. return `
  150. * {
  151. box-sizing:border-box; margin:0; padding:0;
  152. }
  153. :host {
  154. position: fixed;
  155. top: 0;
  156. left: 0;
  157. width: 100vw;
  158. height: 100vh;
  159. overflow-x: hidden;
  160. overflow-y: hidden;
  161. -webkit-tap-highlight-color:rgba(0,0,0,0);
  162. -webkit-touch-callout: none;
  163. }
  164. .root {
  165. width: 100vw;
  166. height: 100vh;
  167. -webkit-tap-highlight-color:rgba(0,0,0,0);
  168. -webkit-touch-callout: none;
  169. }
  170. .mask {
  171. position: fixed;
  172. top: 0;
  173. left: 0;
  174. width: 100vw;
  175. height: 100vh;
  176. padding-top: env(safe-area-inset-top);
  177. padding-bottom: env(safe-area-inset-bottom);
  178. background-color: #000;
  179. opacity: 0.5;
  180. overflow-x: hidden;
  181. overflow-y: hidden;
  182. -webkit-tap-highlight-color:rgba(0,0,0,0);
  183. -webkit-touch-callout: none;
  184. }
  185. .container {
  186. display: block;
  187. position: absolute;
  188. top: 0px;
  189. left: 0px;
  190. margin-top: 0px;
  191. padding-top: env(safe-area-inset-top);
  192. padding-bottom: env(safe-area-inset-bottom);
  193. min-width: 100vw;
  194. height: 100vh;
  195. color: #000;
  196. overflow-x: hidden;
  197. overflow-y: hidden;
  198. }
  199. `;
  200. }
  201. /**
  202. * template
  203. * @protected
  204. */
  205. template(){
  206. return `
  207. <div class="root">
  208. <div id="mask" class="mask"></div>
  209. <div id="container" class="container"></div>
  210. </div>
  211. `;
  212. }
  213. }