@windwalker-io/unicorn-next 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +18 -18
- package/.gulp.json +7 -7
- package/bin/release.mjs +47 -47
- package/dist/chunks/button-radio.js.map +1 -1
- package/dist/chunks/checkboxes-multi-select.js.map +1 -1
- package/dist/chunks/field-cascade-select.js.map +1 -1
- package/dist/chunks/field-file-drag.js +34 -31
- package/dist/chunks/field-file-drag.js.map +1 -1
- package/dist/chunks/field-flatpickr.js +10 -3
- package/dist/chunks/field-flatpickr.js.map +1 -1
- package/dist/chunks/field-modal-select.js +6 -2
- package/dist/chunks/field-modal-select.js.map +1 -1
- package/dist/chunks/field-modal-tree.js +8 -5
- package/dist/chunks/field-modal-tree.js.map +1 -1
- package/dist/chunks/field-multi-uploader.js +6 -3
- package/dist/chunks/field-multi-uploader.js.map +1 -1
- package/dist/chunks/field-repeatable.js.map +1 -1
- package/dist/chunks/field-single-image-drag.js +12 -7
- package/dist/chunks/field-single-image-drag.js.map +1 -1
- package/dist/chunks/form.js.map +1 -1
- package/dist/chunks/grid.js.map +1 -1
- package/dist/chunks/http-client.js.map +1 -1
- package/dist/chunks/iframe-modal.js +27 -24
- package/dist/chunks/iframe-modal.js.map +1 -1
- package/dist/chunks/keep-tab.js.map +1 -1
- package/dist/chunks/legacy.js.map +1 -1
- package/dist/chunks/list-dependent.js.map +1 -1
- package/dist/chunks/s3-multipart-uploader.js.map +1 -1
- package/dist/chunks/s3-uploader.js.map +1 -1
- package/dist/chunks/show-on.js.map +1 -1
- package/dist/chunks/tinymce.js.map +1 -1
- package/dist/chunks/ui-bootstrap5.js.map +1 -1
- package/dist/chunks/unicorn.js +6 -4
- package/dist/chunks/unicorn.js.map +1 -1
- package/dist/chunks/validation.js.map +1 -1
- package/dist/index.d.ts +25 -19
- package/dist/unicorn.js +3 -3
- package/fusionfile.mjs +155 -155
- package/package.json +103 -103
- package/scss/bootstrap/multi-level-menu.scss +121 -121
- package/scss/editor.scss +116 -116
- package/scss/field/file-drag.scss +102 -102
- package/scss/field/single-image-drag.scss +88 -88
- package/scss/field/vue-drag-uploader.scss +160 -160
- package/scss/switcher.scss +156 -156
- package/src/app.ts +128 -128
- package/src/bootstrap/button-radio.ts +208 -208
- package/src/bootstrap/keep-tab.ts +155 -155
- package/src/composable/index.ts +21 -21
- package/src/composable/useCheckboxesMultiSelect.ts +22 -22
- package/src/composable/useFieldCascadeSelect.ts +9 -9
- package/src/composable/useFieldFileDrag.ts +9 -9
- package/src/composable/useFieldFlatpickr.ts +3 -3
- package/src/composable/useFieldModalSelect.ts +6 -6
- package/src/composable/useFieldModalTree.ts +3 -3
- package/src/composable/useFieldMultiUploader.ts +3 -3
- package/src/composable/useFieldRepeatable.ts +9 -9
- package/src/composable/useFieldSingleImageDrag.ts +9 -5
- package/src/composable/useForm.ts +43 -43
- package/src/composable/useGrid.ts +57 -57
- package/src/composable/useHttp.ts +9 -9
- package/src/composable/useIframeModal.ts +10 -10
- package/src/composable/useListDependent.ts +26 -26
- package/src/composable/useQueue.ts +13 -13
- package/src/composable/useS3Uploader.ts +32 -32
- package/src/composable/useShowOn.ts +9 -9
- package/src/composable/useStack.ts +13 -13
- package/src/composable/useTinymce.ts +29 -29
- package/src/composable/useTomSelect.ts +72 -72
- package/src/composable/useUIBootstrap5.ts +48 -48
- package/src/composable/useUniDirective.ts +32 -32
- package/src/composable/useValidation.ts +39 -39
- package/src/data.ts +34 -34
- package/src/events.ts +82 -82
- package/src/legacy/legacy.ts +190 -190
- package/src/legacy/loader.ts +125 -125
- package/src/module/checkboxes-multi-select.ts +54 -54
- package/src/module/field-cascade-select.ts +292 -292
- package/src/module/field-file-drag.ts +295 -292
- package/src/module/field-flatpickr.ts +130 -127
- package/src/module/field-modal-select.ts +179 -174
- package/src/module/field-modal-tree.ts +31 -27
- package/src/module/field-multi-uploader.ts +363 -361
- package/src/module/field-repeatable.ts +202 -202
- package/src/module/field-single-image-drag.ts +475 -468
- package/src/module/form.ts +223 -223
- package/src/module/grid.ts +465 -465
- package/src/module/http-client.ts +248 -248
- package/src/module/iframe-modal.ts +170 -167
- package/src/module/list-dependent.ts +321 -321
- package/src/module/s3-multipart-uploader.ts +300 -300
- package/src/module/s3-uploader.ts +234 -234
- package/src/module/show-on.ts +175 -175
- package/src/module/tinymce.ts +276 -276
- package/src/module/ui-bootstrap5.ts +116 -116
- package/src/module/validation.ts +1026 -1026
- package/src/plugin/index.ts +1 -1
- package/src/plugin/php-adapter.ts +72 -72
- package/src/polyfill/form-request-submit.ts +31 -31
- package/src/polyfill/index.ts +9 -9
- package/src/service/animate.ts +58 -58
- package/src/service/crypto.ts +27 -27
- package/src/service/dom-watcher.ts +62 -62
- package/src/service/dom.ts +265 -265
- package/src/service/helper.ts +48 -48
- package/src/service/index.ts +10 -10
- package/src/service/lang.ts +122 -122
- package/src/service/loader.ts +152 -152
- package/src/service/router.ts +118 -118
- package/src/service/ui.ts +525 -525
- package/src/service/uri.ts +106 -106
- package/src/types/base.ts +9 -9
- package/src/types/index.ts +4 -4
- package/src/types/modal-tree.ts +12 -12
- package/src/types/plugin.ts +6 -6
- package/src/types/shims.d.ts +18 -18
- package/src/types/ui.ts +6 -6
- package/src/unicorn.ts +79 -79
- package/src/utilities/arr.ts +25 -25
- package/src/utilities/base.ts +9 -9
- package/src/utilities/data.ts +48 -48
- package/src/utilities/index.ts +5 -5
- package/src/utilities/tree.ts +20 -20
- package/src/vue/components/ModalTree/ModalTreeApp.vue +175 -175
- package/src/vue/components/ModalTree/TreeItem.vue +262 -262
- package/src/vue/components/ModalTree/TreeModal.vue +225 -225
- package/tests/test.js +4 -4
- package/tsconfig.js.json +25 -25
- package/tsconfig.json +17 -17
- package/vite.assets.config.ts +61 -61
- package/vite.config.test.ts +36 -36
- package/vite.config.ts +112 -112
package/src/plugin/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './php-adapter';
|
|
1
|
+
export * from './php-adapter';
|
|
@@ -1,72 +1,72 @@
|
|
|
1
|
-
import type { UnicornApp } from '../app';
|
|
2
|
-
import {
|
|
3
|
-
useBs5ButtonRadio, useBs5KeepTab,
|
|
4
|
-
useBs5Tooltip,
|
|
5
|
-
useFieldCascadeSelect,
|
|
6
|
-
useFieldFileDrag,
|
|
7
|
-
useFieldFlatpickr,
|
|
8
|
-
useFieldModalSelect, useFieldModalTree,
|
|
9
|
-
useFieldRepeatable,
|
|
10
|
-
useFieldSingleImageDrag,
|
|
11
|
-
useIframeModal, useS3Uploader,
|
|
12
|
-
useShowOn, useTomSelect,
|
|
13
|
-
} from '../composable';
|
|
14
|
-
import { useFieldMultiUploader } from '../composable/useFieldMultiUploader';
|
|
15
|
-
import { useTinymce } from '../composable/useTinymce';
|
|
16
|
-
import { useUnicorn } from '../unicorn';
|
|
17
|
-
|
|
18
|
-
declare module '../app' {
|
|
19
|
-
export interface UnicornApp {
|
|
20
|
-
/** @deprecated Only for code generator use. */
|
|
21
|
-
$ui: typeof methods;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// @ts-ignore
|
|
26
|
-
declare module '@windwalker-io/unicorn-next' {
|
|
27
|
-
export interface UnicornApp {
|
|
28
|
-
/** @deprecated Only for code generator use. */
|
|
29
|
-
$ui: typeof methods;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function useUnicornPhpAdapter(app?: UnicornApp) {
|
|
34
|
-
app ??= useUnicorn();
|
|
35
|
-
|
|
36
|
-
app.use(UnicornPhpAdapter);
|
|
37
|
-
|
|
38
|
-
return app.$ui;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const methods = {
|
|
42
|
-
repeatable: useFieldRepeatable,
|
|
43
|
-
flatpickr: useFieldFlatpickr,
|
|
44
|
-
fileDrag: useFieldFileDrag,
|
|
45
|
-
modalField: useFieldModalSelect,
|
|
46
|
-
cascadeSelect: useFieldCascadeSelect,
|
|
47
|
-
sid: useFieldSingleImageDrag,
|
|
48
|
-
tinymce: {
|
|
49
|
-
init: useTinymce
|
|
50
|
-
},
|
|
51
|
-
s3Uploader: useS3Uploader,
|
|
52
|
-
iframeModal: useIframeModal,
|
|
53
|
-
initShowOn: useShowOn,
|
|
54
|
-
modalTree: useFieldModalTree,
|
|
55
|
-
multiUploader: useFieldMultiUploader,
|
|
56
|
-
tomSelect: useTomSelect,
|
|
57
|
-
bootstrap: {
|
|
58
|
-
tooltip: useBs5Tooltip,
|
|
59
|
-
buttonRadio: useBs5ButtonRadio,
|
|
60
|
-
keepTab: useBs5KeepTab,
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export class UnicornPhpAdapter {
|
|
65
|
-
static install(app: UnicornApp) {
|
|
66
|
-
if (app.$ui) {
|
|
67
|
-
app.$ui = { ...app.$ui, ...methods };
|
|
68
|
-
} else {
|
|
69
|
-
app.$ui = methods;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
1
|
+
import type { UnicornApp } from '../app';
|
|
2
|
+
import {
|
|
3
|
+
useBs5ButtonRadio, useBs5KeepTab,
|
|
4
|
+
useBs5Tooltip,
|
|
5
|
+
useFieldCascadeSelect,
|
|
6
|
+
useFieldFileDrag,
|
|
7
|
+
useFieldFlatpickr,
|
|
8
|
+
useFieldModalSelect, useFieldModalTree,
|
|
9
|
+
useFieldRepeatable,
|
|
10
|
+
useFieldSingleImageDrag,
|
|
11
|
+
useIframeModal, useS3Uploader,
|
|
12
|
+
useShowOn, useTomSelect,
|
|
13
|
+
} from '../composable';
|
|
14
|
+
import { useFieldMultiUploader } from '../composable/useFieldMultiUploader';
|
|
15
|
+
import { useTinymce } from '../composable/useTinymce';
|
|
16
|
+
import { useUnicorn } from '../unicorn';
|
|
17
|
+
|
|
18
|
+
declare module '../app' {
|
|
19
|
+
export interface UnicornApp {
|
|
20
|
+
/** @deprecated Only for code generator use. */
|
|
21
|
+
$ui: typeof methods;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// @ts-ignore
|
|
26
|
+
declare module '@windwalker-io/unicorn-next' {
|
|
27
|
+
export interface UnicornApp {
|
|
28
|
+
/** @deprecated Only for code generator use. */
|
|
29
|
+
$ui: typeof methods;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function useUnicornPhpAdapter(app?: UnicornApp) {
|
|
34
|
+
app ??= useUnicorn();
|
|
35
|
+
|
|
36
|
+
app.use(UnicornPhpAdapter);
|
|
37
|
+
|
|
38
|
+
return app.$ui;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const methods = {
|
|
42
|
+
repeatable: useFieldRepeatable,
|
|
43
|
+
flatpickr: useFieldFlatpickr,
|
|
44
|
+
fileDrag: useFieldFileDrag,
|
|
45
|
+
modalField: useFieldModalSelect,
|
|
46
|
+
cascadeSelect: useFieldCascadeSelect,
|
|
47
|
+
sid: useFieldSingleImageDrag,
|
|
48
|
+
tinymce: {
|
|
49
|
+
init: useTinymce
|
|
50
|
+
},
|
|
51
|
+
s3Uploader: useS3Uploader,
|
|
52
|
+
iframeModal: useIframeModal,
|
|
53
|
+
initShowOn: useShowOn,
|
|
54
|
+
modalTree: useFieldModalTree,
|
|
55
|
+
multiUploader: useFieldMultiUploader,
|
|
56
|
+
tomSelect: useTomSelect,
|
|
57
|
+
bootstrap: {
|
|
58
|
+
tooltip: useBs5Tooltip,
|
|
59
|
+
buttonRadio: useBs5ButtonRadio,
|
|
60
|
+
keepTab: useBs5KeepTab,
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
export class UnicornPhpAdapter {
|
|
65
|
+
static install(app: UnicornApp) {
|
|
66
|
+
if (app.$ui) {
|
|
67
|
+
app.$ui = { ...app.$ui, ...methods };
|
|
68
|
+
} else {
|
|
69
|
+
app.$ui = methods;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
// @see https://github.com/javan/form-request-submit-polyfill
|
|
3
|
-
export function formRequestSubmit(prototype) {
|
|
4
|
-
if (typeof prototype.requestSubmit == 'function') {
|
|
5
|
-
return;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
prototype.requestSubmit = function (submitter) {
|
|
9
|
-
if (submitter) {
|
|
10
|
-
validateSubmitter(submitter, this);
|
|
11
|
-
submitter.click();
|
|
12
|
-
} else {
|
|
13
|
-
submitter = document.createElement('input');
|
|
14
|
-
submitter.type = 'submit';
|
|
15
|
-
submitter.hidden = true;
|
|
16
|
-
this.appendChild(submitter);
|
|
17
|
-
submitter.click();
|
|
18
|
-
this.removeChild(submitter);
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
function validateSubmitter(submitter, form) {
|
|
23
|
-
submitter instanceof HTMLElement || raise(TypeError, 'parameter 1 is not of type \'HTMLElement\'');
|
|
24
|
-
submitter.type == 'submit' || raise(TypeError, 'The specified element is not a submit button');
|
|
25
|
-
submitter.form == form || raise(DOMException, 'The specified element is not owned by this form element', 'NotFoundError');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function raise(errorConstructor, message, name) {
|
|
29
|
-
throw new errorConstructor('Failed to execute \'requestSubmit\' on \'HTMLFormElement\': ' + message + '.', name);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
// @see https://github.com/javan/form-request-submit-polyfill
|
|
3
|
+
export function formRequestSubmit(prototype) {
|
|
4
|
+
if (typeof prototype.requestSubmit == 'function') {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
prototype.requestSubmit = function (submitter) {
|
|
9
|
+
if (submitter) {
|
|
10
|
+
validateSubmitter(submitter, this);
|
|
11
|
+
submitter.click();
|
|
12
|
+
} else {
|
|
13
|
+
submitter = document.createElement('input');
|
|
14
|
+
submitter.type = 'submit';
|
|
15
|
+
submitter.hidden = true;
|
|
16
|
+
this.appendChild(submitter);
|
|
17
|
+
submitter.click();
|
|
18
|
+
this.removeChild(submitter);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function validateSubmitter(submitter, form) {
|
|
23
|
+
submitter instanceof HTMLElement || raise(TypeError, 'parameter 1 is not of type \'HTMLElement\'');
|
|
24
|
+
submitter.type == 'submit' || raise(TypeError, 'The specified element is not a submit button');
|
|
25
|
+
submitter.form == form || raise(DOMException, 'The specified element is not owned by this form element', 'NotFoundError');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function raise(errorConstructor, message, name) {
|
|
29
|
+
throw new errorConstructor('Failed to execute \'requestSubmit\' on \'HTMLFormElement\': ' + message + '.', name);
|
|
30
|
+
}
|
|
31
|
+
}
|
package/src/polyfill/index.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import { formRequestSubmit } from './form-request-submit';
|
|
3
|
-
|
|
4
|
-
export function polyfill() {
|
|
5
|
-
// If in browser
|
|
6
|
-
if (typeof window !== 'undefined') {
|
|
7
|
-
formRequestSubmit(HTMLFormElement.prototype);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
1
|
+
|
|
2
|
+
import { formRequestSubmit } from './form-request-submit';
|
|
3
|
+
|
|
4
|
+
export function polyfill() {
|
|
5
|
+
// If in browser
|
|
6
|
+
if (typeof window !== 'undefined') {
|
|
7
|
+
formRequestSubmit(HTMLFormElement.prototype);
|
|
8
|
+
}
|
|
9
|
+
}
|
package/src/service/animate.ts
CHANGED
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
import { selectOne } from './dom';
|
|
2
|
-
|
|
3
|
-
export function animateTo(
|
|
4
|
-
element: HTMLElement,
|
|
5
|
-
styles: Partial<Record<keyof CSSStyleDeclaration, any>>,
|
|
6
|
-
options: number | KeyframeAnimationOptions = {}
|
|
7
|
-
): Animation {
|
|
8
|
-
element = selectOne(element);
|
|
9
|
-
|
|
10
|
-
const currentStyles = window.getComputedStyle(element);
|
|
11
|
-
const transitions: Record<string, any[]> = {};
|
|
12
|
-
|
|
13
|
-
for (const name in styles) {
|
|
14
|
-
const value = styles[name];
|
|
15
|
-
|
|
16
|
-
transitions[name] = Array.isArray(value)
|
|
17
|
-
? value
|
|
18
|
-
: [
|
|
19
|
-
currentStyles.getPropertyValue(name),
|
|
20
|
-
value
|
|
21
|
-
];
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (typeof options === 'number') {
|
|
25
|
-
options = { duration: options };
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
options = Object.assign(
|
|
29
|
-
{
|
|
30
|
-
duration: 400,
|
|
31
|
-
easing: 'linear',
|
|
32
|
-
fill: 'both'
|
|
33
|
-
},
|
|
34
|
-
options
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
const animation = element.animate(
|
|
38
|
-
transitions,
|
|
39
|
-
options
|
|
40
|
-
);
|
|
41
|
-
|
|
42
|
-
animation.addEventListener('finish', () => {
|
|
43
|
-
for (const name in styles) {
|
|
44
|
-
const value = styles[name];
|
|
45
|
-
|
|
46
|
-
element.style.setProperty(
|
|
47
|
-
name,
|
|
48
|
-
Array.isArray(value)
|
|
49
|
-
? value[value.length - 1]
|
|
50
|
-
: value
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
animation.cancel();
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
return animation;
|
|
58
|
-
}
|
|
1
|
+
import { selectOne } from './dom';
|
|
2
|
+
|
|
3
|
+
export function animateTo(
|
|
4
|
+
element: HTMLElement,
|
|
5
|
+
styles: Partial<Record<keyof CSSStyleDeclaration, any>>,
|
|
6
|
+
options: number | KeyframeAnimationOptions = {}
|
|
7
|
+
): Animation {
|
|
8
|
+
element = selectOne(element);
|
|
9
|
+
|
|
10
|
+
const currentStyles = window.getComputedStyle(element);
|
|
11
|
+
const transitions: Record<string, any[]> = {};
|
|
12
|
+
|
|
13
|
+
for (const name in styles) {
|
|
14
|
+
const value = styles[name];
|
|
15
|
+
|
|
16
|
+
transitions[name] = Array.isArray(value)
|
|
17
|
+
? value
|
|
18
|
+
: [
|
|
19
|
+
currentStyles.getPropertyValue(name),
|
|
20
|
+
value
|
|
21
|
+
];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (typeof options === 'number') {
|
|
25
|
+
options = { duration: options };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
options = Object.assign(
|
|
29
|
+
{
|
|
30
|
+
duration: 400,
|
|
31
|
+
easing: 'linear',
|
|
32
|
+
fill: 'both'
|
|
33
|
+
},
|
|
34
|
+
options
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
const animation = element.animate(
|
|
38
|
+
transitions,
|
|
39
|
+
options
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
animation.addEventListener('finish', () => {
|
|
43
|
+
for (const name in styles) {
|
|
44
|
+
const value = styles[name];
|
|
45
|
+
|
|
46
|
+
element.style.setProperty(
|
|
47
|
+
name,
|
|
48
|
+
Array.isArray(value)
|
|
49
|
+
? value[value.length - 1]
|
|
50
|
+
: value
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
animation.cancel();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return animation;
|
|
58
|
+
}
|
package/src/service/crypto.ts
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { uid, tid, randomBytes, randomBytesString } from '@lyrasoft/ts-toolkit/generic';
|
|
2
|
-
|
|
3
|
-
export function base64UrlEncode(string: string): string {
|
|
4
|
-
return btoa(String(string))
|
|
5
|
-
.replace(/\+/, '-')
|
|
6
|
-
.replace(new RegExp('\\/'), '_')
|
|
7
|
-
.replace(/=+$/, '');
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Base64 URL decode
|
|
12
|
-
*/
|
|
13
|
-
export function base64UrlDecode(string: string): string {
|
|
14
|
-
return atob(
|
|
15
|
-
String(string)
|
|
16
|
-
.replace(/-/, '+')
|
|
17
|
-
.replace(/_/, '/')
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export { uid, tid, randomBytes, randomBytesString };
|
|
22
|
-
|
|
23
|
-
let globalSerial = 1;
|
|
24
|
-
|
|
25
|
-
export function serial(): number {
|
|
26
|
-
return globalSerial++;
|
|
27
|
-
}
|
|
1
|
+
import { uid, tid, randomBytes, randomBytesString } from '@lyrasoft/ts-toolkit/generic';
|
|
2
|
+
|
|
3
|
+
export function base64UrlEncode(string: string): string {
|
|
4
|
+
return btoa(String(string))
|
|
5
|
+
.replace(/\+/, '-')
|
|
6
|
+
.replace(new RegExp('\\/'), '_')
|
|
7
|
+
.replace(/=+$/, '');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Base64 URL decode
|
|
12
|
+
*/
|
|
13
|
+
export function base64UrlDecode(string: string): string {
|
|
14
|
+
return atob(
|
|
15
|
+
String(string)
|
|
16
|
+
.replace(/-/, '+')
|
|
17
|
+
.replace(/_/, '/')
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { uid, tid, randomBytes, randomBytesString };
|
|
22
|
+
|
|
23
|
+
let globalSerial = 1;
|
|
24
|
+
|
|
25
|
+
export function serial(): number {
|
|
26
|
+
return globalSerial++;
|
|
27
|
+
}
|
|
@@ -1,62 +1,62 @@
|
|
|
1
|
-
export function watchAttributes<T extends HTMLElement>(el: T, callback?: AttributeMutationCallback<T>) {
|
|
2
|
-
return new AttributeMutationObserver<T>(el, callback);
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export type AttributeMutationCallback<T extends HTMLElement = HTMLElement> = (el: T, name: string, value: any, oldValue: any) => void;
|
|
6
|
-
export type AttributeWatcher<T extends HTMLElement = HTMLElement> = (el: T, value: any, oldValue: any) => void;
|
|
7
|
-
|
|
8
|
-
export class AttributeMutationObserver<T extends HTMLElement> {
|
|
9
|
-
observer: MutationObserver;
|
|
10
|
-
watches: Record<string, (AttributeWatcher<T>)[]> = {};
|
|
11
|
-
|
|
12
|
-
constructor(protected element: T, public callback?: (el: T, name: string, value: any, oldValue: any) => void) {
|
|
13
|
-
this.element = element;
|
|
14
|
-
|
|
15
|
-
this.observer = new MutationObserver((mutations) => {
|
|
16
|
-
for (const mutation of mutations) {
|
|
17
|
-
if (mutation.type === 'attributes') {
|
|
18
|
-
const attrName = mutation.attributeName!;
|
|
19
|
-
const target = mutation.target as T;
|
|
20
|
-
const value = target.getAttribute(attrName);
|
|
21
|
-
|
|
22
|
-
this.callback?.(
|
|
23
|
-
target,
|
|
24
|
-
attrName,
|
|
25
|
-
value,
|
|
26
|
-
mutation.oldValue
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
if (this.watches[attrName]) {
|
|
30
|
-
for (const watch of this.watches[attrName]) {
|
|
31
|
-
watch(target, value, mutation.oldValue);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
this.observe();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
watch(name: string, callback: AttributeWatcher<T>): () => void {
|
|
42
|
-
this.watches[name] ??= [];
|
|
43
|
-
this.watches[name].push(callback);
|
|
44
|
-
|
|
45
|
-
return () => {
|
|
46
|
-
this.watches[name] = this.watches[name].filter(fn => fn !== callback);
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
observe() {
|
|
51
|
-
this.observer.observe(this.element, {
|
|
52
|
-
attributes: true,
|
|
53
|
-
attributeOldValue: true,
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
disconnect() {
|
|
58
|
-
this.observer.disconnect();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
|
|
1
|
+
export function watchAttributes<T extends HTMLElement>(el: T, callback?: AttributeMutationCallback<T>) {
|
|
2
|
+
return new AttributeMutationObserver<T>(el, callback);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export type AttributeMutationCallback<T extends HTMLElement = HTMLElement> = (el: T, name: string, value: any, oldValue: any) => void;
|
|
6
|
+
export type AttributeWatcher<T extends HTMLElement = HTMLElement> = (el: T, value: any, oldValue: any) => void;
|
|
7
|
+
|
|
8
|
+
export class AttributeMutationObserver<T extends HTMLElement> {
|
|
9
|
+
observer: MutationObserver;
|
|
10
|
+
watches: Record<string, (AttributeWatcher<T>)[]> = {};
|
|
11
|
+
|
|
12
|
+
constructor(protected element: T, public callback?: (el: T, name: string, value: any, oldValue: any) => void) {
|
|
13
|
+
this.element = element;
|
|
14
|
+
|
|
15
|
+
this.observer = new MutationObserver((mutations) => {
|
|
16
|
+
for (const mutation of mutations) {
|
|
17
|
+
if (mutation.type === 'attributes') {
|
|
18
|
+
const attrName = mutation.attributeName!;
|
|
19
|
+
const target = mutation.target as T;
|
|
20
|
+
const value = target.getAttribute(attrName);
|
|
21
|
+
|
|
22
|
+
this.callback?.(
|
|
23
|
+
target,
|
|
24
|
+
attrName,
|
|
25
|
+
value,
|
|
26
|
+
mutation.oldValue
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
if (this.watches[attrName]) {
|
|
30
|
+
for (const watch of this.watches[attrName]) {
|
|
31
|
+
watch(target, value, mutation.oldValue);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
this.observe();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
watch(name: string, callback: AttributeWatcher<T>): () => void {
|
|
42
|
+
this.watches[name] ??= [];
|
|
43
|
+
this.watches[name].push(callback);
|
|
44
|
+
|
|
45
|
+
return () => {
|
|
46
|
+
this.watches[name] = this.watches[name].filter(fn => fn !== callback);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
observe() {
|
|
51
|
+
this.observer.observe(this.element, {
|
|
52
|
+
attributes: true,
|
|
53
|
+
attributeOldValue: true,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
disconnect() {
|
|
58
|
+
this.observer.disconnect();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
|