Vanilla JS Dialog

A general purpose JavaScript class for Dialog Creation in Vanilla JS.

目前为 2023-05-03 提交的版本。查看 最新版本

此脚本不应直接安装,它是一个供其他脚本使用的外部库。如果您需要使用该库,请在脚本元属性加入:// @require https://update.cn-greasyfork.org/scripts/465421/1184885/Vanilla%20JS%20Dialog.js

  1. // ==UserScript==
  2. // @name Vanilla JS Dialog
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1.1
  5. // @description A general purpose JavaScript class for Dialog Creation in Vanilla JS.
  6. // @author CY Fung
  7. // @grant none
  8. // @license MIT
  9. // ==/UserScript==
  10.  
  11. /*
  12.  
  13. MIT License
  14.  
  15. Copyright (c) 2023 cyfung1031
  16.  
  17. Permission is hereby granted, free of charge, to any person obtaining a copy
  18. of this software and associated documentation files (the "Software"), to deal
  19. in the Software without restriction, including without limitation the rights
  20. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  21. copies of the Software, and to permit persons to whom the Software is
  22. furnished to do so, subject to the following conditions:
  23.  
  24. The above copyright notice and this permission notice shall be included in all
  25. copies or substantial portions of the Software.
  26.  
  27. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  28. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  29. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  30. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  31. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  32. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  33. SOFTWARE.
  34.  
  35. */
  36. /* version: 0.1.1 */
  37. const VanillaJSDialog = (function pluginVanillaJSDialog() {
  38. 'strict';
  39.  
  40. const _themeProps_ = {
  41. dialogBackgroundColor: '#f6f6f6',
  42. dialogBackgroundColorDark: '#23252a',
  43. backdropColor: '#b5b5b568',
  44. textColor: '#343434',
  45. textColorDark: '#f0f3f4',
  46. zIndex: 60000,
  47. fontSize: '10pt',
  48. dialogMinWidth: '320px',
  49. dialogMinHeight: '240px',
  50.  
  51. };
  52.  
  53.  
  54. /* https://www.freeformatter.com/css-beautifier.html */
  55. const _cssForThemeProps_ = ($) =>
  56. `
  57. .vjsd-dialog {
  58. --vjsd-font-family: "Inter var", ui-sans-serif, system-ui, -apple-system, system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  59. --vjsd-dialog-background-color: ${$.dialogBackgroundColor};
  60. --vjsd-dialog-text-color: ${$.textColor};
  61. --vjsd-dialog-border-color: #747474;
  62. --vjsd-inputable-background-color: #fcfcfc;
  63. --vjsd-inputable-text-color: ${$.textColor};
  64. --vjsd-inputable-outline-color: #959494;
  65. --vjsd-inputable-focus-outline-color: #212121;
  66. --vjsd-button-background-color: #FFFFFF;
  67. --vjsd-button-border-color: #959494;
  68. --vjsd-button-text-color: #111827;
  69. --vjsd-button-hover-background-color: rgb(249, 250, 251);
  70. --vjsd-button-hover-border-color: #212121;
  71. }
  72. .vjsd-dialog.vjsd-dark {
  73. --vjsd-dialog-background-color: ${$.dialogBackgroundColorDark};
  74. --vjsd-dialog-text-color: ${$.textColorDark};
  75. --vjsd-dialog-border-color: #878787;
  76. --vjsd-inputable-background-color: #181a1e;
  77. --vjsd-inputable-text-color: ${$.textColorDark};
  78. --vjsd-inputable-outline-color: #757576;
  79. --vjsd-inputable-focus-outline-color: #a7a5a5;
  80. --vjsd-button-background-color: #21262d;
  81. --vjsd-button-border-color: #6a6a6a;
  82. --vjsd-button-text-color: #c9d1d9;
  83. --vjsd-button-hover-background-color: #30363d;
  84. --vjsd-button-hover-border-color: #8b949e;
  85. }
  86. .vjsd-dialog * {
  87. overscroll-behavior: inherit;
  88. }
  89. .vjsd-overscroll-none {
  90. overscroll-behavior: none;
  91. }
  92. .vjsd-overscroll-contain {
  93. overscroll-behavior: contain;
  94. }
  95. .vjsd-overscroll-auto {
  96. overscroll-behavior: auto;
  97. }
  98. .vjsd-dialog {
  99. font-family: var(--vjsd-font-family);
  100. font-size: ${$.fontSize};
  101. display: none;
  102. flex-direction: column;
  103. position: fixed;
  104. pointer-events: all;
  105. top: 50%;
  106. left: 50%;
  107. transform: translate(-50%, -50%);
  108. z-index: ${$.zIndex};
  109. user-select: none;
  110. touch-action: none;
  111. border-radius: 12px;
  112. border: 1px solid var(--vjsd-dialog-border-color);
  113. box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  114. background-color: var(--vjsd-dialog-background-color);
  115. color: var(--vjsd-dialog-text-color);
  116. contain: content;
  117. }
  118. .vjsd-dialog textarea,
  119. .vjsd-dialog input {
  120. font-family: var(--vjsd-font-family);
  121. border: 0;
  122. outline: 1px solid var(--vjsd-inputable-outline-color);
  123. border-radius: 3px;
  124. -webkit-tap-highlight-color: rgba(0, 0, 0, 0.18) !important;
  125. overflow: auto;
  126. -webkit-box-shadow: none;
  127. -moz-box-shadow: none;
  128. box-shadow: none;
  129. resize: none;
  130. /* remove the resize handle on the bottom right */
  131. background-color: var(--vjsd-inputable-background-color);
  132. color: var(--vjsd-inputable-text-color);
  133. outline-color: var(--vjsd-inputable-outline-color);
  134. }
  135. .vjsd-dialog textarea:focus,
  136. .vjsd-dialog input:focus {
  137. outline-color: var(--vjsd-inputable-focus-outline-color);
  138. transition-duration: .1s;
  139. }
  140. .vjsd-title {
  141. padding: 4px 16px;
  142. text-decoration: none #D1D5DB solid;
  143. text-decoration-thickness: auto;
  144. font-weight: 700;
  145. letter-spacing: .6px;
  146. }
  147. .vjsd-dialog-visible {
  148. display: flex;
  149. }
  150. .vjsd-dialog-header {
  151. padding: 7px 12px;
  152. }
  153. .vjsd-dialog-body {
  154. padding: 7px 12px;
  155. }
  156. .vjsd-dialog-footer {
  157. padding: 7px 12px;
  158. }
  159. .vjsd-flex-fill {
  160. flex-grow: 1;
  161. }
  162. .vjsd-space {
  163. flex-grow: 1;
  164. }
  165. .vjsd-buttonicon {
  166. cursor: pointer;
  167. opacity: 0.85;
  168. }
  169. .vjsd-dialog-backdrop {
  170. background-color: ${$.backdropColor};
  171. contain: strict;
  172. }
  173. .vjsd-buttonicon:hover {
  174. opacity: 1.0;
  175. }
  176. .vjsd-icon {
  177. font-size: 180%;
  178. display: inline-flex;
  179. }
  180. .vjsd-button {
  181. display: inline-flex;
  182. background-color: var(--vjsd-button-background-color);
  183. border: 1px solid var(--vjsd-button-border-color);
  184. color: var(--vjsd-button-text-color);
  185. border-radius: .5em;
  186. box-sizing: border-box;
  187. font-family: var(--vjsd-font-family);
  188. font-size: 85%;
  189. font-weight: 600;
  190. padding: .66em .86em;
  191. text-align: center;
  192. text-decoration: none #D1D5DB solid;
  193. text-decoration-thickness: auto;
  194. box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  195. cursor: pointer;
  196. user-select: none;
  197. -webkit-user-select: none;
  198. touch-action: manipulation;
  199. }
  200. .vjsd-button:hover {
  201. background-color: var(--vjsd-button-hover-background-color);
  202. border-color: var(--vjsd-button-hover-border-color);
  203. transition-duration: .1s;
  204. }
  205. .vjsd-button:focus {
  206. outline: 2px solid transparent;
  207. outline-offset: 2px;
  208. }
  209. .vjsd-button:focus-visible {
  210. box-shadow: none;
  211. }
  212. .vjsd-vflex {
  213. display: flex;
  214. flex-direction: column;
  215. align-items: center;
  216. }
  217. .vjsd-dialog-footer.vjsd-hflex {
  218. column-gap: 8px;
  219. }
  220. .vjsd-hflex {
  221. display: flex;
  222. flex-direction: row;
  223. align-items: center;
  224. }
  225. .vjsd-dialog-backdrop {
  226. display: none;
  227. position: fixed;
  228. pointer-events: all;
  229. top: 0;
  230. bottom: 0;
  231. left: 0;
  232. right: 0;
  233. pointer-events: all;
  234. z-index: ${$.zIndex - 1};
  235. /* when modal active */
  236. touch-action: none;
  237. -webkit-overflow-scrolling: none;
  238. overflow: hidden;
  239. /* Other browsers */
  240. overscroll-behavior: none;
  241. }
  242. .vjsd-dialog-body {
  243. min-width: ${$.dialogMinWidth};
  244. min-height: ${$.dialogMinHeight};
  245. }
  246. .vjsd-dialog-body.vjsd-vflex {
  247. align-items: stretch;
  248. }
  249. .vjsd-dialog-backdrop.vjsd-backdrop-visible {
  250. display: flex;
  251. }
  252. label.vjsd-checkbox-label {
  253. font-weight: bold;
  254. line-height: 1.1;
  255. display: flex;
  256. flex-direction: row;
  257. gap: 0.5em;
  258. position: relative;
  259. z-index: 0;
  260. }
  261. label.vjsd-checkbox-label::after {
  262. /* avoid text seleciton */
  263. position: absolute;
  264. content: '';
  265. left: 0;
  266. top: 0;
  267. right: 0;
  268. bottom: 0;
  269. z-index: 1;
  270. }
  271. input.vjsd-checkbox1 {
  272. -webkit-appearance: none;
  273. appearance: none;
  274. /*background-color: var(--vjsd-dialog-background-color);*/
  275. margin: 0;
  276. font: inherit;
  277. color: currentColor;
  278. width: 1.15em;
  279. height: 1.15em;
  280. border: 0.15em solid currentColor;
  281. border-radius: 0.15em;
  282. transform: translateY(-0.075em);
  283. display: grid;
  284. place-content: center;
  285. outline: none;
  286. }
  287. input.vjsd-checkbox1::before {
  288. content: "";
  289. width: 0.65em;
  290. height: 0.65em;
  291. transform: scale(0);
  292. }
  293. input.vjsd-checkbox1:checked::before {
  294. transform: scale(1);
  295. }
  296. input.vjsd-checkbox-tick::before {
  297. transform-origin: bottom left;
  298. transition: 80ms transform ease-in-out;
  299. box-shadow: inset 1em 1em currentColor;
  300. background-color: CanvasText;
  301. clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
  302. }
  303. input.vjsd-checkbox-square::before {
  304. transition: 80ms transform ease-in-out;
  305. box-shadow: inset 1em 1em currentColor;
  306. border-radius: 4px;
  307. }
  308. input.vjsd-checkbox1.vjsd-checkbox-square:checked::before {
  309. transform: scale(0.9);
  310. }
  311. .vjsd-gap-1 {
  312. gap: 3px;
  313. }
  314. .vjsd-gap-2 {
  315. gap: 6px;
  316. }
  317. .vjsd-gap-3 {
  318. gap: 9px;
  319. }
  320. .vjsd-gap-4 {
  321. gap: 12px;
  322. }
  323. .vjsd-gap-5 {
  324. gap: 15px;
  325. }
  326. .sample-textbox {
  327. height: 300px;
  328. }
  329. html.vjsd-dialog-shown {
  330. --vjsd-prevent-scroll-pointer-events: none;
  331. --vjsd-prevent-scroll-overflow: hidden;
  332. }
  333. html,
  334. body {
  335. pointer-events: var(--vjsd-prevent-scroll-pointer-events) !important;
  336. overflow: var(--vjsd-prevent-scroll-overflow) !important;
  337. }
  338. html.vjsd-dialog-shown {
  339. --vjsd-page-background-filter: blur(4px);
  340. --vjsd-page-background-opacity: 0.4;
  341. }
  342. .vjsd-dialog-backdrop,
  343. .vjsd-dialog {
  344. --vjsd-page-background-filter: void;
  345. --vjsd-page-background-opacity: void;
  346. }
  347. body > * {
  348. filter: var(--vjsd-page-background-filter);
  349. opacity: calc(var(--vjsd-page-background-opacity) * 1.0);
  350. }
  351. `;
  352.  
  353.  
  354.  
  355. /**
  356. *
  357. * @typedef { (...args: HTMLElement[]) => void } onElementGenerated
  358. *
  359. * */
  360.  
  361.  
  362.  
  363. // let __ceId__ =0;
  364. // const __ceIdStore__ = new WeakMap();
  365.  
  366. // This is just for common utils.
  367. class VanillaJSDialogMethods {
  368. __widgets__ = {};
  369. /**
  370. * @returns { Object.<string, (...args?: ( onElementGenerated|string|number)[])=>HTMLElement > }
  371. */
  372. get widgets() {
  373. return this.__widgets__
  374. };
  375.  
  376. set widgets(newWidgets) {
  377.  
  378. if ('prototype' in newWidgets) {
  379. // class
  380. newWidgets = new newWidgets;
  381. }
  382.  
  383. // object
  384. Object.assign(this.__widgets__, newWidgets);
  385.  
  386. return true;
  387. }
  388.  
  389. /**
  390. *
  391. * @param {HTMLElement} elm
  392. * @param {string} parentSelector
  393. * @param {string} childSelector
  394. * @returns
  395. */
  396. query(elm, parentSelector, childSelector) {
  397. return elm.closest(parentSelector).querySelector(childSelector)
  398. }
  399.  
  400. /**
  401. *
  402. * @param {HTMLElement} elm
  403. * @param {string} parentSelector
  404. * @param {string} childSelector
  405. * @returns
  406. */
  407. querys(elm, parentSelector, childSelector) {
  408. return elm.closest(parentSelector).querySelectorAll(childSelector)
  409. }
  410.  
  411. /**
  412. * You might override it using userscript manager's css loader.
  413. * @param {...string} urls external url of the css file
  414. */
  415. importCSS(...urls) {
  416. /*
  417.  
  418. // @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js#sha512=qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==
  419. <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js" integrity="sha512-qTXRIMyZIFb8iQcfjXWCO8+M5Tbc38Qi5WzdPOYZHIlZpzBHG3L3by84BBBOiRGiEb7KKtAOAs5qYdUiZiQNNQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  420.  
  421. */
  422. const elements = urls.map(url => {
  423. let elm = document.createElement('link');
  424. elm.setAttribute('rel', 'stylesheet');
  425. elm.setAttribute('href', url);
  426. if(url.includes('#')){
  427. let idx1 = url.indexOf('#');
  428. let idx2 = url.indexOf('=',idx1);
  429. if(idx1 > 1 && idx2 === idx1+7){
  430. let s = url.substring(idx1+1, idx2);
  431. switch(s){
  432. case 'sha256':
  433. case 'sha384':
  434. case 'sha512':
  435. elm.setAttribute('integrity', `${s}-${url.substring(idx2+1)}`);
  436. }
  437. }
  438. }
  439. elm.setAttribute('crossorigin', 'anonymous');
  440. elm.setAttribute('referrerpolicy', 'no-referrer');
  441. // document.head.appendChild(elm);
  442. return elm;
  443. })
  444. document.head.append(...elements);
  445. return urls.length === 1 ? elements[0] : elements;
  446.  
  447. }
  448.  
  449. // ceToString(){
  450. // return `${__ceIdStore__.toString.call(this)} #${__ceIdStore__.get(this)}`;
  451. // }
  452. /**
  453. *
  454. * @param {string} tag
  455. * @param {Object.<string, any?>} props
  456. * @param {Object.<string, string?>} attrs
  457. * @returns {HTMLElement}
  458. */
  459. ce(tag, props, attrs) {
  460.  
  461. /** @type {HTMLElement} */
  462. const elm = (tag instanceof HTMLElement) ? elm :
  463. (typeof tag == 'string') ? document.createElement(tag) :
  464. console.assert(false, "argument invalid");
  465.  
  466. if (props) Object.assign(elm, props);
  467. if (attrs) {
  468. for (const k of Object.keys(attrs)) {
  469. elm.setAttribute(k, attrs[k]);
  470. }
  471. }
  472. // __ceIdStore__.set(elm, ++__ceId__);
  473. // elm.toString = this.ceToString;
  474. return elm;
  475. }
  476.  
  477. /**
  478. *
  479. * @param {string} t
  480. * @param {string} [id]
  481. * @returns
  482. */
  483. addCSS(t, id) {
  484. let styleElm = document.createElement('style');
  485. styleElm.textContent = t;
  486. if (id) styleElm.id = id;
  487. document.head.appendChild(styleElm);
  488. return styleElm;
  489. }
  490.  
  491. randomInputId() {
  492. const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
  493. const resultArr = new Array(8);
  494. for (let i = 0; i < 8; i++) {
  495. resultArr[i] = chars.charAt(Math.floor(Math.random() * (i ? 36 : 26)));
  496. }
  497. return resultArr.join('');
  498. }
  499.  
  500. /**
  501. *
  502. * @param {HTMLElement} elm
  503. * @param {Object.<string, string|number> | Function | any[]} args
  504. * @returns
  505. * */
  506. st(elm, ...args) {
  507. console.assert(elm instanceof HTMLElement, 'HTMLElement shall be required.');
  508. if (args.length === 0) return;
  509. if ('length' in args[0]) args = args[0];
  510.  
  511. let f = null;
  512. for (const arg of args) {
  513. if (typeof arg == 'function') {
  514. f = arg;
  515. } else if (typeof arg == 'object') {
  516. const obj = arg;
  517. for (const k of Object.keys(obj)) {
  518. if (k in elm) {
  519. if (k === 'className' && elm[k].length > 0) obj[k] = `${elm[k]} ${obj[k]}`;
  520. elm[k] = obj[k];
  521. } else elm.setAttribute(k, obj[k]);
  522. }
  523. }
  524. }
  525. if (f instanceof Function) f(elm);
  526.  
  527. }
  528.  
  529.  
  530. esProxyHandler = {
  531. get(obj, prop) {
  532. const elm = obj[prop];
  533. if (elm instanceof HTMLElement) {
  534. return elm;
  535. }
  536. console.warn(`Element '${prop}' is not yet assigned.`);
  537. return null;
  538. }
  539. }
  540. }
  541.  
  542. const S = new VanillaJSDialogMethods();
  543.  
  544. class VanillaJSDialog {
  545. // CAUTION: DO NOT CACHE ELEMENTS IN THE NESTED FUNCTIONS.
  546. S = S;
  547. shown = false;
  548.  
  549. /** @type {Function | null} */
  550. backdropClickHandler = null;
  551. backdrop = '';
  552.  
  553. /** @type {Map<string, Function>} */
  554. clicks2 = new Map(); /* the string key is just an arbitrary id for the click handler */
  555.  
  556.  
  557. _es_proxy_ = null;
  558.  
  559. /** @returns {Object.<string, HTMLElement?>} */
  560. get es() {
  561. return this._es_proxy_;
  562. }
  563.  
  564. constructor() {
  565. /** @type {VanillaJSDialog} */
  566. this._es_proxy_ = new Proxy({}, S.esProxyHandler);
  567. if (!S.firstDialogCreated) this.onFirstCreation();
  568. this.init();
  569. console.assert(this.es.dialog instanceof HTMLElement, 'es.dialog must be set.');
  570.  
  571. if (this.clickHandler !== null) {
  572. this.es.dialog.addEventListener('click', this.clickHandler, true);
  573. }
  574. S.firstDialogCreated = true;
  575. }
  576.  
  577. onFirstCreation() {
  578. // TODO
  579. }
  580.  
  581. init() {
  582. // TODO
  583. }
  584.  
  585. get themeProps() {
  586. return _themeProps_;
  587. }
  588.  
  589. get cssForThemeProps() {
  590. return _cssForThemeProps_;
  591. }
  592. themeSetup() {
  593. S.addCSS(this.cssForThemeProps(this.themeProps), 'vjsd-style');
  594. }
  595.  
  596. onBeforeShow() {
  597. // TODO
  598. }
  599. onShow() {
  600. // TODO
  601. }
  602.  
  603. show() {
  604.  
  605. if (this.shown === true) return;
  606. if (this.onBeforeShow() === false) return;
  607.  
  608.  
  609. let { dialog } = this.es;
  610. dialog.classList.add('vjsd-dialog-visible');
  611. this.shown = true;
  612.  
  613.  
  614. if (this.backdrop === 'dismiss' || this.backdrop === 'block') {
  615.  
  616. if (this.backdropClickHandler === null) {
  617. this.backdropClickHandler = () => {
  618. const shown = this.shown;
  619. if (shown && this.backdrop === 'dismiss') {
  620. this.dismiss();
  621. }
  622. };
  623. }
  624.  
  625. if (!('backdrop' in this.es)) {
  626. const backdrop = S.ce('div', {
  627. className: 'vjsd-dialog-backdrop'
  628. });
  629.  
  630. backdrop.setAttribute('__vjsd__', '');
  631.  
  632. backdrop.addEventListener('click', this.backdropClickHandler, true);
  633.  
  634.  
  635.  
  636. document.body.appendChild(backdrop);
  637.  
  638. this.es.backdrop = backdrop;
  639. }
  640.  
  641. document.documentElement.classList.add('vjsd-dialog-shown');
  642. this.es.backdrop.classList.add('vjsd-backdrop-visible');
  643.  
  644. }
  645.  
  646. dialog.classList.toggle('vjsd-dark', this.isDarkTheme());
  647.  
  648. this.onShow();
  649.  
  650. }
  651.  
  652. onBeforeDismiss() {
  653. // TODO
  654.  
  655. }
  656. onDismiss() {
  657. // TODO
  658.  
  659. }
  660.  
  661. dismiss() {
  662.  
  663. if (this.shown) {
  664.  
  665. if (this.onBeforeDismiss() === false) return;
  666.  
  667. document.documentElement.classList.remove('vjsd-dialog-shown');
  668. const es = this.es;
  669.  
  670. es.dialog.classList.remove('vjsd-dialog-visible');
  671. if ('backdrop' in es) {
  672. let backdrop = es.backdrop;
  673. if (backdrop instanceof HTMLElement && backdrop.classList.contains('vjsd-backdrop-visible')) {
  674. backdrop.classList.remove('vjsd-backdrop-visible');
  675. }
  676. }
  677. this.shown = false;
  678. this.onDismiss();
  679. }
  680.  
  681.  
  682. }
  683.  
  684. isDarkTheme() {
  685. // TODO - shall be overrided
  686. return false;
  687. }
  688.  
  689. /** @type {Function?} */
  690. clickHandler = null;
  691.  
  692. createClickHandler() {
  693. const clicks2 = this.clicks2;
  694. return (evt) => {
  695. let evtTarget = ((evt || 0).target || 0);
  696. if (!(evtTarget instanceof HTMLElement)) return;
  697. let vjsdElement = evtTarget.closest('[vjsd-clickable]');
  698. if (vjsdElement instanceof HTMLElement) {
  699. let p = vjsdElement.getAttribute('vjsd-clickable');
  700. let f = clicks2.get(p);
  701. if (f instanceof Function) f(evt);
  702. }
  703. };
  704. }
  705.  
  706.  
  707. /**
  708. *
  709. * @param {HTMLElement | string} elm
  710. * @param {Function} func
  711. *
  712. * */
  713. clickable(elm, func) {
  714. if (typeof elm == 'string') {
  715. this.clicks2.set(elm, func);
  716. }
  717. if (this.clickHandler === null) this.clickHandler = this.createClickHandler();
  718.  
  719. }
  720.  
  721.  
  722.  
  723. };
  724. VanillaJSDialog.S = S;
  725.  
  726. VanillaJSDialog.setup1 = function () {
  727. const S = this.S;
  728.  
  729. S.widgets = {
  730.  
  731.  
  732. /**
  733. * [@Override] The user shall set a customized method to replace VJSD.icon for customization
  734. * @param {string} iconTag Icon Tag
  735. * @returns {VE} generated VE
  736. */
  737. icon(iconTag) {
  738. return S.ce('i', { className: 'vjsd-icon vjsd-icon-' + iconTag });
  739. // return VJSD.iconBuilder(VJSD.ce('span', {className:'vjsd-icon'}), iconTag);
  740. },
  741.  
  742. title(text, ...args) {
  743. const elm = S.ce('span', { className: 'vjsd-title', textContent: text });
  744. S.st(elm, args);
  745. return elm;
  746. },
  747.  
  748. buttonIcon(iconTag, ...args) {
  749. const icon = S.widgets.icon(iconTag);
  750. icon.classList.add('vjsd-buttonicon');
  751. S.st(icon, args)
  752. return icon;
  753. },
  754.  
  755.  
  756. labeledCheckbox(className, text, f) {
  757.  
  758. let elmLabel = S.ce('label', {
  759. className: 'vjsd-checkbox-label'
  760. });
  761.  
  762. let elmInput = S.ce('input', {
  763. className
  764. }, {
  765. 'type': 'checkbox'
  766. })
  767.  
  768. elmLabel.append(elmInput,text + "")
  769.  
  770. if (f instanceof Function) f(elmLabel, elmInput);
  771.  
  772. return elmLabel;
  773.  
  774. },
  775.  
  776. labeledRadio(className, text, f) {
  777.  
  778. let elmLabel = S.ce('label', {
  779. className: 'vjsd-checkbox-label'
  780. });
  781.  
  782. let elmInput = S.ce('input', {
  783. className
  784. }, {
  785. 'type': 'radio'
  786. });
  787.  
  788. elmLabel.append(elmInput, text + "");
  789.  
  790. if (f instanceof Function) f(elmLabel, elmInput);
  791.  
  792. return elmLabel;
  793. },
  794.  
  795. button(text, ...args) {
  796. let elm = S.ce('div', { className: 'vjsd-button', textContent: text });
  797. S.st(elm, args)
  798. return elm;
  799. },
  800.  
  801. space() {
  802. return S.ce('div', { className: 'vjsd-space' });
  803. },
  804.  
  805. span(text) {
  806. return S.ce('span', { className: 'vjsd-span', textContent: text });
  807. },
  808.  
  809. inputText(f) {
  810. let elm = S.ce('input', { className: 'vjsd-input' }, {
  811. 'type': 'text',
  812. id: S.randomInputId(),
  813. autocomplete: "off"
  814. });
  815. if (f instanceof Function) f(elm);
  816. return elm
  817. }
  818.  
  819. };
  820.  
  821. }
  822.  
  823. VanillaJSDialog.VanillaJSDialogMethods = VanillaJSDialogMethods;
  824.  
  825. // Export to external environment
  826. try { window.VanillaJSDialog = VanillaJSDialog; } catch (error) { /* for Greasemonkey */ }
  827. try { module.VanillaJSDialog = VanillaJSDialog; } catch (error) { /* for CommonJS */ }
  828.  
  829. // module.exports = VanillaJSDialog
  830. return VanillaJSDialog;
  831. })();
  832.  
  833.