inviton-powerduck 0.0.164 → 0.0.166
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/app/global-state.ts +28 -0
- package/app/powerduck-initializer.ts +10 -9
- package/app/powerduck-state.ts +3 -2
- package/common/ajax-xhr.ts +2 -1
- package/common/api-http.ts +6 -5
- package/common/base-component.tsx +2 -1
- package/common/dialog-utils.ts +2 -1
- package/common/external-barcode-scanner.ts +244 -242
- package/common/history-extended.ts +44 -6
- package/common/history-handler.ts +15 -15
- package/common/keyboard-open-tracker.ts +20 -6
- package/common/ladda-lite.ts +14 -1
- package/common/local-storage-shim.ts +66 -30
- package/common/resource-helper.ts +77 -71
- package/common/scroll-utils.ts +9 -4
- package/common/set-current-url.ts +8 -5
- package/common/utils/checkbox-utils.ts +6 -0
- package/common/utils/clipboard-provider.ts +37 -34
- package/common/utils/cookie.ts +9 -0
- package/common/utils/dropdown-utils.ts +5 -0
- package/common/utils/string-utils.ts +46 -40
- package/common/utils/upload-image-helper.ts +2 -1
- package/common/utils/utils.ts +34 -14
- package/components/app/navigation-guard.ts +5 -2
- package/components/app/root-dynamic-component-container.tsx +2 -1
- package/components/app/vue-plugin-jsxtransform.ts +3 -1
- package/components/chart-js/line-chart-flot.tsx +4 -3
- package/components/chart-js/line-chart.tsx +5 -0
- package/components/chart-js/pie-chart.tsx +4 -3
- package/components/collapse/index.tsx +9 -0
- package/components/container-with-breakpoints/ts/breakpoint-handler.ts +7 -6
- package/components/counter/index.tsx +2 -1
- package/components/counter/testall.tsx +12 -9
- package/components/datatable/datatable.tsx +2363 -2362
- package/components/dropdown/mobile/legacy_fdd.ts +10 -9
- package/components/dropdown/mobile/legacy_lvb.ts +3 -1
- package/components/file-downloader/index.tsx +6 -5
- package/components/google/maps.tsx +18 -8
- package/components/google/places-autocomplete.tsx +6 -1
- package/components/google/ts/google-maps-api.ts +3 -2
- package/components/image-crop/image-cropping-modal.tsx +11 -6
- package/components/image-crop/upload-and-crop.tsx +163 -162
- package/components/input/daterange-picker.tsx +9 -0
- package/components/input/datetime-picker.tsx +11 -2
- package/components/input/localized-url-input.tsx +2 -1
- package/components/input/ts/bootstrapInputSpinner.ts +7 -2
- package/components/input/ts/dateInputHelper.ts +8 -7
- package/components/memory-cache/index.ts +7 -5
- package/components/modal/modal-utils.ts +2 -1
- package/components/modal/modal.tsx +5 -4
- package/components/modal/ts/file-manager-dialog.ts +3 -2
- package/components/share/share-modal.tsx +13 -12
- package/components/share/share.tsx +13 -12
- package/components/swiper/swiper.tsx +19 -15
- package/package.json +1 -1
- package/common/cdn-webpack-shim.ts +0 -5
- package/components/input/plugins/daterangepicker/jquery.daterangepicker.min.js +0 -1910
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { globalState } from '../../../app/global-state';
|
|
2
|
+
import { latinize } from '../../../common/extensions/string-extensions';
|
|
1
3
|
import TemporalUtils from '../../../common/utils/temporal-utils';
|
|
2
4
|
import ListviewBuilder from './legacy_lvb';
|
|
3
5
|
import './legacy_fdd.css';
|
|
4
|
-
import { latinize } from '../../../common/extensions/string-extensions';
|
|
5
6
|
|
|
6
7
|
const $ = jQuery;
|
|
7
8
|
|
|
@@ -42,11 +43,11 @@ export default function FilterableSelect(this: any, args: FilterableSelectArgs):
|
|
|
42
43
|
let contextWindow, contextBody;
|
|
43
44
|
|
|
44
45
|
if (iframeTopMode) {
|
|
45
|
-
contextWindow =
|
|
46
|
+
contextWindow = globalState.top;
|
|
46
47
|
contextBody = contextWindow.document.body;
|
|
47
48
|
} else {
|
|
48
|
-
contextWindow =
|
|
49
|
-
contextBody =
|
|
49
|
+
contextWindow = globalState;
|
|
50
|
+
contextBody = globalState.document.body;
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
args = args || ({} as any);
|
|
@@ -459,7 +460,7 @@ export default function FilterableSelect(this: any, args: FilterableSelectArgs):
|
|
|
459
460
|
$(contextBody).find('#filterableSelectOverlay').addClass('fdd-anim-shown');
|
|
460
461
|
$(contextBody).find('#filterableSelectDropDown').addClass('fdd-anim-shown');
|
|
461
462
|
|
|
462
|
-
const availableHeight = $(
|
|
463
|
+
const availableHeight = $(globalState).height() - 100;
|
|
463
464
|
const scrollTarget = $('#filterableSelectDropDownInner');
|
|
464
465
|
const selectedTop = $('.filterabledd-item.fdd-selected').offset()?.top - scrollTarget.offset().top + availableHeight;
|
|
465
466
|
|
|
@@ -472,10 +473,10 @@ export default function FilterableSelect(this: any, args: FilterableSelectArgs):
|
|
|
472
473
|
currentContext.find('.paginator-container').attr('style', 'margin-top:20px;margin-bottom:10px;');
|
|
473
474
|
openClickTime = TemporalUtils.dateNowMs();
|
|
474
475
|
|
|
475
|
-
if (useIscroll) {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
}
|
|
476
|
+
// if (useIscroll) {
|
|
477
|
+
// contextWindow._filterableIscroll = globalState.utils.bindIscroll($(contextBody).find('#filterableSelectDropWrap'));
|
|
478
|
+
// currentContext.find('.paginator-container').attr('style', 'margin-top:10px;margin-bottom:10px;');
|
|
479
|
+
// }
|
|
479
480
|
|
|
480
481
|
$(contextBody).find('#btn_fdd_FddCancel').click(() => {
|
|
481
482
|
this.hide();
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { globalState } from '../../../app/global-state';
|
|
2
|
+
|
|
1
3
|
const $ = jQuery;
|
|
2
4
|
|
|
3
5
|
export default function ListviewBuilder(this: any): void {
|
|
@@ -269,7 +271,7 @@ export default function ListviewBuilder(this: any): void {
|
|
|
269
271
|
setTimeout(() => {
|
|
270
272
|
currentContext.changePagination(newIndex);
|
|
271
273
|
currentContext.buildRows();
|
|
272
|
-
|
|
274
|
+
globalState.scrollTo(0, 0);
|
|
273
275
|
self.targetElem.trigger('pagination-end', null);
|
|
274
276
|
}, 200);
|
|
275
277
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { toNative } from 'vue-facing-decorator';
|
|
2
|
+
import { globalState } from '../../app/global-state';
|
|
2
3
|
import PowerduckState from '../../app/powerduck-state';
|
|
3
4
|
import TsxComponent, { Component } from '../../app/vuetsx';
|
|
4
5
|
import { PortalUtils } from '../../common/utils/utils';
|
|
@@ -63,11 +64,11 @@ class FileDownloadDialogComponent extends TsxComponent<FileDownloadDialogBinding
|
|
|
63
64
|
}
|
|
64
65
|
};
|
|
65
66
|
|
|
66
|
-
|
|
67
|
+
const innerDownload = () => {
|
|
67
68
|
const currentFile = fileArr.shift();
|
|
68
69
|
if (currentFile != null) {
|
|
69
70
|
let downloadMethod;
|
|
70
|
-
if (
|
|
71
|
+
if (globalState.fetch) {
|
|
71
72
|
downloadMethod = mySelf.downloadUsingFetch;
|
|
72
73
|
} else {
|
|
73
74
|
downloadMethod = mySelf.downloadUsingXMLHTTP;
|
|
@@ -111,7 +112,7 @@ class FileDownloadDialogComponent extends TsxComponent<FileDownloadDialogBinding
|
|
|
111
112
|
document.getElementById(randomId).click();
|
|
112
113
|
|
|
113
114
|
setTimeout(() => {
|
|
114
|
-
|
|
115
|
+
globalState.URL.revokeObjectURL(_OBJECT_URL);
|
|
115
116
|
document.body.removeChild(dummyLink);
|
|
116
117
|
}, 5000);
|
|
117
118
|
|
|
@@ -134,7 +135,7 @@ class FileDownloadDialogComponent extends TsxComponent<FileDownloadDialogBinding
|
|
|
134
135
|
},
|
|
135
136
|
);
|
|
136
137
|
}
|
|
137
|
-
}
|
|
138
|
+
};
|
|
138
139
|
|
|
139
140
|
mySelf.getModal().show({
|
|
140
141
|
onShown() {
|
|
@@ -179,7 +180,7 @@ class FileDownloadDialogComponent extends TsxComponent<FileDownloadDialogBinding
|
|
|
179
180
|
callback: (response: any) => void,
|
|
180
181
|
error: () => void,
|
|
181
182
|
): void {
|
|
182
|
-
const winFetch =
|
|
183
|
+
const winFetch = globalState.fetch as any;
|
|
183
184
|
winFetch(file.url, {
|
|
184
185
|
method: 'get',
|
|
185
186
|
headers: {},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Prop, toNative } from 'vue-facing-decorator';
|
|
2
|
+
import { globalState } from '../../app/global-state';
|
|
2
3
|
import TsxComponent, { Component } from '../../app/vuetsx';
|
|
3
4
|
import { isNullOrEmpty } from '../../common/utils/is-null-or-empty';
|
|
4
5
|
import { PortalUtils } from '../../common/utils/utils';
|
|
@@ -39,8 +40,8 @@ class GoogleMapComponent extends TsxComponent<GoogleMapArgs> implements GoogleMa
|
|
|
39
40
|
}
|
|
40
41
|
|
|
41
42
|
getLocPoint() {
|
|
42
|
-
if (
|
|
43
|
-
return new
|
|
43
|
+
if (globalState.google?.maps?.LatLng) {
|
|
44
|
+
return new globalState.google.maps.LatLng(this.latitude as any, this.longitude as any);
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
return {
|
|
@@ -50,8 +51,12 @@ class GoogleMapComponent extends TsxComponent<GoogleMapArgs> implements GoogleMa
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
mounted() {
|
|
54
|
+
// eslint-disable-next-line ts/no-this-alias
|
|
53
55
|
const mySelf = this;
|
|
54
|
-
|
|
56
|
+
globalState.mapInst = mySelf;
|
|
57
|
+
if (!globalState.windowExists) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
55
60
|
|
|
56
61
|
GoogleMapsApiLoader.load().then((result) => {
|
|
57
62
|
if (result) {
|
|
@@ -65,12 +70,13 @@ class GoogleMapComponent extends TsxComponent<GoogleMapArgs> implements GoogleMa
|
|
|
65
70
|
gmapArgs.zoom = 16;
|
|
66
71
|
}
|
|
67
72
|
|
|
68
|
-
mySelf.map = new
|
|
73
|
+
mySelf.map = new globalState.google.maps.Map(mySelf.$refs.mapWrapper as any, gmapArgs);
|
|
74
|
+
// eslint-disable-next-line no-useless-call
|
|
69
75
|
mySelf.refreshMapItems.call(mySelf);
|
|
70
|
-
|
|
76
|
+
globalState.mapInstance = mySelf.map;
|
|
71
77
|
|
|
72
78
|
if (this.initComplete != null) {
|
|
73
|
-
this.initComplete(mySelf.map,
|
|
79
|
+
this.initComplete(mySelf.map, globalState.google.maps);
|
|
74
80
|
}
|
|
75
81
|
}
|
|
76
82
|
});
|
|
@@ -89,6 +95,10 @@ class GoogleMapComponent extends TsxComponent<GoogleMapArgs> implements GoogleMa
|
|
|
89
95
|
}
|
|
90
96
|
|
|
91
97
|
refreshMapItems(args?: GoogleMapRefreshArgs) {
|
|
98
|
+
if (!globalState.windowExists) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
92
102
|
const map = this.map;
|
|
93
103
|
const locPoint = this.getLocPoint();
|
|
94
104
|
const newState = this.getCurrentState();
|
|
@@ -102,7 +112,7 @@ class GoogleMapComponent extends TsxComponent<GoogleMapArgs> implements GoogleMa
|
|
|
102
112
|
}
|
|
103
113
|
|
|
104
114
|
if (this.infoWindow == null && !isNullOrEmpty(this.name)) {
|
|
105
|
-
this.infoWindow = new
|
|
115
|
+
this.infoWindow = new globalState.google.maps.InfoWindow({
|
|
106
116
|
content: '',
|
|
107
117
|
});
|
|
108
118
|
}
|
|
@@ -113,7 +123,7 @@ class GoogleMapComponent extends TsxComponent<GoogleMapArgs> implements GoogleMa
|
|
|
113
123
|
}
|
|
114
124
|
|
|
115
125
|
if (this.marker == null) {
|
|
116
|
-
this.marker = new
|
|
126
|
+
this.marker = new globalState.google.maps.Marker({
|
|
117
127
|
position: locPoint,
|
|
118
128
|
title: PortalUtils.htmlEscape(this.name),
|
|
119
129
|
visible: true,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { DropdownButtonItemArgs } from '../dropdown-button/dropdown-button-item';
|
|
2
2
|
import type { FormItemWrapperArgs, MarginType } from '../form/form-item-wrapper';
|
|
3
3
|
import { Prop, toNative } from 'vue-facing-decorator';
|
|
4
|
+
import { globalState } from '../../app/global-state';
|
|
4
5
|
import PowerduckState from '../../app/powerduck-state';
|
|
5
6
|
import TsxComponent, { Component } from '../../app/vuetsx';
|
|
6
7
|
import { AppHttpProvider } from '../../common/api-http';
|
|
@@ -304,7 +305,11 @@ class GooglePlacesAutocompleteWrapper {
|
|
|
304
305
|
};
|
|
305
306
|
}
|
|
306
307
|
|
|
307
|
-
|
|
308
|
+
if (!globalState.windowExists) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const autocomplete = new globalState.google.maps.places.Autocomplete(args.element as any, acArgs);
|
|
308
313
|
autocomplete.addListener('place_changed', () => {
|
|
309
314
|
const place = autocomplete.getPlace();
|
|
310
315
|
const name = GooglePlacesUtils.getName(place, args.resultType);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { globalState } from '../../../app/global-state';
|
|
1
2
|
import PowerduckState from '../../../app/powerduck-state';
|
|
2
3
|
|
|
3
4
|
export default class GoogleMapsApiLoader {
|
|
@@ -35,7 +36,7 @@ export default class GoogleMapsApiLoader {
|
|
|
35
36
|
};
|
|
36
37
|
script.onerror = function (e) {
|
|
37
38
|
delete GoogleMapsApiLoader._loading;
|
|
38
|
-
reject(
|
|
39
|
+
reject(e);
|
|
39
40
|
};
|
|
40
41
|
script.src = `https://maps.googleapis.com/maps/api/js?key=${PowerduckState.getGoogleMapsApiKey()}&libraries=places`;
|
|
41
42
|
document.head.appendChild(script);
|
|
@@ -43,6 +44,6 @@ export default class GoogleMapsApiLoader {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
private static apiLoaded(): boolean {
|
|
46
|
-
return (
|
|
47
|
+
return (globalState.google && globalState.google.maps && globalState.google.maps.places && globalState.google.maps.places.Autocomplete) != null;
|
|
47
48
|
}
|
|
48
49
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { toNative } from 'vue-facing-decorator';
|
|
2
|
+
import { globalState } from '../../app/global-state';
|
|
2
3
|
import PowerduckState from '../../app/powerduck-state';
|
|
3
4
|
import TsxComponent, { Component } from '../../app/vuetsx';
|
|
4
5
|
import { isNullOrEmpty } from '../../common/utils/is-null-or-empty';
|
|
@@ -72,8 +73,12 @@ class ImageCropModalComponent extends TsxComponent<ImageCropModalBindingArgs> im
|
|
|
72
73
|
}
|
|
73
74
|
|
|
74
75
|
public show(args: ImageCropModalShowArgs): void {
|
|
75
|
-
if (
|
|
76
|
-
|
|
76
|
+
if (!globalState.windowExists) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (globalState.currentJCrop != null) {
|
|
81
|
+
globalState.currentJCrop.destroy();
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
this.blocked = true;
|
|
@@ -90,7 +95,7 @@ class ImageCropModalComponent extends TsxComponent<ImageCropModalBindingArgs> im
|
|
|
90
95
|
|
|
91
96
|
(this.$refs.imageCropModal as typeof Modal.prototype).show();
|
|
92
97
|
|
|
93
|
-
const containerWidth = $(
|
|
98
|
+
const containerWidth = $(globalState).width() - 62;
|
|
94
99
|
let maxWidth = 780;
|
|
95
100
|
if (containerWidth < maxWidth) {
|
|
96
101
|
maxWidth = containerWidth;
|
|
@@ -114,7 +119,7 @@ class ImageCropModalComponent extends TsxComponent<ImageCropModalBindingArgs> im
|
|
|
114
119
|
waitForLoad(() => {
|
|
115
120
|
const height = img.height;
|
|
116
121
|
const width = img.width;
|
|
117
|
-
const maxHeight = $(
|
|
122
|
+
const maxHeight = $(globalState).height() - 140;
|
|
118
123
|
const imgRatio = height / width;
|
|
119
124
|
const possibleHeight = maxWidth * imgRatio;
|
|
120
125
|
|
|
@@ -139,7 +144,7 @@ class ImageCropModalComponent extends TsxComponent<ImageCropModalBindingArgs> im
|
|
|
139
144
|
($ as any).Jcrop.component.DragState.prototype.touch = false;
|
|
140
145
|
|
|
141
146
|
(imgElem as any).Jcrop(cropParams, function (this: any) {
|
|
142
|
-
|
|
147
|
+
globalState.currentJCrop = this;
|
|
143
148
|
mySelf.blocked = false;
|
|
144
149
|
});
|
|
145
150
|
});
|
|
@@ -326,7 +331,7 @@ class ImageCropModalComponent extends TsxComponent<ImageCropModalBindingArgs> im
|
|
|
326
331
|
dataParam.TargetContainer = 'savethedate';
|
|
327
332
|
|
|
328
333
|
try {
|
|
329
|
-
const selectedBounds =
|
|
334
|
+
const selectedBounds = globalState.currentJCrop.getSelection();
|
|
330
335
|
dataParam.SelectionX = Math.round(selectedBounds.x);
|
|
331
336
|
dataParam.SelectionY = Math.round(selectedBounds.y);
|
|
332
337
|
dataParam.SelectionHeight = Math.round(selectedBounds.h);
|
|
@@ -2,187 +2,188 @@ import type { _ButtonArgsBase, ButtonLayout, ButtonSize } from '../button/button
|
|
|
2
2
|
import type { UploadButtonFileObtainedArgs } from '../button/upload-button';
|
|
3
3
|
import type { ImageCroppedUploadArgs } from './image-cropping-modal';
|
|
4
4
|
import { Prop, toNative } from 'vue-facing-decorator';
|
|
5
|
+
import { globalState } from '../../app/global-state';
|
|
5
6
|
import PowerduckState from '../../app/powerduck-state';
|
|
6
7
|
import TsxComponent, { Component } from '../../app/vuetsx';
|
|
8
|
+
import { format } from '../../common/extensions/string-extensions';
|
|
7
9
|
import { BrowserImageCompression } from '../../common/utils/broswer-image-compression';
|
|
8
10
|
import { PortalUtils } from '../../common/utils/utils';
|
|
9
11
|
import UploadButton from '../button/upload-button';
|
|
10
12
|
import LoadingIndicator from '../loading-indicator';
|
|
11
13
|
import NotificationProvider from '../ui/notification';
|
|
12
14
|
import ImageCropModal from './image-cropping-modal';
|
|
13
|
-
import { format } from '../../common/extensions/string-extensions';
|
|
14
15
|
|
|
15
16
|
export interface UploadImageAndCropFileCompleteArgs {
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
imageSrc: string;
|
|
18
|
+
fileName: string;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export interface UploadImageAndCropUploadEventArgs extends ImageCroppedUploadArgs { }
|
|
21
22
|
|
|
22
23
|
interface UploadImageAndCropButtonArgs extends _ButtonArgsBase {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
24
|
+
title?: string;
|
|
25
|
+
aspectRatio?: number;
|
|
26
|
+
useCropper?: boolean;
|
|
27
|
+
uploadUrl?: string;
|
|
28
|
+
targetBlobContainer: string;
|
|
29
|
+
imageCropperTitleMessage?: string;
|
|
30
|
+
uploadArgs: (e: UploadImageAndCropUploadEventArgs) => any;
|
|
31
|
+
uploadComplete: (args: any) => void;
|
|
32
|
+
autoCommit?: boolean;
|
|
33
|
+
disableCompression?: boolean;
|
|
34
|
+
allowedTypes?: string[];
|
|
35
|
+
compressionMaxSizeMb?: number;
|
|
36
|
+
isLoading?: boolean;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
@Component
|
|
39
40
|
class UploadImageAndCropButtonComponent extends TsxComponent<UploadImageAndCropButtonArgs> implements UploadImageAndCropButtonArgs {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
41
|
+
@Prop() cssClass!: string;
|
|
42
|
+
@Prop() layout!: ButtonLayout;
|
|
43
|
+
@Prop() text!: string;
|
|
44
|
+
@Prop() size!: ButtonSize;
|
|
45
|
+
@Prop() round!: boolean;
|
|
46
|
+
@Prop() outlined!: boolean;
|
|
47
|
+
@Prop() dismissModal!: boolean;
|
|
48
|
+
@Prop() icon!: string;
|
|
49
|
+
@Prop() disabled!: boolean;
|
|
50
|
+
@Prop() useCropper!: boolean;
|
|
51
|
+
@Prop() fullWidth!: boolean;
|
|
52
|
+
@Prop() title!: string;
|
|
53
|
+
@Prop() aspectRatio!: number;
|
|
54
|
+
@Prop() uploadUrl: string;
|
|
55
|
+
@Prop() isLoading?: boolean;
|
|
56
|
+
@Prop() targetBlobContainer: string;
|
|
57
|
+
@Prop() imageCropperTitleMessage!: string;
|
|
58
|
+
@Prop() uploadArgs: (e: UploadImageAndCropUploadEventArgs) => any;
|
|
59
|
+
@Prop() uploadComplete: (args: any) => void;
|
|
60
|
+
@Prop() autoCommit: boolean;
|
|
61
|
+
@Prop() disableCompression: boolean;
|
|
62
|
+
@Prop() allowedTypes: string[];
|
|
63
|
+
@Prop() compressionMaxSizeMb?: number;
|
|
64
|
+
isInternalLoading: boolean = false;
|
|
65
|
+
|
|
66
|
+
handleFileObtained(e: UploadButtonFileObtainedArgs): void {
|
|
67
|
+
const urlCreator = globalState.URL || globalState.webkitURL;
|
|
68
|
+
const imgUrl = urlCreator.createObjectURL(e.file);
|
|
69
|
+
|
|
70
|
+
if (this.allowedTypes?.length > 0 && !this.allowedTypes.includes(e.file.type)) {
|
|
71
|
+
NotificationProvider.showErrorMessage(PowerduckState.getResourceValue('uploadImageInvalidFileType')[format](PortalUtils.htmlEscape(this.allowedTypes.join(', '))));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (this.useCropper != false) {
|
|
76
|
+
(this.$refs.imgCrop as typeof ImageCropModal.prototype).show({
|
|
77
|
+
fileName: e.file.name,
|
|
78
|
+
imageSrc: imgUrl,
|
|
79
|
+
aspectRatio: (this.aspectRatio || (5 / 3)),
|
|
80
|
+
title: null,
|
|
81
|
+
titleMessageHtml: this.imageCropperTitleMessage,
|
|
82
|
+
handleCropUpload: (e) => {
|
|
83
|
+
return this.getUploadPromise(e);
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
} else {
|
|
87
|
+
this.isInternalLoading = true;
|
|
88
|
+
this.getUploadPromise({
|
|
89
|
+
file: e.file,
|
|
90
|
+
fileName: e.file.name,
|
|
91
|
+
dataUrl: null,
|
|
92
|
+
}).then(() => {
|
|
93
|
+
this.isInternalLoading = false;
|
|
94
|
+
}).catch((_err) => {
|
|
95
|
+
this.isInternalLoading = false;
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
getUploadButton() {
|
|
101
|
+
return this.$refs.uploadButton as typeof UploadButton.prototype;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async getUploadPromise(args: ImageCroppedUploadArgs): Promise<any> {
|
|
105
|
+
if (!(this.disableCompression || args.file.type == 'image/svg+xml')) {
|
|
106
|
+
args.file = await BrowserImageCompression.compress(args.file, {
|
|
107
|
+
maxSizeMB: this.compressionMaxSizeMb,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return new Promise((resolve, reject) => {
|
|
112
|
+
const formData = new FormData();
|
|
113
|
+
if (this.uploadArgs != null) {
|
|
114
|
+
const argsVal = this.uploadArgs(args);
|
|
115
|
+
if (argsVal != null) {
|
|
116
|
+
for (const key in argsVal) {
|
|
117
|
+
formData.append(key, argsVal[key]);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (this.autoCommit === true) {
|
|
123
|
+
const request = new XMLHttpRequest();
|
|
124
|
+
request.open('POST', this.uploadUrl);
|
|
125
|
+
request.onreadystatechange = () => {
|
|
126
|
+
if (request.readyState == 4) {
|
|
127
|
+
let response;
|
|
128
|
+
try {
|
|
129
|
+
response = JSON.parse(request.responseText);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
response = request.responseText;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (request.status == 200) {
|
|
135
|
+
if (this.uploadComplete) {
|
|
136
|
+
this.uploadComplete(response);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
resolve(response);
|
|
140
|
+
} else {
|
|
141
|
+
try {
|
|
142
|
+
if (response.responseText) {
|
|
143
|
+
NotificationProvider.showErrorMessage(response.responseText);
|
|
144
|
+
} else {
|
|
145
|
+
NotificationProvider.showErrorMessage(response);
|
|
146
|
+
}
|
|
147
|
+
} catch (e) { }
|
|
148
|
+
|
|
149
|
+
reject(response);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
request.send(formData);
|
|
155
|
+
} else {
|
|
156
|
+
const argsVal = this.uploadArgs(args);
|
|
157
|
+
this.uploadComplete(argsVal);
|
|
158
|
+
resolve(formData);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
render(h) {
|
|
164
|
+
return (
|
|
165
|
+
<span style="position:relative;">
|
|
166
|
+
<LoadingIndicator visible={(this.isLoading || this.isInternalLoading)} />
|
|
167
|
+
<UploadButton
|
|
168
|
+
ref="uploadButton"
|
|
169
|
+
fileObtained={async (e) => {
|
|
170
|
+
await this.handleFileObtained(e);
|
|
171
|
+
}}
|
|
172
|
+
onlyImages={true}
|
|
173
|
+
cssClass={this.cssClass}
|
|
174
|
+
layout={this.layout}
|
|
175
|
+
text={this.text}
|
|
176
|
+
size={this.size}
|
|
177
|
+
round={this.round}
|
|
178
|
+
outlined={this.outlined}
|
|
179
|
+
icon={this.icon}
|
|
180
|
+
disabled={this.disabled}
|
|
181
|
+
/>
|
|
182
|
+
|
|
183
|
+
<ImageCropModal ref="imgCrop" />
|
|
184
|
+
</span>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
186
187
|
}
|
|
187
188
|
|
|
188
189
|
const UploadImageAndCropButton = toNative(UploadImageAndCropButtonComponent);
|
|
@@ -2,6 +2,7 @@ import type { DropdownButtonItemArgs } from '../dropdown-button/dropdown-button-
|
|
|
2
2
|
import type { FormItemWrapperArgs, MarginType } from '../form/form-item-wrapper';
|
|
3
3
|
import { Temporal } from '@js-temporal/polyfill';
|
|
4
4
|
import { Prop, toNative } from 'vue-facing-decorator';
|
|
5
|
+
import { globalState } from '../../app/global-state';
|
|
5
6
|
import PowerduckState from '../../app/powerduck-state';
|
|
6
7
|
import TsxComponent, { Component } from '../../app/vuetsx';
|
|
7
8
|
import { utcEpochMilliseconds } from '../../common/extensions/temporal-extensions';
|
|
@@ -159,6 +160,10 @@ class DaterangePickerComponent extends TsxComponent<DaterangePickerArgs> impleme
|
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
mounted() {
|
|
163
|
+
if (!globalState.windowExists) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
162
167
|
const self = this;
|
|
163
168
|
const $elem = this.getInputElement();
|
|
164
169
|
const now = Temporal.Now.plainDateTimeISO();
|
|
@@ -261,6 +266,10 @@ class DaterangePickerComponent extends TsxComponent<DaterangePickerArgs> impleme
|
|
|
261
266
|
}
|
|
262
267
|
|
|
263
268
|
beforeUpdate() {
|
|
269
|
+
if (!globalState.windowExists) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
264
273
|
this.handleModelValueChange();
|
|
265
274
|
}
|
|
266
275
|
|