diff --git a/asset/webcomponent/module/swipe.js b/asset/webcomponent/module/swipe.js new file mode 100644 index 0000000..64a4aff --- /dev/null +++ b/asset/webcomponent/module/swipe.js @@ -0,0 +1,94 @@ +/** + * JQuery Mobile Swipe + * + * This plugin adds some classes to html's DOM which can be used as fallback for action such as :hover which are not + * always intuitive on mobile ( and sometimes, unexisting ). + + * Based on jquery.detectSwipe v2.1.1 [http://github.com/marcandre/detect_swipe] which is based on touchwipe by Andreas Waltl, netCU Internetagentur (http://www.netcu.de) + */ +(function ($) { + $.mobileswipe = { + attach : register, + enabled : 'ontouchstart' in document.documentElement, + threshold : 20, + reset_timer : null + }; + + $.fn.mobileswipe = register; + + $.event.special.swipe = { setup: register }; + + $.each(['left', 'up', 'down', 'right'], function () { + $.event.special['swipe' + this] = {setup: function () { + $(this).on('swipe', $.noop); + }}; + }); + + $(function() { $('.swipe').mobileswipe(); }); + + var startX, startY, + timeout_instance = [], + isMoving = false; + + function onTouchEnd() { + this.removeEventListener('touchmove', onTouchMove); + this.removeEventListener('touchend', onTouchEnd); + isMoving = false; + } + + function onTouchMove(e) { + if (isMoving) { + var dir, delta, $this = $(this); + + if (Math.abs(delta = startX - e.touches[0].pageX) >= $.mobileswipe.threshold) { + dir = delta > 0 ? 'left' : 'right'; + $this.removeClass('swipe-left swipe-right'); + } + else if (Math.abs(delta = startY - e.touches[0].pageY) >= $.mobileswipe.threshold) { + dir = delta < 0 ? 'down' : 'up'; + $this.removeClass('swipe-down swipe-up'); + } + + if ( dir ) { + onTouchEnd.call(this); + $this.trigger('swipe', dir).trigger('swipe' + dir).addClass('swipe-' + dir); + checkPersistency($this, dir, $this.data('reset-timer')); + } + } + } + + function onTouchStart(e) { + if (e.touches.length === 1) { + startX = e.touches[0].pageX; + startY = e.touches[0].pageY; + isMoving = true; + + this.addEventListener('touchmove', onTouchMove, false); + this.addEventListener('touchend', onTouchEnd, false); + } + } + + function checkPersistency($elem, dir, timer) { + timer || ( timer = $.mobileswipe.reset_timer ); + + if ( timer ) { + (dir in timeout_instance) && clearTimeout(timeout_instance[dir]); + + timeout_instance[dir] = setTimeout(function() { + $elem.removeClass('swipe-'+dir); + }, timer); + } + } + + function register() { + $(this).each(function() { + this.addEventListener && this.addEventListener('touchstart', onTouchStart, false); + }); + } + + function unregister() { + $(this).each(function() { + this.removeEventListener('touchstart', onTouchStart); + }); + } +})(jQuery); \ No newline at end of file diff --git a/asset/webcomponent/module/ui-popup.js b/asset/webcomponent/module/ui-popup.js index 395f869..0ce6621 100644 --- a/asset/webcomponent/module/ui-popup.js +++ b/asset/webcomponent/module/ui-popup.js @@ -13,6 +13,14 @@ class UiPopup extends Webcomponent { this.message = this.querySelector('.message'); this.title = this.querySelector('.title'); + if (!this.message) { + this.message = document.createElement("div"); + } + + if (!this.title) { + this.title = document.createElement("div"); + } + this.replaceVarsPlaceholder().attach().render(); this.init(); @@ -55,25 +63,32 @@ class UiPopup extends Webcomponent { init() { document.addEventListener('keyup', function(e) { if ( this.visible() ) { - let trigger, ev; + let trigger, ev, action; e.preventDefault(); // There's no real value in checking if the popup is shown or not. switch ( e.keyCode ) { case 13: // RETURN - trigger = this.querySelector('[action="confirm"]'); - ev = new CustomEvent('click', { trigger: trigger } ); - - trigger.dispatchEvent(ev); + action = "confirm"; break; case 27: // ESC - trigger = this.querySelector('[action="close"]'); - ev = new CustomEvent('click', { trigger: trigger } ); + action = "close"; + break + } + + if (action) { + trigger = this.querySelector(`[action="${action}"]`); + + if ( trigger ) { + ev = new CustomEvent('click', {trigger: trigger}); trigger.dispatchEvent(ev); - break; + } + else { + this.hide(); + } } } }.bind(this)); @@ -98,7 +113,7 @@ class UiPopup extends Webcomponent { } render() { - this.querySelectorAll('[action]').forEach(function(element) { + this.querySelectorAll('[action]:not(form)').forEach(function(element) { element.addEventListener("click", this.action.bind(this, element), false); }.bind(this)); @@ -116,10 +131,13 @@ class UiPopup extends Webcomponent { case "ok": let retval = this.actionFollowLink(element) || this.actionClickButton(element); + if (! retval) { retval = this.actionSendForm(element) || this.actionSendForm(this.trigger) || - this.actionSendForm(element.closest('ui-popup').querySelector('form')); + this.actionSendForm(this.querySelector('[slot="message"] form')) || + this.actionSendForm(this.querySelector('[slot="title"] form')) || + this.actionSendForm(this.querySelector('[slot="buttons"] form')); if ( ! retval ) { throw "No action to trigger automatically on Popup confirmation."; @@ -181,7 +199,7 @@ class UiPopup extends Webcomponent { let tag = this.trigger.tagName.toLowerCase(); // Automatically redirect to given location if it exists. - if ( tag === "button" || ( ( tag === "input" ) && ( this.trigger.getAttribute("type").toLowerCase() === "submit") ) ) { + if ( ( tag === "button" || tag === "input" ) && this.trigger.getAttribute("type").toLowerCase() === "submit") { this.pause = true; this.trigger.click(); @@ -205,7 +223,7 @@ class UiPopup extends Webcomponent { let form = element.tagName === "FORM" ? element : element.closest('FORM'); if ( form ) { -// form.addEventListener("submit", e => this.hide); + form.addEventListener("submit", e => this.hide, { once: true }); let submitBtn = form.querySelector("button[type='submit']"); @@ -233,7 +251,6 @@ class UiPopup extends Webcomponent { this.trigger = item; args.vars && Object.keys(args.vars).map(function(objectKey, index) { -// let element = this.message.querySelectorAll(`.${objectKey}`); let element = Array.prototype.slice.call( this.message.querySelectorAll(`.${objectKey}`) ).concat(Array.prototype.slice.call(this.title.querySelectorAll(`.${objectKey}`))); element.length ? element.forEach(function(item) { @@ -244,22 +261,41 @@ class UiPopup extends Webcomponent { }.bind(this)); if ( args.options ) { + if (args.options['clear_input']) { + let skipInput = args.options['clear_input']['skip'] ? args.options['clear_input']['skip'] : []; + + this.querySelectorAll(`input,textarea`).forEach(function(f) { + if (! skipInput.includes(f.name)) { + f.value = ""; + } + }); + } + args.options['input'] && Object.keys(args.options['input']).forEach( key => this.querySelectorAll(`[name="${key}"]`).forEach(function(f) { - if (f.tagName === "TEXTAREA") { - f.value = args.options['input'][key]; - } - else { - f.setAttribute("value", args.options['input'][key]); - } - + console.log(f); + f.value = args.options['input'][key]; f.dispatchEvent(new Event("change")); }) ); + + args.options['form_url'] && Object.keys(args.options['form_url']).forEach( + key => { + let form = this.querySelector(`form${key}`); + + if (form) { + form.setAttribute('action', args.options['form_url'][key]); + } + else { + console.warn(`Form selector '${key}' could not be found within popup.`); + } + } + ); } this.show(); + e.stopPropagation(); return true; } diff --git a/asset/webcomponent/module/ui-textarea.js b/asset/webcomponent/module/ui-textarea.js index d4cd68e..be0e567 100644 --- a/asset/webcomponent/module/ui-textarea.js +++ b/asset/webcomponent/module/ui-textarea.js @@ -41,7 +41,9 @@ class UiTextarea extends Webcomponent { render() { document.execCommand("DefaultParagraphSeparator", false, "p"); - this.content.innerHTML = this.textarea.value.trim(); + this.textarea.addEventListener("change", (e) => this.content.innerHTML = this.textarea.value.trim()); + + this.textarea.dispatchEvent(new Event("change")); this.content.addEventListener("input", function(e, d) { this.content.querySelectorAll('[style]').forEach(function(element) { diff --git a/view/webcomponent/ui-popup.phtml b/view/webcomponent/ui-popup.phtml index e66e844..990b0dc 100644 --- a/view/webcomponent/ui-popup.phtml +++ b/view/webcomponent/ui-popup.phtml @@ -5,8 +5,8 @@ ui-popup > * {padding:1.5rem} ui-popup .button-list {text-align:right;} ui-popup .button-list .button {padding: 0px 7%;} + ui-popup [slot="title"] {font-size:1.5rem;display:flex;justify-content: space-between;background:rgba(120,120,120,0.12);color:#464646} ui-popup [slot="message"] {background: transparent;padding:1.2rem 1.5rem!important} - ui-popup [slot="title"] {font-size:1.5rem;display:flex;justify-content: space-between;background:rgba(120,120,120,0.12)} ui-popup [slot="buttons"] {background:rgba(120,120,120,0.07)} ui-popup::before {left:0;right:0;top:0;bottom:0;background:rgba(0,0,0,0.1);content:" ";}