Top
craft-uikit
craft-widget-

UI/ModalViewController.js


import { View } from './View.js';
import { Transition } from '../Core/Transition.js';

/** 
 * ViewController for Modal.
 * 
 * If you put full page content, 
 * you have to set content background color by yourself to fill the safe area.
 * 
 * ``` 
 * modalViewController.setContent(modal_page);
 * modalViewController.content.style['background-color'] = '#fff';
 * ``` 
 * 
 * @packagename Craft.UI.ModalViewController
 * 
 * @example
 * 
 * const modalViewController = new Craft.UI.ModalViewController();
 * modalViewController.loadView();
 * 
 * const dialog = new Dialog({
 *     closeHandler : () => {
 *         modalViewController.hideContent( () => {
 *             dialog.unloadView();
 *             modalViewController.unloadView();
 *         });
 *     }
 * });
 * dialog.loadView();
 * 
 * modalViewController.setContent(dialog);
 * 
 * Craft.Core.Context.getRootViewController().appendView(modalViewController);
 * modalViewController.showContent();
 * 
 */
export class ModalViewController extends View {
	
	/**
	 * ModalViewController Constructor
	 * 
	 * You can customize modal behaviour via `this.MaskConfig` and `this.AnimationConfig`.  
	 * See the code if needed.
	 */
	constructor(){
		super();
		
		this.packagename = 'Craft.UI.ModalViewController';
		
		this.MaskConfig = {};
		this.MaskConfig.color = '#000';
		this.MaskConfig.opacity = 0.5;
		
		this.AnimationConfig = {};
		this.AnimationConfig.duration  = 150;
		this.AnimationConfig.delayShow = 0;
		this.AnimationConfig.delayHide = 150;
		
		this.mask = '';
		this.container = '';
		
		this.content = '';
		this.viewController = '';
	}
	
	/**
	 * override viewDidLoad: 
	 * @override
	 * @param {Function} callback - callback
	 */
	viewDidLoad(callback){
		this.mask = this.shadow.getElementById('mask');
		this.container = this.shadow.getElementById('container');
		this.view.addEventListener('touchmove',(e) => { e.preventDefault(); });
		this.mask.addEventListener('touchmove',(e) => { e.preventDefault(); });
	}
	
	/**
	 * Set modal content
	 * @param {Craft.Core.Component} component - component
	 */
	setContent(component){
		if( !component.isViewLoaded ){
			component.loadView();
		}
		this.content = component;
		this.content.setViewController(this);
		this.container.style['margin-top'] = String(window.screen.height)+'px';
		this.container.innerHTML = '';
		this.content.viewWillAppear();
		this.container.appendChild(this.content.view);
	}
	
	/**
	 * Show mask
	 * @param {Function} callback - callback
	 */
	showMask(callback){
		this.mask.style['display']          = 'block';
		this.mask.style['opacity']          = this.MaskConfig.opacity;
		this.mask.style['background-color'] = this.MaskConfig.color;
		if( callback ){ callback(); }
	}
	
	/**
	 * Hide mask
	 * @param {Function} callback - callback
	 */
	hideMask(callback){
		Transition.animate({
			element    : this.mask,
			properties : { 'opacity': 0 },
			duration   : this.AnimationConfig.duration,
			delay      : this.AnimationConfig.delayHide,
			callback   : () => {
				this.mask.style['display'] = 'none';
				if( callback ){ callback(); }
			},
		});
	}
	
	/**
	 * Show modal content
	 * @param {Function} callback - callback
	 */
	showContent(callback){
		this.showMask();
		this.content.viewDidAppear();
		Transition.animate({
			element    : this.container,
			properties : { 'margin-top': '0px' },
			duration   : this.AnimationConfig.duration,
			delay      : this.AnimationConfig.delayShow,
			callback   : callback,
		});
	}
	
	/**
	 * Hide modal content
	 * @param {Function} callback - callback
	 */
	hideContent(callback){
		this.hideMask();
		this.content.viewWillDisappear();
		Transition.animate({
			element    : this.container,
			properties : { 'margin-top': String(window.screen.height)+'px' },
			duration   : this.AnimationConfig.duration,
			delay      : this.AnimationConfig.delay,
			callback   : () => {
				this.content.viewDidDisappear();
				this.hideMask(callback);
			}
		});
	}
	
	/**
	 * style
	 * @protected
	 */
	style(){
		return `
			* { 
				box-sizing:border-box; margin:0; padding:0;
			}
			:host {
				position: fixed;
				top: 0;
				left: 0;
				width: 100vw;
				height: 100vh;
				overflow-x: hidden;
				overflow-y: hidden;
				-webkit-tap-highlight-color:rgba(0,0,0,0);
				-webkit-touch-callout: none;
			}
			.root {
				width: 100vw;
				height: 100vh;
				-webkit-tap-highlight-color:rgba(0,0,0,0);
				-webkit-touch-callout: none;
			}
			.mask {
				position: fixed;
				top: 0;
				left: 0;
				width: 100vw;
				height: 100vh;
				padding-top: env(safe-area-inset-top);
				padding-bottom: env(safe-area-inset-bottom);
				background-color: #000;
				opacity: 0.5;
				overflow-x: hidden;
				overflow-y: hidden;
				-webkit-tap-highlight-color:rgba(0,0,0,0);
				-webkit-touch-callout: none;
			}
			.container {
				display: block;
				position: absolute;
				top: 0px;
				left: 0px;
				margin-top: 0px;
				padding-top: env(safe-area-inset-top);
				padding-bottom: env(safe-area-inset-bottom);
				min-width: 100vw;
				height: 100vh;
				color: #000;
				overflow-x: hidden;
				overflow-y: hidden;
			}
		`;
	}
	
	/**
	 * template
	 * @protected
	 */
	template(){
		return `
			<div class="root">
				<div id="mask" class="mask"></div>
				<div id="container" class="container"></div>
			</div>
		`;
	}
	

}