glib-web 2.6.7 → 3.0.0
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/action.js +39 -17
- package/actions/analytics/logEvent.js +2 -2
- package/actions/auth/saveCsrfToken.js +6 -0
- package/actions/cables/push.js +4 -4
- package/actions/commands/enqueue.js +17 -0
- package/actions/fields/reset.js +2 -2
- package/actions/http/get.js +15 -27
- package/actions/panels/scrollTo.js +1 -1
- package/actions/panels/scrollToBottom.js +1 -1
- package/actions/popovers/close.js +5 -0
- package/actions/popovers/open.js +9 -0
- package/actions/windows/closeWithReload.js +1 -1
- package/actions/windows/refreshState.js +3 -1
- package/actions/ws/push.js +5 -3
- package/app.vue +59 -27
- package/components/_badge.vue +1 -6
- package/components/_button.vue +30 -30
- package/components/_chip.vue +27 -29
- package/components/_dropdownMenu.vue +10 -23
- package/components/_icon.vue +5 -5
- package/components/_responsive.vue +7 -21
- package/components/avatar.vue +11 -15
- package/components/banners/alert.vue +2 -7
- package/components/banners/select.vue +18 -30
- package/components/button.vue +4 -5
- package/components/component.vue +112 -133
- package/components/datetime.vue +2 -0
- package/components/fields/_patternText.vue +8 -19
- package/components/fields/_select.vue +9 -27
- package/components/fields/autocomplete.vue +8 -21
- package/components/fields/check.vue +5 -12
- package/components/fields/checkGroup.vue +3 -13
- package/components/fields/country/field.vue +9 -27
- package/components/fields/date.vue +5 -5
- package/components/fields/datetime.vue +6 -11
- package/components/fields/dynamicSelect.vue +8 -29
- package/components/fields/file.vue +10 -29
- package/components/fields/newRichText.vue +67 -54
- package/components/fields/otpField.vue +11 -31
- package/components/fields/phone/field.vue +60 -78
- package/components/fields/radio.vue +8 -44
- package/components/fields/radioGroup.vue +17 -19
- package/components/fields/rating.vue +9 -16
- package/components/fields/richText.vue +27 -45
- package/components/fields/select.vue +10 -7
- package/components/fields/stripe/stripeFields.vue +9 -2
- package/components/fields/stripe/stripeIndividualFields.vue +9 -7
- package/components/fields/stripeExternalAccount.vue +10 -24
- package/components/fields/text.vue +26 -50
- package/components/fields/textarea.vue +14 -27
- package/components/fields/timeZone.vue +9 -6
- package/components/fields/timer.vue +5 -11
- package/components/image.vue +12 -23
- package/components/label.vue +10 -18
- package/components/markdown.vue +45 -23
- package/components/mixins/events.js +24 -25
- package/components/mixins/generic.js +7 -4
- package/components/mixins/inputVariant.js +16 -0
- package/components/mixins/list/autoload.js +7 -5
- package/components/mixins/styles.js +16 -16
- package/components/mixins/table/autoload.js +6 -4
- package/components/mixins/ws/actionCable.js +6 -5
- package/components/mixins/ws/phoenixSocket.js +11 -9
- package/components/p.vue +10 -0
- package/components/panels/column.vue +8 -19
- package/components/panels/custom.vue +9 -13
- package/components/panels/flow.vue +19 -13
- package/components/panels/form.vue +26 -34
- package/components/panels/grid.vue +15 -9
- package/components/panels/horizontal.vue +58 -54
- package/components/panels/list.vue +37 -72
- package/components/panels/responsive.vue +2 -33
- package/components/panels/scroll.vue +3 -0
- package/components/panels/split.vue +2 -2
- package/components/panels/table.vue +32 -63
- package/components/panels/timeline.vue +20 -30
- package/components/panels/vertical.vue +8 -13
- package/components/popover.vue +39 -0
- package/components/progressCircle.vue +2 -8
- package/components/progressbar.vue +4 -14
- package/components/shareButton.vue +24 -30
- package/components/tabBar.vue +29 -28
- package/index.js +60 -94
- package/nav/appbar.vue +8 -6
- package/nav/dialog.vue +30 -49
- package/nav/drawer.vue +39 -51
- package/nav/drawerButton.vue +5 -7
- package/nav/drawerLabel.vue +2 -3
- package/nav/sheet.vue +21 -22
- package/nav/snackbar.vue +19 -30
- package/package.json +13 -16
- package/plugins/driverCustomBehavior.js +1 -1
- package/plugins/updatableComponent.js +2 -2
- package/plugins/vuetify.js +26 -0
- package/store.js +16 -0
- package/templates/comment.vue +42 -19
- package/templates/featured.vue +8 -9
- package/templates/thumbnail-old.vue +188 -0
- package/templates/thumbnail.vue +3 -208
- package/tsconfig.json +1 -1
- package/utils/component.js +18 -18
- package/utils/constant.js +4 -0
- package/utils/eventBus.js +9 -2
- package/utils/history.js +12 -8
- package/utils/http.js +29 -71
- package/utils/launch.js +89 -52
- package/utils/private/ws.js +5 -3
- package/utils/public.js +6 -0
- package/utils/queue.js +102 -0
- package/utils/settings.js +3 -9
|
@@ -1,30 +1,19 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :style="$styles()" :class="classes()">
|
|
3
3
|
<!-- See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date for why we need to use `pattern` -->
|
|
4
|
-
<v-text-field
|
|
5
|
-
|
|
6
|
-
:
|
|
7
|
-
:
|
|
8
|
-
|
|
9
|
-
:hint="spec.hint"
|
|
10
|
-
:type="type"
|
|
11
|
-
:readonly="spec.readOnly || false"
|
|
12
|
-
:disabled="spec.readOnly"
|
|
13
|
-
:min="$sanitizeValue(spec.min)"
|
|
14
|
-
:max="$sanitizeValue(spec.max)"
|
|
15
|
-
:pattern="pattern"
|
|
16
|
-
:rules="$validation()"
|
|
17
|
-
:outlined="$classes().includes('outlined')"
|
|
18
|
-
:style="$styles()"
|
|
19
|
-
:dense="$classes().includes('dense')"
|
|
20
|
-
clearable
|
|
21
|
-
@input="onChange"
|
|
22
|
-
/>
|
|
4
|
+
<v-text-field v-model="fieldModel" :name="fieldName" :label="spec.label" :hint="spec.hint" :type="type"
|
|
5
|
+
:readonly="spec.readOnly || false" :disabled="spec.readOnly" :min="$sanitizeValue(spec.min)"
|
|
6
|
+
:max="$sanitizeValue(spec.max)" :pattern="pattern" :rules="$validation()" :style="$styles()"
|
|
7
|
+
:dense="$classes().includes('dense') || null" clearable @input="onChange" :variant="variant" validate-on="blur"
|
|
8
|
+
persistent-placeholder />
|
|
23
9
|
</div>
|
|
24
10
|
</template>
|
|
25
11
|
|
|
26
12
|
<script>
|
|
13
|
+
import inputVariant from '../mixins/inputVariant';
|
|
14
|
+
|
|
27
15
|
export default {
|
|
16
|
+
mixins: [inputVariant],
|
|
28
17
|
props: {
|
|
29
18
|
spec: { type: Object, required: true },
|
|
30
19
|
type: { type: String, required: true },
|
|
@@ -1,38 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :style="$styles()" :class="classes()">
|
|
3
|
-
<v-autocomplete
|
|
4
|
-
|
|
5
|
-
:
|
|
6
|
-
:
|
|
7
|
-
|
|
8
|
-
:deletable-chips="spec.multiple"
|
|
9
|
-
:multiple="spec.multiple"
|
|
10
|
-
:disabled="spec.readOnly"
|
|
11
|
-
:clearable="!spec.readOnly"
|
|
12
|
-
:hint="spec.hint"
|
|
13
|
-
:placeholder="spec.placeholder"
|
|
14
|
-
:rules="rules"
|
|
15
|
-
validate-on-blur
|
|
16
|
-
persistent-hint
|
|
17
|
-
:class="$classes()"
|
|
18
|
-
:dense="$classes().includes('dense')"
|
|
19
|
-
:outlined="$classes().includes('outlined')"
|
|
20
|
-
:append-icon="append.icon"
|
|
21
|
-
@change="onChange"
|
|
22
|
-
/>
|
|
3
|
+
<v-autocomplete v-model="fieldModel" :label="spec.label" :items="options || []" :chips="spec.multiple"
|
|
4
|
+
:multiple="spec.multiple" :disabled="spec.readOnly" :clearable="!spec.readOnly" :hint="spec.hint"
|
|
5
|
+
:placeholder="spec.placeholder" :rules="rules" persistent-hint :class="$classes()" :append-icon="append.icon"
|
|
6
|
+
@change="onChange" validate-on="blur" item-title='text' :variant="variant" :closable-chips="spec.multiple"
|
|
7
|
+
persistent-placeholder />
|
|
23
8
|
|
|
24
|
-
<input
|
|
25
|
-
v-for="(item, index) in values"
|
|
26
|
-
:key="index"
|
|
27
|
-
type="hidden"
|
|
28
|
-
:name="fieldName"
|
|
29
|
-
:value="item"
|
|
30
|
-
/>
|
|
9
|
+
<input v-for="(item, index) in values" :key="index" type="hidden" :name="fieldName" :value="item" />
|
|
31
10
|
</div>
|
|
32
11
|
</template>
|
|
33
12
|
|
|
34
13
|
<script>
|
|
14
|
+
import inputVariant from '../mixins/inputVariant';
|
|
15
|
+
|
|
35
16
|
export default {
|
|
17
|
+
mixins: [inputVariant],
|
|
36
18
|
props: {
|
|
37
19
|
spec: { type: Object, required: true },
|
|
38
20
|
defaultValue: { type: String, default: null }
|
|
@@ -1,33 +1,20 @@
|
|
|
1
1
|
<!-- TODO: Remove (deprecated) -->
|
|
2
2
|
<template>
|
|
3
3
|
<div :style="genericStyles()">
|
|
4
|
-
<v-combobox
|
|
5
|
-
|
|
6
|
-
:
|
|
7
|
-
:
|
|
8
|
-
:chips="spec.multiple"
|
|
9
|
-
:deletable-chips="spec.multiple"
|
|
10
|
-
:multiple="spec.multiple"
|
|
11
|
-
:readonly="spec.readOnly"
|
|
12
|
-
:disabled="spec.readOnly"
|
|
13
|
-
:hint="spec.hint"
|
|
14
|
-
:placeholder="spec.placeholder"
|
|
15
|
-
:outlined="$classes().includes('outlined')"
|
|
16
|
-
:append-icon="append.icon"
|
|
17
|
-
/>
|
|
4
|
+
<v-combobox v-model="fieldModel" :label="spec.label" :items="options" :chips="spec.multiple"
|
|
5
|
+
:deletable-chips="spec.multiple" :multiple="spec.multiple" :readonly="spec.readOnly" :disabled="spec.readOnly"
|
|
6
|
+
:hint="spec.hint" :placeholder="spec.placeholder" :outlined="$classes().includes('outlined') || null"
|
|
7
|
+
:append-icon="append.icon" validate-on="blur" :variant="variant" persistent-placeholder />
|
|
18
8
|
|
|
19
|
-
<input
|
|
20
|
-
v-for="(item, index) in values"
|
|
21
|
-
:key="index"
|
|
22
|
-
type="hidden"
|
|
23
|
-
:name="fieldName"
|
|
24
|
-
:value="item"
|
|
25
|
-
/>
|
|
9
|
+
<input v-for="(item, index) in values" :key="index" type="hidden" :name="fieldName" :value="item" />
|
|
26
10
|
</div>
|
|
27
11
|
</template>
|
|
28
12
|
|
|
29
13
|
<script>
|
|
14
|
+
import inputVariant from '../mixins/inputVariant';
|
|
15
|
+
|
|
30
16
|
export default {
|
|
17
|
+
mixins: [inputVariant],
|
|
31
18
|
props: {
|
|
32
19
|
spec: { type: Object, required: true }
|
|
33
20
|
},
|
|
@@ -2,18 +2,10 @@
|
|
|
2
2
|
<div :class="$classes()" :style="$styles()">
|
|
3
3
|
<!-- This hidden field should always be there to make sure the submitted param is not empty,
|
|
4
4
|
which could cause "Not accessible" error on the server. -->
|
|
5
|
-
<input type="hidden" :name="fieldName"
|
|
6
|
-
<v-checkbox
|
|
7
|
-
|
|
8
|
-
:
|
|
9
|
-
:disabled="spec.readOnly"
|
|
10
|
-
:value="spec.checkValue"
|
|
11
|
-
:label="fieldModel ? spec.onLabel || spec.label : spec.label"
|
|
12
|
-
:on-icon="spec.onIcon"
|
|
13
|
-
:off-icon="spec.offIcon"
|
|
14
|
-
hide-details
|
|
15
|
-
@change="changed"
|
|
16
|
-
></v-checkbox>
|
|
5
|
+
<input v-model="uncheckValue" type="hidden" :name="fieldName" />
|
|
6
|
+
<v-checkbox v-model="fieldModel" :name="fieldName" :disabled="spec.readOnly"
|
|
7
|
+
:label="fieldModel ? spec.onLabel || spec.label : spec.label" :true-icon="spec.onIcon" :false-icon="spec.offIcon"
|
|
8
|
+
:value="spec.checkValue" hide-details @change="changed" color="primary"></v-checkbox>
|
|
17
9
|
</div>
|
|
18
10
|
</template>
|
|
19
11
|
|
|
@@ -26,6 +18,7 @@ export default {
|
|
|
26
18
|
return {
|
|
27
19
|
groupName: null,
|
|
28
20
|
fieldType: null,
|
|
21
|
+
uncheckValue: this.spec.uncheckValue
|
|
29
22
|
};
|
|
30
23
|
},
|
|
31
24
|
methods: {
|
|
@@ -1,23 +1,13 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
ref="checkGroup"
|
|
4
|
-
class="checkgroup"
|
|
5
|
-
data-component="checkGroup"
|
|
6
|
-
:name="spec.name"
|
|
7
|
-
>
|
|
2
|
+
<div ref="checkGroup" class="checkgroup" data-component="checkGroup" :name="spec.name">
|
|
8
3
|
<!-- <fields-hidden v-if="!anyChecked" :spec="uncheckSpec" /> -->
|
|
9
4
|
|
|
10
5
|
<div v-for="(item, index) in spec.childViews" :key="index">
|
|
11
6
|
<glib-component :spec="childSpec(item)" />
|
|
12
7
|
</div>
|
|
13
8
|
|
|
14
|
-
<v-text-field
|
|
15
|
-
|
|
16
|
-
:disabled="anyChecked"
|
|
17
|
-
:name="spec.name"
|
|
18
|
-
:value="spec.uncheckValue"
|
|
19
|
-
:rules="rules"
|
|
20
|
-
/>
|
|
9
|
+
<v-text-field class="checkgroup__uncheckvalue" :disabled="anyChecked" :name="spec.name" :value="spec.uncheckValue"
|
|
10
|
+
:rules="rules" />
|
|
21
11
|
</div>
|
|
22
12
|
</template>
|
|
23
13
|
|
|
@@ -19,32 +19,14 @@
|
|
|
19
19
|
:value="regionField.value"
|
|
20
20
|
/>-->
|
|
21
21
|
|
|
22
|
-
<v-autocomplete
|
|
23
|
-
|
|
24
|
-
:
|
|
25
|
-
:name="spec.name"
|
|
26
|
-
:items="countryOptions"
|
|
27
|
-
:readonly="spec.readOnly"
|
|
28
|
-
:disabled="spec.readOnly"
|
|
29
|
-
:clearable="!spec.readOnly"
|
|
30
|
-
:hint="spec.hint"
|
|
31
|
-
persistent-hint
|
|
32
|
-
:outlined="$classes().includes('outlined')"
|
|
33
|
-
/>
|
|
22
|
+
<v-autocomplete v-model="country" :label="spec.label" :name="spec.name" :items="countryOptions"
|
|
23
|
+
:readonly="spec.readOnly" :disabled="spec.readOnly" :clearable="!spec.readOnly" :hint="spec.hint" persistent-hint
|
|
24
|
+
:outlined="$classes().includes('outlined') || null" />
|
|
34
25
|
|
|
35
|
-
<v-autocomplete
|
|
36
|
-
|
|
37
|
-
:
|
|
38
|
-
:
|
|
39
|
-
:value="regionField.value"
|
|
40
|
-
:items="regionOptions"
|
|
41
|
-
:readonly="regionField.readOnly"
|
|
42
|
-
:disabled="regionField.readOnly"
|
|
43
|
-
:clearable="!regionField.readOnly"
|
|
44
|
-
:hint="regionField.hint"
|
|
45
|
-
persistent-hint
|
|
46
|
-
:outlined="$classes().includes('outlined')"
|
|
47
|
-
/>
|
|
26
|
+
<v-autocomplete v-if="regionField && regionOptions" :label="regionField.label" :name="regionField.name"
|
|
27
|
+
:value="regionField.value" :items="regionOptions" :readonly="regionField.readOnly" :disabled="regionField.readOnly"
|
|
28
|
+
:clearable="!regionField.readOnly" :hint="regionField.hint" persistent-hint
|
|
29
|
+
:outlined="$classes().includes('outlined') || null" />
|
|
48
30
|
</div>
|
|
49
31
|
</template>
|
|
50
32
|
|
|
@@ -63,10 +45,10 @@ export default {
|
|
|
63
45
|
};
|
|
64
46
|
},
|
|
65
47
|
computed: {
|
|
66
|
-
regionField: function() {
|
|
48
|
+
regionField: function () {
|
|
67
49
|
return this.spec.region;
|
|
68
50
|
},
|
|
69
|
-
regionOptions: function() {
|
|
51
|
+
regionOptions: function () {
|
|
70
52
|
return regions[this.country];
|
|
71
53
|
}
|
|
72
54
|
},
|
|
@@ -9,22 +9,22 @@
|
|
|
9
9
|
</template>
|
|
10
10
|
|
|
11
11
|
<script>
|
|
12
|
-
import PatternTextField from "./_patternText";
|
|
12
|
+
import PatternTextField from "./_patternText.vue";
|
|
13
13
|
|
|
14
14
|
export default {
|
|
15
15
|
components: {
|
|
16
16
|
// Need to start with `fields-` to enable jsonlogic in `styles.js#_linkFieldModels`
|
|
17
|
-
"fields-patternText": PatternTextField
|
|
17
|
+
"fields-patternText": PatternTextField,
|
|
18
18
|
},
|
|
19
19
|
props: {
|
|
20
|
-
spec: { type: Object, required: true }
|
|
20
|
+
spec: { type: Object, required: true },
|
|
21
21
|
},
|
|
22
22
|
methods: {
|
|
23
23
|
action_merge(mergedSpec) {
|
|
24
24
|
Object.assign(this.spec, mergedSpec);
|
|
25
25
|
this.$refs.delegate.updateData();
|
|
26
|
-
}
|
|
27
|
-
}
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
28
|
};
|
|
29
29
|
</script>
|
|
30
30
|
|
|
@@ -13,30 +13,25 @@
|
|
|
13
13
|
:outlined="$classes().includes('outlined')"
|
|
14
14
|
:style="genericStyles()"
|
|
15
15
|
/> -->
|
|
16
|
-
<fields-patternText
|
|
17
|
-
:spec="spec"
|
|
18
|
-
type="datetime-local"
|
|
19
|
-
pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}"
|
|
20
|
-
:value="value"
|
|
21
|
-
/>
|
|
16
|
+
<fields-patternText :spec="spec" type="datetime-local" pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}" />
|
|
22
17
|
</template>
|
|
23
18
|
|
|
24
19
|
<script>
|
|
25
|
-
import PatternTextField from "./_patternText";
|
|
20
|
+
import PatternTextField from "./_patternText.vue";
|
|
26
21
|
|
|
27
22
|
export default {
|
|
28
23
|
components: {
|
|
29
24
|
// Need to start with `fields-` to enable jsonlogic in `styles.js#_linkFieldModels`
|
|
30
|
-
"fields-patternText": PatternTextField
|
|
25
|
+
"fields-patternText": PatternTextField,
|
|
31
26
|
},
|
|
32
27
|
props: {
|
|
33
|
-
spec: { type: Object, required: true }
|
|
28
|
+
spec: { type: Object, required: true },
|
|
34
29
|
},
|
|
35
30
|
data() {
|
|
36
31
|
return {
|
|
37
|
-
value: null
|
|
32
|
+
value: null,
|
|
38
33
|
};
|
|
39
|
-
}
|
|
34
|
+
},
|
|
40
35
|
// methods: {
|
|
41
36
|
// $ready() {
|
|
42
37
|
// this.value = this.spec.value.slice(0, 16);
|
|
@@ -1,42 +1,20 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div :style="genericStyles()">
|
|
3
|
-
<v-autocomplete
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
:items="allItems"
|
|
7
|
-
:loading="$isBusy"
|
|
8
|
-
:search-input.sync="search"
|
|
9
|
-
:label="spec.label"
|
|
10
|
-
hide-no-data
|
|
11
|
-
hide-selected
|
|
12
|
-
no-filter
|
|
13
|
-
return-object
|
|
14
|
-
:chips="true"
|
|
15
|
-
:deletable-chips="true"
|
|
16
|
-
:multiple="spec.multiple"
|
|
17
|
-
>
|
|
3
|
+
<v-autocomplete ref="autocomplete" v-model="model" :items="allItems" :loading="$isBusy" :v-model:search-input="search"
|
|
4
|
+
:label="spec.label" hide-no-data hide-selected no-filter return-object :chips="true" :deletable-chips="true"
|
|
5
|
+
:multiple="spec.multiple">
|
|
18
6
|
<template v-slot:item="data">
|
|
19
7
|
{{ data.item.title }} - {{ data.item.subtitle }}
|
|
20
8
|
</template>
|
|
21
9
|
|
|
22
|
-
<v-list-item
|
|
23
|
-
v-if="!$isBusy && nextPageUrl"
|
|
24
|
-
slot="append-item"
|
|
25
|
-
class="load-more"
|
|
26
|
-
>
|
|
10
|
+
<!-- <v-list-item v-if="!$isBusy && nextPageUrl" slot="append-item" class="load-more">
|
|
27
11
|
<v-list-item-content class="text-content" @click="loadMore">
|
|
28
12
|
<v-list-item-title>Load More</v-list-item-title>
|
|
29
13
|
</v-list-item-content>
|
|
30
|
-
</v-list-item>
|
|
14
|
+
</v-list-item> -->
|
|
31
15
|
</v-autocomplete>
|
|
32
16
|
|
|
33
|
-
<input
|
|
34
|
-
v-for="(item, index) in values"
|
|
35
|
-
:key="index"
|
|
36
|
-
type="hidden"
|
|
37
|
-
:name="spec.name"
|
|
38
|
-
:value="item.value"
|
|
39
|
-
/>
|
|
17
|
+
<input v-for="(item, index) in values" :key="index" type="hidden" :name="spec.name" :value="item.value" />
|
|
40
18
|
</div>
|
|
41
19
|
</template>
|
|
42
20
|
|
|
@@ -155,7 +133,7 @@ export default {
|
|
|
155
133
|
return data.rows.map(row => {
|
|
156
134
|
const extra = row.extra;
|
|
157
135
|
row.value = extra.value;
|
|
158
|
-
row.
|
|
136
|
+
row.title = extra.text;
|
|
159
137
|
return row;
|
|
160
138
|
});
|
|
161
139
|
}
|
|
@@ -167,6 +145,7 @@ export default {
|
|
|
167
145
|
.load-more {
|
|
168
146
|
cursor: pointer;
|
|
169
147
|
}
|
|
148
|
+
|
|
170
149
|
.load-more:hover {
|
|
171
150
|
background-color: lightgray;
|
|
172
151
|
}
|
|
@@ -1,29 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div ref="fileUploadContainer"
|
|
2
|
+
<div ref="fileUploadContainer" :style="$styles()">
|
|
3
3
|
<label class="v-label v-label--active">{{ spec.label }}</label>
|
|
4
4
|
<div class="preview-container">
|
|
5
|
-
<v-avatar
|
|
6
|
-
v-if="placeholder.type == 'avatar'"
|
|
7
|
-
:style="genericStyles(placeholder)"
|
|
8
|
-
class="mr-4"
|
|
9
|
-
>
|
|
5
|
+
<v-avatar v-if="placeholder.type == 'avatar'" :style="genericStyles(placeholder)" class="mr-4">
|
|
10
6
|
<img :src="fileImage || placeholder.url" />
|
|
11
7
|
</v-avatar>
|
|
12
|
-
<img
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/>
|
|
18
|
-
|
|
19
|
-
<v-text-field
|
|
20
|
-
v-else-if="placeholder.type == 'input'"
|
|
21
|
-
:value="fileTitle"
|
|
22
|
-
outlined
|
|
23
|
-
prominent
|
|
24
|
-
placholder="Upload your file"
|
|
25
|
-
disabled
|
|
26
|
-
/>
|
|
8
|
+
<img v-else-if="placeholder.type == 'image'" class="square-image mr-4" :style="genericStyles(placeholder)"
|
|
9
|
+
:src="fileImage || placeholder.url" />
|
|
10
|
+
|
|
11
|
+
<v-text-field v-else-if="placeholder.type == 'input'" :value="fileTitle" variant="outlined"
|
|
12
|
+
placholder="Upload your file" disabled />
|
|
27
13
|
|
|
28
14
|
<span v-else class="mr-4">{{ fileTitle }}</span>
|
|
29
15
|
|
|
@@ -38,21 +24,16 @@
|
|
|
38
24
|
</v-btn>
|
|
39
25
|
</span>
|
|
40
26
|
<span v-else class="action-container">
|
|
41
|
-
<v-btn icon @click="triggerUpload">
|
|
27
|
+
<v-btn variant="flat" icon @click="triggerUpload">
|
|
42
28
|
<v-icon>edit</v-icon>
|
|
43
29
|
</v-btn>
|
|
44
30
|
|
|
45
|
-
<v-btn v-if="fileImage" icon @click="removeImage">
|
|
31
|
+
<v-btn variant="flat" v-if="fileImage" icon @click="removeImage">
|
|
46
32
|
<v-icon>close</v-icon>
|
|
47
33
|
</v-btn>
|
|
48
34
|
</span>
|
|
49
35
|
</div>
|
|
50
|
-
<input
|
|
51
|
-
ref="directUploadFile"
|
|
52
|
-
style="display: none"
|
|
53
|
-
type="file"
|
|
54
|
-
@change="uploadFiles"
|
|
55
|
-
/>
|
|
36
|
+
<input ref="directUploadFile" style="display: none" type="file" @change="uploadFiles" />
|
|
56
37
|
|
|
57
38
|
<!-- <input type="file" :name="spec.name" ref='directUploadFile' @change='uploadFiles' v-show='!uploaded'/> -->
|
|
58
39
|
<v-progress-linear v-if="showProgress" v-model="progress.value" />
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div style="width: 100%;">
|
|
3
|
-
<v-progress-linear
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
<v-progress-linear
|
|
4
|
+
v-if="showProgress"
|
|
5
|
+
v-model="progress.value"
|
|
6
|
+
/>
|
|
7
|
+
<textarea
|
|
8
|
+
id="editor"
|
|
9
|
+
class="entry"
|
|
10
|
+
></textarea>
|
|
11
|
+
<input
|
|
12
|
+
type="hidden"
|
|
13
|
+
:name="spec.name"
|
|
14
|
+
:value="cleanValue"
|
|
15
|
+
/>
|
|
6
16
|
<input
|
|
7
17
|
v-for="(imageKey, index) in imageKeys"
|
|
8
18
|
:key="index"
|
|
@@ -14,7 +24,10 @@
|
|
|
14
24
|
<p>{{ cleanValue }}</p>
|
|
15
25
|
|
|
16
26
|
<ol>
|
|
17
|
-
<li
|
|
27
|
+
<li
|
|
28
|
+
v-for="(imageKey, index) in imageKeys"
|
|
29
|
+
:key="index"
|
|
30
|
+
>
|
|
18
31
|
{{ images[imageKey] }} -- {{ imageKey }}
|
|
19
32
|
</li>
|
|
20
33
|
</ol>
|
|
@@ -23,7 +36,7 @@
|
|
|
23
36
|
|
|
24
37
|
<script>
|
|
25
38
|
import Uploader from "../../utils/uploader";
|
|
26
|
-
import RedactorX from "../../static/redactorx";
|
|
39
|
+
// import RedactorX from "../../static/redactorx";
|
|
27
40
|
import "../../static/redactorx.css";
|
|
28
41
|
import "../../static/plugins/icons/icons";
|
|
29
42
|
import "../../static/plugins/inlineformat/inlineformat";
|
|
@@ -35,8 +48,8 @@ export default {
|
|
|
35
48
|
props: {
|
|
36
49
|
spec: {
|
|
37
50
|
type: Object,
|
|
38
|
-
default: null
|
|
39
|
-
}
|
|
51
|
+
default: null,
|
|
52
|
+
},
|
|
40
53
|
},
|
|
41
54
|
data() {
|
|
42
55
|
return {
|
|
@@ -44,13 +57,13 @@ export default {
|
|
|
44
57
|
cleanValue: "",
|
|
45
58
|
progress: { value: -1 },
|
|
46
59
|
images: {},
|
|
47
|
-
imageKeys: []
|
|
60
|
+
imageKeys: [],
|
|
48
61
|
};
|
|
49
62
|
},
|
|
50
63
|
computed: {
|
|
51
|
-
showProgress: function() {
|
|
64
|
+
showProgress: function () {
|
|
52
65
|
return this.progress.value >= 0;
|
|
53
|
-
}
|
|
66
|
+
},
|
|
54
67
|
},
|
|
55
68
|
methods: {
|
|
56
69
|
$ready() {
|
|
@@ -60,26 +73,26 @@ export default {
|
|
|
60
73
|
initValue() {
|
|
61
74
|
let rawValue = this.spec.value || "";
|
|
62
75
|
|
|
63
|
-
Utils.type.ifArray(this.spec.images, images => {
|
|
76
|
+
Utils.type.ifArray(this.spec.images, (images) => {
|
|
64
77
|
const vm = this;
|
|
65
|
-
rawValue = rawValue.replace(
|
|
66
|
-
|
|
67
|
-
index
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
rawValue = rawValue.replace(
|
|
79
|
+
/\{\{image([0-9]+)\}\}/g,
|
|
80
|
+
function (_, index) {
|
|
81
|
+
const image = images[index - 1];
|
|
82
|
+
if (
|
|
83
|
+
image &&
|
|
84
|
+
vm.$type.isString(image.value) &&
|
|
85
|
+
vm.$type.isString(image.fileUrl)
|
|
86
|
+
) {
|
|
87
|
+
const url = image.fileUrl;
|
|
88
|
+
const key = url.hashCode().toString();
|
|
89
|
+
vm.images[key] = image.value;
|
|
90
|
+
// return `<img src="${url}">`;
|
|
91
|
+
return url;
|
|
92
|
+
}
|
|
93
|
+
return "{{IMAGE_NOT_FOUND}}";
|
|
80
94
|
}
|
|
81
|
-
|
|
82
|
-
});
|
|
95
|
+
);
|
|
83
96
|
});
|
|
84
97
|
|
|
85
98
|
this.updateValue(rawValue);
|
|
@@ -91,23 +104,23 @@ export default {
|
|
|
91
104
|
source: Utils.settings.isDev,
|
|
92
105
|
plugins: ["inlineformat", "style"],
|
|
93
106
|
image: {
|
|
94
|
-
upload: function(upload, data) {
|
|
107
|
+
upload: function (upload, data) {
|
|
95
108
|
for (var key in data.files) {
|
|
96
109
|
if (typeof data.files[key] === "object") {
|
|
97
110
|
const file = data.files[key];
|
|
98
|
-
vm.uploadImage(file, response => {
|
|
111
|
+
vm.uploadImage(file, (response) => {
|
|
99
112
|
upload.complete(response, data.e);
|
|
100
113
|
});
|
|
101
114
|
}
|
|
102
115
|
}
|
|
103
|
-
}
|
|
116
|
+
},
|
|
104
117
|
},
|
|
105
118
|
subscribe: {
|
|
106
|
-
"editor.change": function(event) {
|
|
119
|
+
"editor.change": function (event) {
|
|
107
120
|
const content = this.app.editor.getContent();
|
|
108
121
|
vm.updateValue(content);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
122
|
+
},
|
|
123
|
+
},
|
|
111
124
|
});
|
|
112
125
|
},
|
|
113
126
|
updateValue(content) {
|
|
@@ -119,20 +132,20 @@ export default {
|
|
|
119
132
|
var index = 0;
|
|
120
133
|
vm.imageKeys.clear();
|
|
121
134
|
// TODO: Fix to avoid replacing <video src="">
|
|
122
|
-
this.cleanValue = this.rawValue.replace(
|
|
123
|
-
|
|
124
|
-
imageValue
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
this.cleanValue = this.rawValue.replace(
|
|
136
|
+
/src="([^"]+)"/g,
|
|
137
|
+
function (_, imageValue) {
|
|
138
|
+
// It seems that quill encodes '&' in the URL to '&' which would screw up key matching.
|
|
139
|
+
var decodedValue = imageValue.replace(/&/g, "&");
|
|
140
|
+
const key = decodedValue.hashCode().toString();
|
|
141
|
+
const existingIndex = vm.imageKeys.indexOf(key);
|
|
142
|
+
if (existingIndex < 0) {
|
|
143
|
+
vm.imageKeys.push(key);
|
|
144
|
+
return `src="{{image${++index}}}"`;
|
|
145
|
+
}
|
|
146
|
+
return `src="{{image${existingIndex + 1}}}"`;
|
|
133
147
|
}
|
|
134
|
-
|
|
135
|
-
});
|
|
148
|
+
);
|
|
136
149
|
},
|
|
137
150
|
uploadImage(file, onComplete) {
|
|
138
151
|
const uploaderSpec = this.spec.imageUploader;
|
|
@@ -147,7 +160,7 @@ export default {
|
|
|
147
160
|
upload.start((error, blob) => {
|
|
148
161
|
if (error) {
|
|
149
162
|
// Handle the error
|
|
150
|
-
console.
|
|
163
|
+
console.log("Failed uploading image!");
|
|
151
164
|
} else {
|
|
152
165
|
this.insertImage(file, blob, onComplete);
|
|
153
166
|
}
|
|
@@ -157,18 +170,18 @@ export default {
|
|
|
157
170
|
insertImage(file, blob, onComplete) {
|
|
158
171
|
let vm = this;
|
|
159
172
|
var reader = new FileReader();
|
|
160
|
-
reader.onload = function(e) {
|
|
173
|
+
reader.onload = function (e) {
|
|
161
174
|
if (file.type.indexOf("image") !== -1) {
|
|
162
175
|
var image = new Image();
|
|
163
176
|
image.src = e.target.result;
|
|
164
177
|
|
|
165
178
|
const key = image.src.hashCode().toString();
|
|
166
|
-
image.onload = function() {
|
|
179
|
+
image.onload = function () {
|
|
167
180
|
const response = {
|
|
168
181
|
[key]: {
|
|
169
182
|
url: image.src,
|
|
170
|
-
id: key
|
|
171
|
-
}
|
|
183
|
+
id: key,
|
|
184
|
+
},
|
|
172
185
|
};
|
|
173
186
|
|
|
174
187
|
onComplete(response);
|
|
@@ -179,8 +192,8 @@ export default {
|
|
|
179
192
|
};
|
|
180
193
|
reader.readAsDataURL(file);
|
|
181
194
|
vm.progress.value = -1;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
195
|
+
},
|
|
196
|
+
},
|
|
184
197
|
};
|
|
185
198
|
</script>
|
|
186
199
|
|