From bc926ffb90c058bdd98fa1069d17a9b1fd49f873 Mon Sep 17 00:00:00 2001 From: wpalani Date: Sun, 8 Oct 2023 19:32:46 -0700 Subject: [PATCH] Add dialog php, js and css --- bootstrap.php | 9 + includes/DeactivationSurvey.php | 79 ++++++++ includes/assets/css/deactivation-survey.css | 188 ++++++++++++++++++++ includes/assets/js/a11y-dialog.min.js | 2 + includes/assets/js/deactivation-survey.js | 127 +++++++++++++ 5 files changed, 405 insertions(+) create mode 100644 includes/DeactivationSurvey.php create mode 100644 includes/assets/css/deactivation-survey.css create mode 100644 includes/assets/js/a11y-dialog.min.js create mode 100644 includes/assets/js/deactivation-survey.js diff --git a/bootstrap.php b/bootstrap.php index cea139c..5c3b38f 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -1,6 +1,7 @@ deactivation_survey_assets(); + $this->deactivation_survey_runtime(); + } + + public function deactivation_survey_assets() { + $assetsDir = container()->plugin()->url . 'vendor/newfold-labs/wp-module-data/includes/assets/'; + + // accessible a11y dialog + wp_register_script( + 'nfd-data-a11y-dialog', + $assetsDir . 'js/a11y-dialog.min.js', + array(), + '8.0.4', + ); + + // deactivation-survey.js + wp_enqueue_script( + 'nfd-data-deactivation-survey', + $assetsDir . 'js/deactivation-survey.js', + array( 'nfd-data-a11y-dialog' ), + container()->plugin()->version, + true + ); + + // Styles + wp_enqueue_style( + 'nfd-data-deactivation-survey-style', + $assetsDir . 'css/deactivation-survey.css', + array(), + container()->plugin()->version + ); + } + + public function deactivation_survey_runtime() { + $plugin_slug = explode( '/', container()->plugin()->basename )[0]; + + wp_localize_script( + 'nfd-data-deactivation-survey', + 'newfoldDataDeactivationSurvey', + array( + 'restApiRoot' => \get_home_url() . '/index.php?rest_route=', + 'restApiNonce' => wp_create_nonce( 'wp_rest' ), + 'brand' => ucwords( container()->plugin()->id ), + 'pluginSlug' => $plugin_slug, + 'strings' => array( + 'surveyTitle' => __( 'Plugin Deactivation Survey', $plugin_slug ), + 'dialogTitle' => __( 'Thank You for Using the ' . ucwords( container()->plugin()->id ) . ' Plugin!', $plugin_slug ), + 'dialogDesc' => __( 'Please take a moment to let us know why you\'re deactivating this plugin.', $plugin_slug ), + 'formAriaLabel' => __( 'Plugin Deactivation Form', $plugin_slug ), + 'label' => __( 'Why are you deactivating this plugin?', $plugin_slug ), + 'placeholder' => __( 'Please share the reason here...', $plugin_slug ), + 'submit' => __( 'Submit & Deactivate', $plugin_slug ), + 'submitAriaLabel' => __( 'Submit and Deactivate Plugin', $plugin_slug ), + 'cancel' => __( 'Cancel', $plugin_slug ), + 'cancelAriaLabel' => __( 'Cancel Deactivation', $plugin_slug ), + 'skip' => __( 'Skip & Deactivate', $plugin_slug ), + 'skipAriaLabel' => __( 'Skip and Deactivate Plugin', $plugin_slug ), + ) + ) + ); + } + +} diff --git a/includes/assets/css/deactivation-survey.css b/includes/assets/css/deactivation-survey.css new file mode 100644 index 0000000..d57c951 --- /dev/null +++ b/includes/assets/css/deactivation-survey.css @@ -0,0 +1,188 @@ +#nfd-deactivation-survey { + z-index: 100000; + display: flex; + justify-content: center; + align-items: center; +} + +#nfd-deactivation-survey[aria-hidden="true"] { + display: none; +} + +#nfd-deactivation-survey, +.nfd-deactivation-survey__overlay, +.nfd-deactivation-survey__disabled { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; +} + +.nfd-deactivation-survey__overlay { + background-color: rgba(43, 46, 56, 0.9); + animation: nfd-fade-in 200ms both; +} + +.nfd-deactivation-survey__disabled { + z-index: 2; +} + +.nfd-deactivation-survey__container { + position: relative; + background-color: white; + color: #3C434A; + max-height: 80vh; + width: 600px; + max-width: 80vw; + padding: 1.5rem; + border-radius: 5px; + animation: nfd-fade-in 400ms 200ms both, nfd-slide-up 400ms 200ms both; +} + +.nfd-deactivation-survey__container button[aria-label="Close dialog"] { + position: absolute; + top: 5px; + right: 5px; + padding: .5rem; + border: none; + background-color: transparent; + color: #3C434A; + cursor: pointer; + font-size: 1.75rem; + line-height: unset; +} + +.nfd-deactivation-survey__content-header { + padding-bottom: .85rem; + border-bottom: 1px solid #E5E5E5; +} + +.nfd-deactivation-survey__content-header h3 { + margin: 0 0 .45rem; + font-size: 1rem; + color: #3C434A; +} + +.nfd-deactivation-survey__content-header p { + margin: 0; + font-size: .85rem; +} + +.nfd-deactivation-survey__content form { + display: flex; + flex-direction: column; + width: 100%; + margin-top: 1.5rem; + gap: 1rem; +} + +.nfd-deactivation-survey__content form label { + display: inline-block; + margin-bottom: 8px; +} + +.nfd-deactivation-survey__content form textarea { + width: 100%; + border-color: #8B8F94; + padding: 8px; + min-height: 60px; + max-height: 150px; +} + +.nfd-deactivation-survey__content form textarea::placeholder { + font-size: 13px; +} + +.nfd-deactivation-survey__content-actions { + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; +} + +.nfd-deactivation-survey__content-actions > div { + display: flex; + align-items: center; + gap: .75rem; +} + +.nfd-deactivation-survey-action { + color: #525354; + background-color: transparent; + padding: 2px; + border: none; + text-decoration: unset; + cursor: pointer; +} + +.nfd-deactivation-survey-action:hover { + text-decoration: underline; +} + +.nfd-deactivation-survey-action:disabled { + opacity: .55; +} + +.nfd-hidden { + display: none !important; +} + +.nfd-visually-hidden { + visibility: hidden; +} + +.nfd-deactivation-survey_loading { + width: 100%; + height: 4.8px; + display: inline-block; + position: relative; + background: #e5ebf0; + border-radius: 99px; + overflow: hidden; + margin-top: 1rem; +} + +.nfd-deactivation-survey_loading::after { + content: ''; + width: 20%; + height: 4.8px; + background: #2270B1; + position: absolute; + top: 0; + left: 0; + box-sizing: border-box; + animation: nfd-submitting 1.5s linear infinite; + border-radius: 99px; +} + +/* animations */ +@keyframes nfd-submitting { + 0% { + left: 0; + transform: translateX(-100%); + } + 100% { + left: 100%; + transform: translateX(0%); + } +} + +@keyframes nfd-fade-in { + from { + opacity: 0; + } +} + +@keyframes nfd-slide-up { + from { + transform: translateY(10%); + } +} + +@media (max-width: 600px) { + .nfd-deactivation-survey__content-actions { + flex-direction: column; + } +} + \ No newline at end of file diff --git a/includes/assets/js/a11y-dialog.min.js b/includes/assets/js/a11y-dialog.min.js new file mode 100644 index 0000000..44682a9 --- /dev/null +++ b/includes/assets/js/a11y-dialog.min.js @@ -0,0 +1,2 @@ +/*! a11y-dialog 8.0.4 — © Kitty Giraudel */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).A11yDialog=e()}(this,(function(){"use strict";const t=":not([inert]):not([inert] *)",e=':not([tabindex^="-"])',i=":not(:disabled)";var s=[`a[href]${t}${e}`,`area[href]${t}${e}`,`input:not([type="hidden"]):not([type="radio"])${t}${e}${i}`,`input[type="radio"]${t}${e}${i}`,`select${t}${e}${i}`,`textarea${t}${e}${i}`,`button${t}${e}${i}`,`details${t} > summary:first-of-type${e}`,`iframe${t}${e}`,`audio[controls]${t}${e}`,`video[controls]${t}${e}`,`[contenteditable]${t}${e}`,`[tabindex]${t}${e}`];function o(t){(t.querySelector("[autofocus]")||t).focus()}function n(t,e){if(e&&d(t))return t;if(!((i=t).shadowRoot&&"-1"===i.getAttribute("tabindex")||i.matches(":disabled,[hidden],[inert]")))if(t.shadowRoot){let i=r(t.shadowRoot,e);for(;i;){const t=n(i,e);if(t)return t;i=a(i,e)}}else if("slot"===t.localName){const i=t.assignedElements({flatten:!0});e||i.reverse();for(const t of i){const i=n(t,e);if(i)return i}}else{let i=r(t,e);for(;i;){const t=n(i,e);if(t)return t;i=a(i,e)}}var i;return!e&&d(t)?t:null}function r(t,e){return e?t.firstElementChild:t.lastElementChild}function a(t,e){return e?t.nextElementSibling:t.previousElementSibling}const d=t=>!t.shadowRoot?.delegatesFocus&&(t.matches(s.join(","))&&!(t=>!(!t.matches("details:not([open]) *")||t.matches("details>summary:first-of-type"))||!(t.offsetWidth||t.offsetHeight||t.getClientRects().length))(t));function l(t=document){const e=t.activeElement;return e?e.shadowRoot?l(e.shadowRoot)||document.activeElement:e:null}function h(t,e){const[i,s]=function(t){const e=n(t,!0);return[e,e?n(t,!1)||e:null]}(t);if(!i)return e.preventDefault();const o=l();e.shiftKey&&o===i?(s.focus(),e.preventDefault()):e.shiftKey||o!==s||(i.focus(),e.preventDefault())}class u{$el;id;previouslyFocused;shown;constructor(t){this.$el=t,this.id=this.$el.getAttribute("data-a11y-dialog")||this.$el.id,this.previouslyFocused=null,this.shown=!1,this.maintainFocus=this.maintainFocus.bind(this),this.bindKeypress=this.bindKeypress.bind(this),this.handleTriggerClicks=this.handleTriggerClicks.bind(this),this.show=this.show.bind(this),this.hide=this.hide.bind(this),this.$el.setAttribute("aria-hidden","true"),this.$el.setAttribute("aria-modal","true"),this.$el.setAttribute("tabindex","-1"),this.$el.hasAttribute("role")||this.$el.setAttribute("role","dialog"),document.addEventListener("click",this.handleTriggerClicks,!0)}destroy(){return this.hide(),document.removeEventListener("click",this.handleTriggerClicks,!0),this.$el.replaceWith(this.$el.cloneNode(!0)),this.fire("destroy"),this}show(t){return this.shown||(this.shown=!0,this.$el.removeAttribute("aria-hidden"),this.previouslyFocused=l(),"BODY"===this.previouslyFocused?.tagName&&t?.target&&(this.previouslyFocused=t.target),"focus"===t?.type?this.maintainFocus(t):o(this.$el),document.body.addEventListener("focus",this.maintainFocus,!0),this.$el.addEventListener("keydown",this.bindKeypress,!0),this.fire("show",t)),this}hide(t){return this.shown?(this.shown=!1,this.$el.setAttribute("aria-hidden","true"),this.previouslyFocused?.focus?.(),document.body.removeEventListener("focus",this.maintainFocus,!0),this.$el.removeEventListener("keydown",this.bindKeypress,!0),this.fire("hide",t),this):this}on(t,e,i){return this.$el.addEventListener(t,e,i),this}off(t,e,i){return this.$el.removeEventListener(t,e,i),this}fire(t,e){this.$el.dispatchEvent(new CustomEvent(t,{detail:e,cancelable:!0}))}handleTriggerClicks(t){const e=t.target;e.closest(`[data-a11y-dialog-show="${this.id}"]`)&&this.show(t),(e.closest(`[data-a11y-dialog-hide="${this.id}"]`)||e.closest("[data-a11y-dialog-hide]")&&e.closest('[aria-modal="true"]')===this.$el)&&this.hide(t)}bindKeypress(t){if(document.activeElement?.closest('[aria-modal="true"]')!==this.$el)return;let e=!1;try{e=!!this.$el.querySelector('[popover]:not([popover="manual"]):popover-open')}catch{}"Escape"!==t.key||"alertdialog"===this.$el.getAttribute("role")||e||(t.preventDefault(),this.hide(t)),"Tab"===t.key&&h(this.$el,t)}maintainFocus(t){t.target.closest('[aria-modal="true"], [data-a11y-dialog-ignore-focus-trap]')||o(this.$el)}}function c(){for(const t of document.querySelectorAll("[data-a11y-dialog]"))new u(t)}return"undefined"!=typeof document&&("loading"===document.readyState?document.addEventListener("DOMContentLoaded",c):c()),u})); \ No newline at end of file diff --git a/includes/assets/js/deactivation-survey.js b/includes/assets/js/deactivation-survey.js new file mode 100644 index 0000000..6f08c3d --- /dev/null +++ b/includes/assets/js/deactivation-survey.js @@ -0,0 +1,127 @@ +{ + let deactivationSurveyDialog; + + const renderDialog = () => { + const surveyDialog = document.createElement('div'); + surveyDialog.id = 'nfd-deactivation-survey'; + surveyDialog.setAttribute('aria-labelledby', 'nfd-deactivation-survey-title'); + surveyDialog.setAttribute('aria-hidden', 'true'); + surveyDialog.innerHTML = getDialogHTML(); + + const wpAdmin = document.querySelector('body.wp-admin'); + wpAdmin.appendChild(surveyDialog); + + deactivationSurveyDialog = new A11yDialog(surveyDialog); + deactivationSurveyDialog.show(); + } + + const getDialogHTML = () => { + const dialogHTML = ` +
+
+
+

${newfoldDataDeactivationSurvey.strings.surveyTitle}

+
+

${newfoldDataDeactivationSurvey.strings.dialogTitle}

+

${newfoldDataDeactivationSurvey.strings.dialogDesc}

+
+
+
+ + +
+
+
+ + +
+
+ +
+
+
+ +
+
+
+ `; + return dialogHTML; + } + + const destroyDialog = () => { + deactivationSurveyDialog.destroy(); + deactivationSurveyDialog = null; + + const dialog = document.getElementById('nfd-deactivation-survey'); + if (dialog) { + dialog.remove(); + } + } + + const deactivatePlugin = () => { + destroyDialog(); + const deactivateLink = document.getElementById('deactivate-' + newfoldDataDeactivationSurvey.pluginSlug).href; + if (deactivateLink) { + window.location.href = deactivateLink; + } else { + console.error('Error: Deactivation link not found.'); + } + } + + isSubmitting = () => { + const dialogDisabledOverlay = document.querySelector('.nfd-deactivation-survey__disabled'); + dialogDisabledOverlay.classList.remove('nfd-hidden'); + const dialogLoading = document.querySelector('.nfd-deactivation-survey_loading'); + dialogLoading.classList.remove('nfd-hidden'); + const actionsBtns = [ + ...document.querySelectorAll('.nfd-deactivation-survey-action'), + document.querySelector('#nfd-deactivation-survey form input[type="submit"]'), + ]; + actionsBtns.forEach(btn => { + btn.setAttribute('disabled', 'true'); + }); + + // disbale ESC key while submitting + deactivationSurveyDialog.on('show', () => { + deactivationSurveyDialog.off('keydown'); + }); + } + + submitSurvey = () => { + isSubmitting(); + const surveyInput = document.getElementById('nfd-deactivation-survey__input').value; + setTimeout(() => { + console.log(surveyInput); + deactivatePlugin(); + }, 3000); + } + + // Attach events listeners + window.addEventListener('DOMContentLoaded', () => { + const wpAdmin = document.querySelector('body.wp-admin'); + wpAdmin.addEventListener('click', (e) => { + // Plugin deactivation listener + if (e.target.id === 'deactivate-' + newfoldDataDeactivationSurvey.pluginSlug) { + e.preventDefault(); + renderDialog(); + } + + // Remove dialog listener + if (e.target.hasAttribute('nfd-deactivation-survey-destroy')) { + destroyDialog(); + } + + // Submit listener + if (e.target.hasAttribute('nfd-deactivation-survey-submit')) { + e.preventDefault(); + submitSurvey(); + } + + // Skip listener + if (e.target.hasAttribute('nfd-deactivation-survey-skip')) { + e.preventDefault(); + deactivatePlugin(); + } + }); + }) +} \ No newline at end of file