mirror of
https://github.com/mayswind/ezbookkeeping.git
synced 2026-05-15 07:27:33 +08:00
Upgrade to vue3 (#16)
* upgrade to vue 3.x and framework7 8.x * change calendar plugin to vue-datepicker * disable export button when user does not hava any transaction * implement new pin code input * append thousands separator in amount in exchange rates page
This commit is contained in:
@@ -1,27 +1,27 @@
|
||||
<template>
|
||||
<f7-sheet :opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler"
|
||||
:opened="show"
|
||||
@sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-toolbar>
|
||||
<div class="swipe-handler"></div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<f7-link sheet-close :text="$t('Done')"></f7-link>
|
||||
</div>
|
||||
</f7-toolbar>
|
||||
<f7-page-content>
|
||||
<f7-block class="margin-vertical">
|
||||
<f7-row class="padding-vertical padding-horizontal-half"
|
||||
:class="{ 'row-has-selected-item': hasSelectedIcon(row) }"
|
||||
v-for="(row, idx) in allColorRows" :key="idx">
|
||||
<f7-col class="text-align-center" v-for="colorInfo in row" :key="colorInfo.color">
|
||||
<f7-icon f7="app_fill"
|
||||
:style="colorInfo.color | iconStyle('default', 'var(--default-icon-color)')"
|
||||
@click.native="onColorClicked(colorInfo)">
|
||||
<f7-block class="margin-vertical no-padding">
|
||||
<div class="grid grid-cols-7 padding-vertical-half padding-horizontal-half"
|
||||
:class="{ 'row-has-selected-item': hasSelectedIcon(row) }"
|
||||
:key="idx" v-for="(row, idx) in allColorRows">
|
||||
<div class="text-align-center" :key="colorInfo.color" v-for="colorInfo in row">
|
||||
<ItemIcon icon-type="fixed-f7" icon-id="app_fill" :color="colorInfo.color" @click="onColorClicked(colorInfo)">
|
||||
<f7-badge color="default" class="right-bottom-icon" v-if="currentValue && currentValue === colorInfo.color">
|
||||
<f7-icon f7="checkmark_alt"></f7-icon>
|
||||
</f7-badge>
|
||||
</f7-icon>
|
||||
</f7-col>
|
||||
<f7-col v-for="idx in (itemPerRow - row.length)" :key="idx"></f7-col>
|
||||
</f7-row>
|
||||
</ItemIcon>
|
||||
</div>
|
||||
</div>
|
||||
</f7-block>
|
||||
</f7-page-content>
|
||||
</f7-sheet>
|
||||
@@ -30,16 +30,20 @@
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'value',
|
||||
'modelValue',
|
||||
'columnCount',
|
||||
'show',
|
||||
'allColorInfos'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show'
|
||||
],
|
||||
data() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
currentValue: self.value,
|
||||
currentValue: self.modelValue,
|
||||
itemPerRow: self.columnCount || 7
|
||||
}
|
||||
},
|
||||
@@ -64,11 +68,11 @@ export default {
|
||||
methods: {
|
||||
onColorClicked(colorInfo) {
|
||||
this.currentValue = colorInfo.color;
|
||||
this.$emit('input', this.currentValue);
|
||||
this.$emit('update:modelValue', this.currentValue);
|
||||
this.$emit('update:show', false);
|
||||
},
|
||||
onSheetOpen(event) {
|
||||
this.currentValue = this.value;
|
||||
this.currentValue = this.modelValue;
|
||||
this.scrollToSelectedItem(event.$el);
|
||||
},
|
||||
onSheetClosed() {
|
||||
|
||||
@@ -1,56 +1,39 @@
|
||||
<template>
|
||||
<f7-sheet style="height:auto" :opened="show"
|
||||
@sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler" style="height:auto"
|
||||
:opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<div class="swipe-handler"></div>
|
||||
<f7-page-content>
|
||||
<div class="display-flex padding justify-content-space-between align-items-center">
|
||||
<div style="font-size: 18px" v-if="title"><b>{{ title }}</b></div>
|
||||
</div>
|
||||
<div class="padding-horizontal padding-bottom">
|
||||
<p class="no-margin-top margin-bottom-half" v-if="hint">{{ hint }}</p>
|
||||
<p class="no-margin-top" v-if="hint">{{ hint }}</p>
|
||||
<p class="no-margin-top margin-bottom" v-if="beginDateTime && endDateTime">
|
||||
<span>{{ beginDateTime }}</span>
|
||||
<span> - </span>
|
||||
<span>{{ endDateTime }}</span>
|
||||
</p>
|
||||
<slot></slot>
|
||||
<f7-list no-hairlines inline-labels class="no-margin-top margin-bottom">
|
||||
<f7-list-input
|
||||
:label="$t('Begin Time')"
|
||||
type="datepicker"
|
||||
class="date-range-sheet-time-item"
|
||||
:calendar-params="{
|
||||
timePicker: true,
|
||||
dateFormat: $t('input-format.datetime.long'),
|
||||
firstDay: defaultFirstDayOfWeek,
|
||||
toolbarCloseText: $t('Done'),
|
||||
timePickerPlaceholder: $t('Select Time'),
|
||||
timePickerFormat: $locale.getInputTimeIntlDateTimeFormatOptions(),
|
||||
monthNames: $locale.getAllLongMonthNames(),
|
||||
monthNamesShort: $locale.getAllShortMonthNames(),
|
||||
dayNames: $locale.getAllLongWeekdayNames(),
|
||||
dayNamesShort: $locale.getAllShortWeekdayNames()}"
|
||||
:value="currentMinDate"
|
||||
@calendar:change="currentMinDate = $event"
|
||||
>
|
||||
</f7-list-input>
|
||||
|
||||
<f7-list-input
|
||||
:label="$t('End Time')"
|
||||
type="datepicker"
|
||||
class="date-range-sheet-time-item"
|
||||
:calendar-params="{
|
||||
timePicker: true,
|
||||
dateFormat: $t('input-format.datetime.long'),
|
||||
firstDay: defaultFirstDayOfWeek,
|
||||
toolbarCloseText: $t('Done'),
|
||||
timePickerPlaceholder: $t('Select Time'),
|
||||
timePickerFormat: $locale.getInputTimeIntlDateTimeFormatOptions(),
|
||||
monthNames: $locale.getAllLongMonthNames(),
|
||||
monthNamesShort: $locale.getAllShortMonthNames(),
|
||||
dayNames: $locale.getAllLongWeekdayNames(),
|
||||
dayNamesShort: $locale.getAllShortWeekdayNames()}"
|
||||
:value="currentMaxDate"
|
||||
@calendar:change="currentMaxDate = $event"
|
||||
>
|
||||
</f7-list-input>
|
||||
</f7-list>
|
||||
<VueDatePicker range inline enable-seconds six-weeks
|
||||
auto-apply month-name-format="long"
|
||||
class="margin-bottom"
|
||||
:dark="isDarkMode"
|
||||
:week-start="firstDayOfWeek"
|
||||
:year-range="yearRange"
|
||||
:day-names="dayNames"
|
||||
:is24="is24Hour"
|
||||
:partial-range="false"
|
||||
:preset-ranges="presetRanges"
|
||||
v-model="dateRange">
|
||||
<template #month="{ text }">
|
||||
{{ $t(`datetime.${text}.short`) }}
|
||||
</template>
|
||||
<template #month-overlay-value="{ text }">
|
||||
{{ $t(`datetime.${text}.short`) }}
|
||||
</template>
|
||||
</VueDatePicker>
|
||||
<f7-button large fill
|
||||
:class="{ 'disabled': !currentMinDate || !currentMaxDate }"
|
||||
:class="{ 'disabled': !dateRange[0] || !dateRange[1] }"
|
||||
:text="$t('Continue')"
|
||||
@click="confirm">
|
||||
</f7-button>
|
||||
@@ -71,6 +54,10 @@ export default {
|
||||
'hint',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:show',
|
||||
'dateRange:change'
|
||||
],
|
||||
data() {
|
||||
const self = this;
|
||||
let minDate = self.$utilities.getTodayFirstUnixTime();
|
||||
@@ -84,65 +71,87 @@ export default {
|
||||
maxDate = self.maxTime;
|
||||
}
|
||||
|
||||
minDate = self.$utilities.getDummyUnixTimeForLocalUsage(minDate, self.$utilities.getTimezoneOffsetMinutes(), self.$utilities.getBrowserTimezoneOffsetMinutes());
|
||||
maxDate = self.$utilities.getDummyUnixTimeForLocalUsage(maxDate, self.$utilities.getTimezoneOffsetMinutes(), self.$utilities.getBrowserTimezoneOffsetMinutes());
|
||||
|
||||
return {
|
||||
currentMinDate: [self.$utilities.getLocalDatetimeFromUnixTime(minDate)],
|
||||
currentMaxDate: [self.$utilities.getLocalDatetimeFromUnixTime(maxDate)]
|
||||
yearRange: [
|
||||
2000,
|
||||
this.$utilities.getYear(this.$utilities.getCurrentDateTime()) + 1
|
||||
],
|
||||
dateRange: [
|
||||
this.$utilities.getLocalDatetimeFromUnixTime(this.$utilities.getDummyUnixTimeForLocalUsage(minDate, this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes())),
|
||||
this.$utilities.getLocalDatetimeFromUnixTime(this.$utilities.getDummyUnixTimeForLocalUsage(maxDate, this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes()))
|
||||
]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
defaultFirstDayOfWeek() {
|
||||
return this.$store.getters.currentUserFirstDayOfWeek;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'currentMinDate': function (newValue) {
|
||||
if (!newValue) {
|
||||
this.currentMinDate = [this.$utilities.getLocalDatetimeFromUnixTime(this.$utilities.getCurrentUnixTime())];
|
||||
}
|
||||
isDarkMode() {
|
||||
return this.$root.isDarkMode;
|
||||
},
|
||||
'currentMaxDate': function (newValue) {
|
||||
if (!newValue) {
|
||||
this.currentMaxDate = [this.$utilities.getLocalDatetimeFromUnixTime(this.$utilities.getCurrentUnixTime())];
|
||||
}
|
||||
firstDayOfWeek() {
|
||||
return this.$store.getters.currentUserFirstDayOfWeek;
|
||||
},
|
||||
dayNames() {
|
||||
return this.$locale.getAllMinWeekdayNames();
|
||||
},
|
||||
is24Hour() {
|
||||
const datetimeFormat = this.$t('format.datetime.long');
|
||||
return this.$utilities.is24HourFormat(datetimeFormat);
|
||||
},
|
||||
beginDateTime() {
|
||||
const actualBeginUnixTime = this.$utilities.getActualUnixTimeForStore(this.$utilities.getUnixTime(this.dateRange[0]), this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes());
|
||||
return this.$utilities.formatUnixTime(actualBeginUnixTime, this.$t('format.datetime.long'));
|
||||
},
|
||||
endDateTime() {
|
||||
const actualEndUnixTime = this.$utilities.getActualUnixTimeForStore(this.$utilities.getUnixTime(this.dateRange[1]), this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes());
|
||||
return this.$utilities.formatUnixTime(actualEndUnixTime, this.$t('format.datetime.long'));
|
||||
},
|
||||
presetRanges() {
|
||||
const presetRanges = [];
|
||||
|
||||
[
|
||||
this.$constants.datetime.allDateRanges.Today,
|
||||
this.$constants.datetime.allDateRanges.LastSevenDays,
|
||||
this.$constants.datetime.allDateRanges.LastThirtyDays,
|
||||
this.$constants.datetime.allDateRanges.ThisWeek,
|
||||
this.$constants.datetime.allDateRanges.ThisMonth,
|
||||
this.$constants.datetime.allDateRanges.ThisYear
|
||||
].forEach(dateRangeType => {
|
||||
const dateRange = this.$utilities.getDateRangeByDateType(dateRangeType.type, this.firstDayOfWeek);
|
||||
|
||||
presetRanges.push({
|
||||
label: this.$t(dateRangeType.name),
|
||||
range: [
|
||||
this.$utilities.getLocalDatetimeFromUnixTime(this.$utilities.getDummyUnixTimeForLocalUsage(dateRange.minTime, this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes())),
|
||||
this.$utilities.getLocalDatetimeFromUnixTime(this.$utilities.getDummyUnixTimeForLocalUsage(dateRange.maxTime, this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes()))
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
return presetRanges;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSheetOpen() {
|
||||
if (this.minTime) {
|
||||
const minTime = this.$utilities.getDummyUnixTimeForLocalUsage(this.minTime, this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes());
|
||||
this.currentMinDate = [this.$utilities.getLocalDatetimeFromUnixTime(minTime)];
|
||||
this.dateRange[0] = this.$utilities.getLocalDatetimeFromUnixTime(this.$utilities.getDummyUnixTimeForLocalUsage(this.minTime, this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes()));
|
||||
}
|
||||
|
||||
if (this.maxTime) {
|
||||
const maxTime = this.$utilities.getDummyUnixTimeForLocalUsage(this.maxTime, this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes());
|
||||
this.currentMaxDate = [this.$utilities.getLocalDatetimeFromUnixTime(maxTime)];
|
||||
this.dateRange[1] = this.$utilities.getLocalDatetimeFromUnixTime(this.$utilities.getDummyUnixTimeForLocalUsage(this.maxTime, this.$utilities.getTimezoneOffsetMinutes(), this.$utilities.getBrowserTimezoneOffsetMinutes()));
|
||||
}
|
||||
},
|
||||
onSheetClosed() {
|
||||
this.$emit('update:show', false);
|
||||
},
|
||||
confirm() {
|
||||
if (!this.currentMinDate || !this.currentMaxDate) {
|
||||
if (!this.dateRange[0] || !this.dateRange[1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
let currentMinDate = this.currentMinDate;
|
||||
const currentMinDate = this.dateRange[0];
|
||||
const currentMaxDate = this.dateRange[1];
|
||||
|
||||
if (this.$utilities.isArray(this.currentMinDate)) {
|
||||
currentMinDate = this.currentMinDate[0];
|
||||
}
|
||||
|
||||
let currentMaxDate = this.currentMaxDate;
|
||||
|
||||
if (this.$utilities.isArray(this.currentMaxDate)) {
|
||||
currentMaxDate = this.currentMaxDate[0];
|
||||
}
|
||||
|
||||
let minUnixTime = this.$utilities.getMinuteFirstUnixTime(currentMinDate);
|
||||
let maxUnixTime = this.$utilities.getMinuteLastUnixTime(currentMaxDate);
|
||||
let minUnixTime = this.$utilities.getUnixTime(currentMinDate);
|
||||
let maxUnixTime = this.$utilities.getUnixTime(currentMaxDate);
|
||||
|
||||
if (minUnixTime < 0 || maxUnixTime < 0) {
|
||||
this.$toast('Date is too early');
|
||||
@@ -160,9 +169,3 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.list .date-range-sheet-time-item > .item-content {
|
||||
padding-left: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler" class="date-time-selection-sheet" style="height:auto"
|
||||
:opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-toolbar>
|
||||
<div class="swipe-handler"></div>
|
||||
<div class="left">
|
||||
<f7-link :text="$t('Current Time')" @click="setCurrentTime"></f7-link>
|
||||
</div>
|
||||
<div class="right">
|
||||
<f7-link :text="$t('Done')" @click="confirm"></f7-link>
|
||||
</div>
|
||||
</f7-toolbar>
|
||||
<f7-page-content>
|
||||
<VueDatePicker inline enable-seconds
|
||||
auto-apply month-name-format="long"
|
||||
class="justify-content-center"
|
||||
:dark="isDarkMode"
|
||||
:week-start="firstDayOfWeek"
|
||||
:year-range="yearRange"
|
||||
:day-names="dayNames"
|
||||
:is24="is24Hour"
|
||||
v-model="dateTime">
|
||||
<template #month="{ text }">
|
||||
{{ $t(`datetime.${text}.short`) }}
|
||||
</template>
|
||||
<template #month-overlay-value="{ text }">
|
||||
{{ $t(`datetime.${text}.short`) }}
|
||||
</template>
|
||||
</VueDatePicker>
|
||||
</f7-page-content>
|
||||
</f7-sheet>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'modelValue',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show'
|
||||
],
|
||||
data() {
|
||||
const self = this;
|
||||
let value = self.$utilities.getCurrentUnixTime();
|
||||
|
||||
if (self.modelValue) {
|
||||
value = self.modelValue;
|
||||
}
|
||||
|
||||
return {
|
||||
yearRange: [
|
||||
2000,
|
||||
this.$utilities.getYear(this.$utilities.getCurrentDateTime()) + 1
|
||||
],
|
||||
dateTime: this.$utilities.getLocalDatetimeFromUnixTime(value),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
isDarkMode() {
|
||||
return this.$root.isDarkMode;
|
||||
},
|
||||
firstDayOfWeek() {
|
||||
return this.$store.getters.currentUserFirstDayOfWeek;
|
||||
},
|
||||
dayNames() {
|
||||
return this.$locale.getAllMinWeekdayNames();
|
||||
},
|
||||
is24Hour() {
|
||||
const datetimeFormat = this.$t('format.datetime.long');
|
||||
return this.$utilities.is24HourFormat(datetimeFormat);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSheetOpen() {
|
||||
if (this.modelValue) {
|
||||
this.dateTime = this.$utilities.getLocalDatetimeFromUnixTime(this.modelValue)
|
||||
}
|
||||
},
|
||||
onSheetClosed() {
|
||||
this.$emit('update:show', false);
|
||||
},
|
||||
setCurrentTime() {
|
||||
this.dateTime = this.$utilities.getLocalDatetimeFromUnixTime(this.$utilities.getCurrentUnixTime())
|
||||
},
|
||||
confirm() {
|
||||
if (!this.dateTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
const unixTime = this.$utilities.getUnixTime(this.dateTime);
|
||||
|
||||
if (unixTime < 0) {
|
||||
this.$toast('Date is too early');
|
||||
return;
|
||||
}
|
||||
|
||||
this.$emit('update:modelValue', unixTime);
|
||||
this.$emit('update:show', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.date-time-selection-sheet .dp__menu {
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,27 +1,27 @@
|
||||
<template>
|
||||
<f7-sheet :class="{ 'icon-selection-huge-sheet': hugeIconRows }" :opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler"
|
||||
:class="heightClass" :opened="show"
|
||||
@sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-toolbar>
|
||||
<div class="swipe-handler"></div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<f7-link sheet-close :text="$t('Done')"></f7-link>
|
||||
</div>
|
||||
</f7-toolbar>
|
||||
<f7-page-content>
|
||||
<f7-block class="margin-vertical">
|
||||
<f7-row class="padding-vertical-half padding-horizontal-half"
|
||||
:class="{ 'row-has-selected-item': hasSelectedIcon(row) }"
|
||||
v-for="(row, idx) in allIconRows" :key="idx">
|
||||
<f7-col class="text-align-center" v-for="iconInfo in row" :key="iconInfo.id">
|
||||
<f7-icon :icon="iconInfo.icon"
|
||||
:style="color | iconStyle('default', 'var(--default-icon-color)')"
|
||||
@click.native="onIconClicked(iconInfo)">
|
||||
<f7-block class="margin-vertical no-padding">
|
||||
<div class="grid grid-cols-7 padding-vertical-half padding-horizontal-half"
|
||||
:class="{ 'row-has-selected-item': hasSelectedIcon(row) }"
|
||||
:key="idx" v-for="(row, idx) in allIconRows">
|
||||
<div class="text-align-center" :key="iconInfo.id" v-for="iconInfo in row">
|
||||
<ItemIcon icon-type="fixed" :icon-id="iconInfo.icon" :color="color" @click="onIconClicked(iconInfo)">
|
||||
<f7-badge color="default" class="right-bottom-icon" v-if="currentValue && currentValue === iconInfo.id">
|
||||
<f7-icon f7="checkmark_alt"></f7-icon>
|
||||
</f7-badge>
|
||||
</f7-icon>
|
||||
</f7-col>
|
||||
<f7-col v-for="idx in (itemPerRow - row.length)" :key="idx"></f7-col>
|
||||
</f7-row>
|
||||
</ItemIcon>
|
||||
</div>
|
||||
</div>
|
||||
</f7-block>
|
||||
</f7-page-content>
|
||||
</f7-sheet>
|
||||
@@ -30,17 +30,21 @@
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'value',
|
||||
'modelValue',
|
||||
'color',
|
||||
'columnCount',
|
||||
'show',
|
||||
'allIconInfos'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show'
|
||||
],
|
||||
data() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
currentValue: self.value,
|
||||
currentValue: self.modelValue,
|
||||
itemPerRow: self.columnCount || 7
|
||||
}
|
||||
},
|
||||
@@ -71,18 +75,24 @@ export default {
|
||||
|
||||
return ret;
|
||||
},
|
||||
hugeIconRows() {
|
||||
return this.allIconRows.length > 10;
|
||||
heightClass() {
|
||||
if (this.allIconRows.length > 10) {
|
||||
return 'icon-selection-huge-sheet';
|
||||
} else if (this.allIconRows.length > 6) {
|
||||
return 'icon-selection-large-sheet';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onIconClicked(iconInfo) {
|
||||
this.currentValue = iconInfo.id;
|
||||
this.$emit('input', this.currentValue);
|
||||
this.$emit('update:modelValue', this.currentValue);
|
||||
this.$emit('update:show', false);
|
||||
},
|
||||
onSheetOpen(event) {
|
||||
this.currentValue = this.value;
|
||||
this.currentValue = this.modelValue;
|
||||
this.scrollToSelectedItem(event.$el);
|
||||
},
|
||||
onSheetClosed() {
|
||||
@@ -128,6 +138,10 @@ export default {
|
||||
|
||||
<style>
|
||||
@media (min-height: 630px) {
|
||||
.icon-selection-large-sheet {
|
||||
height: 310px;
|
||||
}
|
||||
|
||||
.icon-selection-huge-sheet {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,21 @@
|
||||
<template>
|
||||
<f7-sheet style="height:auto" :opened="show" @sheet:closed="onSheetClosed">
|
||||
<f7-page-content>
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler" style="height:auto"
|
||||
:opened="show" @sheet:closed="onSheetClosed">
|
||||
<div class="swipe-handler"></div>
|
||||
<f7-page-content class="margin-top no-padding-top">
|
||||
<div class="display-flex padding justify-content-space-between align-items-center">
|
||||
<div style="font-size: 18px" v-if="title"><b>{{ title }}</b></div>
|
||||
</div>
|
||||
<div class="padding-horizontal padding-bottom">
|
||||
<p class="no-margin-top margin-bottom-half" v-if="hint">
|
||||
<span>{{ hint }}</span>
|
||||
<f7-link class="icon-after-text"
|
||||
<f7-link id="copy-to-clipboard-icon" ref="copyToClipboardIcon"
|
||||
class="icon-after-text"
|
||||
icon-only icon-f7="doc_on_doc" icon-size="16px"
|
||||
v-if="enableCopy"
|
||||
v-clipboard:copy="information" v-clipboard:success="onCopied"></f7-link>
|
||||
></f7-link>
|
||||
</p>
|
||||
<textarea class="information-content full-line" :rows="rowCount" readonly="readonly" v-model="information"></textarea>
|
||||
<textarea class="information-content full-line" :rows="rowCount" :value="information"></textarea>
|
||||
<div class="margin-top text-align-center">
|
||||
<f7-link @click="cancel" :text="$t('Close')"></f7-link>
|
||||
</div>
|
||||
@@ -31,14 +34,53 @@ export default {
|
||||
'enableCopy',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:show',
|
||||
'info:copied'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
clipboardHolder: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.makeCopyToClipboardClickable();
|
||||
},
|
||||
updated() {
|
||||
this.makeCopyToClipboardClickable();
|
||||
},
|
||||
watch: {
|
||||
'information': function (newValue) {
|
||||
if (this.clipboardHolder) {
|
||||
this.$utilities.changeClipboardObjectText(this.clipboardHolder, newValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onSheetClosed() {
|
||||
this.$emit('update:show', false);
|
||||
},
|
||||
onCopied() {
|
||||
this.$emit('info:copied');
|
||||
this.close();
|
||||
},
|
||||
cancel() {
|
||||
this.close();
|
||||
},
|
||||
makeCopyToClipboardClickable() {
|
||||
const self = this;
|
||||
|
||||
if (self.clipboardHolder) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.$refs.copyToClipboardIcon) {
|
||||
self.clipboardHolder = self.$utilities.makeButtonCopyToClipboard({
|
||||
el: '#copy-to-clipboard-icon',
|
||||
text: self.information,
|
||||
successCallback: function () {
|
||||
self.$emit('info:copied');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.$emit('update:show', false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<f7-icon :f7="f7Icon" :icon="icon" :style="style">
|
||||
<slot></slot>
|
||||
</f7-icon>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'iconType',
|
||||
'iconId',
|
||||
'color',
|
||||
'defaultColor',
|
||||
'additionalColorAttr'
|
||||
],
|
||||
computed: {
|
||||
f7Icon() {
|
||||
if (this.iconType === 'fixed-f7') {
|
||||
return this.iconId;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
icon() {
|
||||
if (this.iconType === 'account') {
|
||||
return this.getAccountIcon(this.iconId);
|
||||
} else if (this.iconType === 'category') {
|
||||
return this.getCategoryIcon(this.iconId);
|
||||
} else if (this.iconType === 'fixed') {
|
||||
return this.iconId;
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
style() {
|
||||
let defaultColor = 'var(--default-icon-color)';
|
||||
|
||||
if (this.defaultColor) {
|
||||
defaultColor = this.defaultColor;
|
||||
}
|
||||
|
||||
if (this.iconType === 'account') {
|
||||
return this.getAccountIconStyle(this.color, defaultColor, this.additionalColorAttr);
|
||||
} else if (this.iconType === 'category') {
|
||||
return this.getCategoryIconStyle(this.color, defaultColor, this.additionalColorAttr);
|
||||
} else {
|
||||
return this.getDefaultIconStyle(this.color, defaultColor, this.additionalColorAttr);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getAccountIcon(iconId) {
|
||||
if (this.$utilities.isNumber(iconId)) {
|
||||
iconId = iconId.toString();
|
||||
}
|
||||
|
||||
if (!this.$constants.icons.allAccountIcons[iconId]) {
|
||||
return this.$constants.icons.defaultAccountIcon.icon;
|
||||
}
|
||||
|
||||
return this.$constants.icons.allAccountIcons[iconId].icon;
|
||||
},
|
||||
getCategoryIcon(iconId) {
|
||||
if (this.$utilities.isNumber(iconId)) {
|
||||
iconId = iconId.toString();
|
||||
}
|
||||
|
||||
if (!this.$constants.icons.allCategoryIcons[iconId]) {
|
||||
return this.$constants.icons.defaultCategoryIcon.icon;
|
||||
}
|
||||
|
||||
return this.$constants.icons.allCategoryIcons[iconId].icon;
|
||||
},
|
||||
getAccountIconStyle(color, defaultColor, additionalColorAttr) {
|
||||
if (color && color !== this.$constants.colors.defaultAccountColor) {
|
||||
color = '#' + color;
|
||||
} else {
|
||||
color = defaultColor;
|
||||
}
|
||||
|
||||
const ret = {
|
||||
color: color
|
||||
};
|
||||
|
||||
if (additionalColorAttr) {
|
||||
ret[additionalColorAttr] = color;
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
getCategoryIconStyle(color, defaultColor, additionalColorAttr) {
|
||||
if (color && color !== this.$constants.colors.defaultCategoryColor) {
|
||||
color = '#' + color;
|
||||
} else {
|
||||
color = defaultColor;
|
||||
}
|
||||
|
||||
const ret = {
|
||||
color: color
|
||||
};
|
||||
|
||||
if (additionalColorAttr) {
|
||||
ret[additionalColorAttr] = color;
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
getDefaultIconStyle(color, defaultColor, additionalColorAttr) {
|
||||
if (color && color !== this.$constants.colors.defaultColor) {
|
||||
color = '#' + color;
|
||||
} else {
|
||||
color = defaultColor;
|
||||
}
|
||||
|
||||
const ret = {
|
||||
color: color
|
||||
};
|
||||
|
||||
if (additionalColorAttr) {
|
||||
ret[additionalColorAttr] = color;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -1,25 +1,29 @@
|
||||
<template>
|
||||
<f7-sheet :class="{ 'list-item-selection-huge-sheet': hugeListItemRows }" :opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler"
|
||||
:class="{ 'list-item-selection-huge-sheet': hugeListItemRows }" :opened="show"
|
||||
@sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-toolbar>
|
||||
<div class="swipe-handler"></div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<f7-link sheet-close :text="$t('Done')"></f7-link>
|
||||
</div>
|
||||
</f7-toolbar>
|
||||
<f7-page-content>
|
||||
<f7-list no-hairlines class="no-margin-top no-margin-bottom">
|
||||
<f7-list dividers no-hairlines class="no-margin-vertical">
|
||||
<f7-list-item link="#" no-chevron
|
||||
v-for="(item, index) in items"
|
||||
:key="item | itemKeyValue(index, keyField, valueType)"
|
||||
:title="$tIf((titleField ? item[titleField] : item), titleI18n)"
|
||||
:value="getItemValue(item, index, valueField, valueType)"
|
||||
:class="{ 'list-item-selected': isSelected(item, index) }"
|
||||
:value="item | itemKeyValue(index, valueField, valueType)"
|
||||
:title="item | itemFieldContent(titleField, item, titleI18n)"
|
||||
:key="getItemValue(item, index, keyField, valueType)"
|
||||
v-for="(item, index) in items"
|
||||
@click="onItemClicked(item, index)">
|
||||
<f7-icon slot="media"
|
||||
:icon="item[iconField] | icon(iconType)"
|
||||
:style="item[colorField] | iconStyle(iconType, 'var(--default-icon-color)')"
|
||||
v-if="iconField"></f7-icon>
|
||||
<f7-icon slot="after" class="list-item-checked-icon" f7="checkmark_alt" v-if="isSelected(item, index)"></f7-icon>
|
||||
<template #content-start>
|
||||
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" :style="{ 'color': isSelected(item, index) ? '' : 'transparent' }"></f7-icon>
|
||||
</template>
|
||||
<template #media v-if="iconField">
|
||||
<ItemIcon :icon-type="iconType" :icon-id="item[iconField]" :color="item[colorField]"></ItemIcon>
|
||||
</template>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-page-content>
|
||||
@@ -29,7 +33,7 @@
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'value',
|
||||
'modelValue',
|
||||
'valueType', // item or index
|
||||
'keyField', // for value type == item
|
||||
'valueField', // for value type == item
|
||||
@@ -41,11 +45,15 @@ export default {
|
||||
'items',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show'
|
||||
],
|
||||
data() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
currentValue: self.value
|
||||
currentValue: self.modelValue
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -54,6 +62,15 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getItemValue(item, index, fieldName, valueType) {
|
||||
if (valueType === 'index') {
|
||||
return index;
|
||||
} else if (fieldName) {
|
||||
return item[fieldName];
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
},
|
||||
onItemClicked(item, index) {
|
||||
if (this.valueType === 'index') {
|
||||
this.currentValue = index;
|
||||
@@ -65,15 +82,15 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
this.$emit('input', this.currentValue);
|
||||
this.$emit('update:show', false);
|
||||
this.$emit('update:modelValue', this.currentValue);
|
||||
this.close();
|
||||
},
|
||||
onSheetOpen(event) {
|
||||
this.currentValue = this.value;
|
||||
this.currentValue = this.modelValue;
|
||||
this.scrollToSelectedItem(event.$el);
|
||||
},
|
||||
onSheetClosed() {
|
||||
this.$emit('update:show', false);
|
||||
this.close();
|
||||
},
|
||||
isSelected(item, index) {
|
||||
if (this.valueType === 'index') {
|
||||
@@ -106,17 +123,9 @@ export default {
|
||||
}
|
||||
|
||||
container.scrollTop(targetPos);
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
itemKeyValue(item, index, fieldName, valueType) {
|
||||
if (valueType === 'index') {
|
||||
return index;
|
||||
} else if (fieldName) {
|
||||
return item[fieldName];
|
||||
} else {
|
||||
return item;
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.$emit('update:show', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,55 @@
|
||||
<template>
|
||||
<f7-sheet class="numpad-sheet" :opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-page-content class="no-margin no-padding-top">
|
||||
<f7-row class="numpad-values">
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler" class="numpad-sheet" style="height: auto"
|
||||
:opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<div class="swipe-handler"></div>
|
||||
<f7-page-content class="margin-top no-padding-top">
|
||||
<div class="numpad-values">
|
||||
<span class="numpad-value" :style="{ fontSize: currentDisplayFontSize + 'px' }">{{ currentDisplay }}</span>
|
||||
</f7-row>
|
||||
<f7-row class="numpad-buttons">
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(7)">
|
||||
</div>
|
||||
<div class="numpad-buttons">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputNum(7)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">7</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(8)">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputNum(8)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">8</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(9)">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputNum(9)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">9</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('×')">
|
||||
<f7-button class="numpad-button numpad-button-function no-right-border" @mousedown="setSymbol('×')">
|
||||
<span class="numpad-button-text numpad-button-text-normal">×</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(4)">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputNum(4)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">4</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(5)">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputNum(5)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">5</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(6)">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputNum(6)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">6</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('−')">
|
||||
<f7-button class="numpad-button numpad-button-function no-right-border" @mousedown="setSymbol('−')">
|
||||
<span class="numpad-button-text numpad-button-text-normal">−</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(1)">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputNum(1)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">1</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(2)">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputNum(2)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">2</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(3)">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputNum(3)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">3</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-function no-right-border" @click="setSymbol('+')">
|
||||
<f7-button class="numpad-button numpad-button-function no-right-border" @mousedown="setSymbol('+')">
|
||||
<span class="numpad-button-text numpad-button-text-normal">+</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputDot()">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputDot()">
|
||||
<span class="numpad-button-text numpad-button-text-normal">.</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="inputNum(0)">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="inputNum(0)">
|
||||
<span class="numpad-button-text numpad-button-text-normal">0</span>
|
||||
</f7-button>
|
||||
<f7-button class="numpad-button numpad-button-num" @click="backspace" @taphold.native="clear()">
|
||||
<f7-button class="numpad-button numpad-button-num" @mousedown="backspace" @taphold="clear()">
|
||||
<span class="numpad-button-text numpad-button-text-normal">
|
||||
<f7-icon f7="delete_left"></f7-icon>
|
||||
</span>
|
||||
@@ -55,7 +57,7 @@
|
||||
<f7-button class="numpad-button numpad-button-confirm no-right-border no-bottom-border" fill @click="confirm()">
|
||||
<span :class="{ 'numpad-button-text': true, 'numpad-button-text-confirm': !currentSymbol }">{{ confirmText }}</span>
|
||||
</f7-button>
|
||||
</f7-row>
|
||||
</div>
|
||||
</f7-page-content>
|
||||
</f7-sheet>
|
||||
</template>
|
||||
@@ -63,18 +65,22 @@
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'value',
|
||||
'modelValue',
|
||||
'minValue',
|
||||
'maxValue',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show'
|
||||
],
|
||||
data() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
previousValue: '',
|
||||
currentSymbol: '',
|
||||
currentValue: self.getStringValue(self.value)
|
||||
currentValue: self.getStringValue(self.modelValue)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -103,7 +109,7 @@ export default {
|
||||
if (this.currentSymbol) {
|
||||
return '=';
|
||||
} else {
|
||||
return this.$i18n.t('OK');
|
||||
return this.$t('OK');
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -291,17 +297,20 @@ export default {
|
||||
} else {
|
||||
const value = this.$utilities.stringCurrencyToNumeric(this.currentValue);
|
||||
|
||||
this.$emit('input', value);
|
||||
this.$emit('update:show', false);
|
||||
this.$emit('update:modelValue', value);
|
||||
this.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.$emit('update:show', false);
|
||||
},
|
||||
onSheetOpen() {
|
||||
this.currentValue = this.getStringValue(this.value);
|
||||
this.currentValue = this.getStringValue(this.modelValue);
|
||||
},
|
||||
onSheetClosed() {
|
||||
this.$emit('update:show', false);
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -322,7 +331,6 @@ export default {
|
||||
padding-left: 16px;
|
||||
line-height: 1;
|
||||
height: 50px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
user-select: none;
|
||||
@@ -371,7 +379,7 @@ export default {
|
||||
color: var(--f7-color-black);
|
||||
}
|
||||
|
||||
.theme-dark .numpad-button-text-normal {
|
||||
.dark .numpad-button-text-normal {
|
||||
color: var(--f7-color-white);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
<template>
|
||||
<f7-sheet style="height:auto" :opened="show"
|
||||
@sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-page-content>
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler" style="height:auto"
|
||||
:opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<div class="swipe-handler"></div>
|
||||
<f7-page-content class="margin-top no-padding-top">
|
||||
<div class="display-flex padding justify-content-space-between align-items-center">
|
||||
<div style="font-size: 18px" v-if="title"><b>{{ title }}</b></div>
|
||||
</div>
|
||||
<div class="padding-horizontal padding-bottom">
|
||||
<p class="no-margin-top margin-bottom-half" v-if="hint">{{ hint }}</p>
|
||||
<p class="no-margin" v-if="hint">{{ hint }}</p>
|
||||
<slot></slot>
|
||||
<f7-list no-hairlines class="no-margin-top margin-bottom">
|
||||
<f7-list no-hairlines strong class="no-margin">
|
||||
<f7-list-input
|
||||
type="number"
|
||||
autocomplete="one-time-code"
|
||||
outline
|
||||
floating-label
|
||||
clear-button
|
||||
class="no-margin no-padding-bottom"
|
||||
:label="$t('Password')"
|
||||
:placeholder="$t('Passcode')"
|
||||
:value="currentPasscode"
|
||||
@input="currentPasscode = $event.target.value"
|
||||
@keyup.enter.native="confirm()"
|
||||
v-model:value="currentPasscode"
|
||||
@keyup.enter="confirm()"
|
||||
></f7-list-input>
|
||||
</f7-list>
|
||||
<f7-button large fill
|
||||
@@ -36,13 +39,18 @@
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'value',
|
||||
'modelValue',
|
||||
'title',
|
||||
'hint',
|
||||
'confirmDisabled',
|
||||
'cancelDisabled',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show',
|
||||
'passcode:confirm'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
currentPasscode: ''
|
||||
@@ -53,17 +61,20 @@ export default {
|
||||
this.currentPasscode = '';
|
||||
},
|
||||
onSheetClosed() {
|
||||
this.$emit('update:show', false);
|
||||
this.close();
|
||||
},
|
||||
confirm() {
|
||||
if (!this.currentPasscode || this.confirmDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$emit('input', this.currentPasscode);
|
||||
this.$emit('update:modelValue', this.currentPasscode);
|
||||
this.$emit('passcode:confirm', this.currentPasscode);
|
||||
},
|
||||
cancel() {
|
||||
this.close();
|
||||
},
|
||||
close() {
|
||||
this.$emit('update:show', false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,25 @@
|
||||
<template>
|
||||
<f7-sheet style="height:auto" :opened="show"
|
||||
@sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-page-content>
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler" style="height:auto"
|
||||
:opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<div class="swipe-handler"></div>
|
||||
<f7-page-content class="margin-top no-padding-top">
|
||||
<div class="display-flex padding justify-content-space-between align-items-center">
|
||||
<div style="font-size: 18px" v-if="title"><b>{{ title }}</b></div>
|
||||
</div>
|
||||
<div class="padding-horizontal padding-bottom">
|
||||
<p class="no-margin-top margin-bottom-half" v-if="hint">{{ hint }}</p>
|
||||
<f7-list no-hairlines class="no-margin-top margin-bottom">
|
||||
<p class="no-margin" v-if="hint">{{ hint }}</p>
|
||||
<f7-list no-hairlines strong class="no-margin">
|
||||
<f7-list-input
|
||||
type="password"
|
||||
autocomplete="current-password"
|
||||
outline
|
||||
floating-label
|
||||
clear-button
|
||||
class="no-margin no-padding-bottom"
|
||||
:label="$t('Password')"
|
||||
:placeholder="$t('Password')"
|
||||
:value="currentPassword"
|
||||
@input="currentPassword = $event.target.value"
|
||||
@keyup.enter.native="confirm()"
|
||||
v-model:value="currentPassword"
|
||||
@keyup.enter="confirm()"
|
||||
></f7-list-input>
|
||||
</f7-list>
|
||||
<f7-button large fill
|
||||
@@ -35,13 +38,18 @@
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'value',
|
||||
'modelValue',
|
||||
'title',
|
||||
'hint',
|
||||
'confirmDisabled',
|
||||
'cancelDisabled',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show',
|
||||
'password:confirm'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
currentPassword: ''
|
||||
@@ -52,17 +60,20 @@ export default {
|
||||
this.currentPassword = '';
|
||||
},
|
||||
onSheetClosed() {
|
||||
this.$emit('update:show', false);
|
||||
this.close();
|
||||
},
|
||||
confirm() {
|
||||
if (!this.currentPassword || this.confirmDisabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$emit('input', this.currentPassword);
|
||||
this.$emit('update:modelValue', this.currentPassword);
|
||||
this.$emit('password:confirm', this.currentPassword);
|
||||
},
|
||||
cancel() {
|
||||
this.close();
|
||||
},
|
||||
close() {
|
||||
this.$emit('update:show', false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,15 @@
|
||||
<circle class="pie-chart-background" cx="0" cy="0" :r="diameter"></circle>
|
||||
|
||||
<circle class="pie-chart-item"
|
||||
v-for="(item, idx) in validItems" :key="idx"
|
||||
fill="transparent"
|
||||
cx="0" cy="0"
|
||||
:r="diameter / 2"
|
||||
:stroke="item.color | defaultIconColor('var(--default-icon-color)')"
|
||||
:stroke="getColor(item.color)"
|
||||
:stroke-width="diameter"
|
||||
:stroke-dasharray="item | itemStrokeDash(circumference)"
|
||||
:stroke-dashoffset="item | itemDashOffset(validItems, circumference, itemCommonDashOffset)"
|
||||
:stroke-dasharray="getItemStrokeDash(item)"
|
||||
:stroke-dashoffset="getItemDashOffset(item, validItems, itemCommonDashOffset)"
|
||||
:key="idx"
|
||||
v-for="(item, idx) in validItems"
|
||||
@click="switchSelectedIndex(idx)">
|
||||
</circle>
|
||||
|
||||
@@ -48,8 +49,8 @@
|
||||
<span class="skeleton-text">Percent</span>
|
||||
</f7-chip>
|
||||
<f7-chip outline
|
||||
:text="(selectedItem.percent) | percent(2, '<0.01')"
|
||||
:style="(selectedItem ? selectedItem.color : '') | iconStyle('default', 'var(--default-icon-color)', '--f7-chip-outline-border-color')"
|
||||
:text="$utilities.formatPercent(selectedItem.percent, 2, '<0.01')"
|
||||
:style="getColorStyle(selectedItem ? selectedItem.color : '', '--f7-chip-outline-border-color')"
|
||||
v-else-if="!skeleton"></f7-chip>
|
||||
</p>
|
||||
<p v-else-if="!validItems || !validItems.length">
|
||||
@@ -59,7 +60,7 @@
|
||||
<span class="skeleton-text" v-if="skeleton">Name</span>
|
||||
<span v-else-if="!skeleton && selectedItem.name">{{ selectedItem.name }}</span>
|
||||
<span class="skeleton-text" v-if="skeleton">Value</span>
|
||||
<span v-else-if="!skeleton && showValue" :style="(selectedItem ? selectedItem.color : '') | iconStyle('default', 'var(--default-icon-color)')">{{ selectedItem.value | currency(selectedItem.currency || defaultCurrency) }}</span>
|
||||
<span v-else-if="!skeleton && showValue" :style="getColorStyle(selectedItem ? selectedItem.color : '')">{{ $locale.getDisplayCurrency(selectedItem.value, (selectedItem.currency || defaultCurrency)) }}</span>
|
||||
<f7-icon class="item-navigate-icon" f7="chevron_right" v-if="enableClickItem"></f7-icon>
|
||||
</f7-link>
|
||||
<f7-link :no-link-class="true" v-else-if="!validItems || !validItems.length">
|
||||
@@ -107,6 +108,9 @@ export default {
|
||||
'enableClickItem',
|
||||
'centerTextBackground',
|
||||
],
|
||||
emits: [
|
||||
'click'
|
||||
],
|
||||
data: function () {
|
||||
const diameter = 100;
|
||||
|
||||
@@ -195,8 +199,11 @@ export default {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'items': function () {
|
||||
this.selectedIndex = 0;
|
||||
'items': {
|
||||
handler() {
|
||||
this.selectedIndex = 0;
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -216,14 +223,32 @@ export default {
|
||||
if (this.enableClickItem) {
|
||||
this.$emit('click', item.sourceItem);
|
||||
}
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
itemStrokeDash(item, circumference) {
|
||||
const length = item.actualPercent * circumference;
|
||||
return `${length} ${circumference - length}`;
|
||||
},
|
||||
itemDashOffset(item, items, circumference, offset) {
|
||||
getColor: function (color) {
|
||||
if (color && color !== this.$constants.colors.defaultColor) {
|
||||
color = '#' + color;
|
||||
} else {
|
||||
color = 'var(--default-icon-color)';
|
||||
}
|
||||
|
||||
return color;
|
||||
},
|
||||
getColorStyle: function (color, additionalFieldName) {
|
||||
const ret = {
|
||||
color: this.getColor(color)
|
||||
};
|
||||
|
||||
if (additionalFieldName) {
|
||||
ret[additionalFieldName] = ret.color;
|
||||
}
|
||||
|
||||
return ret;
|
||||
},
|
||||
getItemStrokeDash(item) {
|
||||
const length = item.actualPercent * this.circumference;
|
||||
return `${length} ${this.circumference - length}`;
|
||||
},
|
||||
getItemDashOffset(item, items, offset) {
|
||||
let allPreviousPercent = 0;
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
@@ -237,17 +262,17 @@ export default {
|
||||
}
|
||||
|
||||
if (offset) {
|
||||
offset += circumference / 4;
|
||||
offset += this.circumference / 4;
|
||||
} else {
|
||||
offset = circumference / 4;
|
||||
offset = this.circumference / 4;
|
||||
}
|
||||
|
||||
if (allPreviousPercent <= 0) {
|
||||
return offset;
|
||||
}
|
||||
|
||||
const allPreviousLength = allPreviousPercent * circumference;
|
||||
return circumference - allPreviousLength + offset;
|
||||
const allPreviousLength = allPreviousPercent * this.circumference;
|
||||
return this.circumference - allPreviousLength + offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -314,7 +339,7 @@ export default {
|
||||
fill: #f0f0f0;
|
||||
}
|
||||
|
||||
.theme-dark .pie-chart-background {
|
||||
.dark .pie-chart-background {
|
||||
fill: #181818;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
<template>
|
||||
<div class="pin-code-input grid grid-gap" :class="'grid-cols-' + length">
|
||||
<div class="input input-outline input-with-value"
|
||||
:key="index" v-for="(code, index) in codes">
|
||||
<input min="0" maxlength="1" pattern="[0-9]*"
|
||||
:ref="`pin-code-input-${index}`"
|
||||
:value="codes[index].value"
|
||||
:type="codes[index].inputType"
|
||||
@keydown="onKeydown(index, $event)"
|
||||
@paste="onPaste(index, $event)"
|
||||
@change="onInput(index, $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'modelValue',
|
||||
'secure',
|
||||
'length'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'pincode:confirm'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
codes: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
finalPinCode() {
|
||||
let finalPinCode = '';
|
||||
|
||||
for (let i = 0; i < this.codes.length; i++) {
|
||||
if (this.codes[i].value) {
|
||||
finalPinCode += this.codes[i].value;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return finalPinCode;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'length': function (newValue) {
|
||||
this.init(newValue, this.modelValue);
|
||||
},
|
||||
'modelValue': function (newValue) {
|
||||
if (newValue === this.finalPinCode) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.init(this.length, newValue);
|
||||
},
|
||||
'codes': {
|
||||
handler() {
|
||||
this.$emit('update:modelValue', this.finalPinCode);
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.init(this.length, this.modelValue);
|
||||
},
|
||||
methods: {
|
||||
init(length, value) {
|
||||
this.codes.length = 0;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
const code = {
|
||||
value: '',
|
||||
inputType: 'tel',
|
||||
inputTimer: null
|
||||
};
|
||||
|
||||
if (value && value[i]) {
|
||||
code.value = value[i];
|
||||
|
||||
if (this.secure) {
|
||||
code.inputType = 'password';
|
||||
}
|
||||
}
|
||||
|
||||
this.codes.push(code);
|
||||
}
|
||||
},
|
||||
autoFillText(index, text) {
|
||||
let lastIndex = index;
|
||||
|
||||
for (let i = index, j = 0; i < this.codes.length && j < text.length; i++, j++) {
|
||||
if (text[j] < '0' || text[j] > '9') {
|
||||
this.codes[i].value = '';
|
||||
this.$forceUpdate();
|
||||
break;
|
||||
}
|
||||
|
||||
this.codes[i].value = text[j];
|
||||
this.setInputType(i);
|
||||
lastIndex = i;
|
||||
}
|
||||
|
||||
this.setFocus(lastIndex);
|
||||
|
||||
if (this.finalPinCode.length === this.length) {
|
||||
this.$emit('pincode:confirm', this.finalPinCode);
|
||||
}
|
||||
},
|
||||
setInputType(index) {
|
||||
const self = this;
|
||||
|
||||
if (!self.secure) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self.codes[index].value) {
|
||||
self.codes[index].inputType = 'tel';
|
||||
return;
|
||||
}
|
||||
|
||||
if (self.codes[index].inputTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.codes[index].inputTimer = setTimeout(() => {
|
||||
if (self.codes[index].value) {
|
||||
self.codes[index].inputType = 'password';
|
||||
} else {
|
||||
self.codes[index].inputType = 'tel';
|
||||
}
|
||||
|
||||
self.codes[index].inputTimer = null;
|
||||
}, 300);
|
||||
},
|
||||
setFocus(index) {
|
||||
const refId = `pin-code-input-${index}`;
|
||||
const ref = this.$refs[refId];
|
||||
|
||||
if (ref && ref[0]) {
|
||||
ref[0].focus();
|
||||
ref[0].select();
|
||||
}
|
||||
},
|
||||
setPreviousFocus(index) {
|
||||
if (index > 0) {
|
||||
this.setFocus(index - 1);
|
||||
}
|
||||
},
|
||||
setNextFocus(index) {
|
||||
if (index < this.length - 1) {
|
||||
this.setFocus(index + 1);
|
||||
}
|
||||
},
|
||||
onKeydown(index, event) {
|
||||
if (event.code === 'Enter' && this.finalPinCode.length === this.length) {
|
||||
this.$emit('pincode:confirm', this.finalPinCode);
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.code === 'ArrowLeft' || (event.shiftKey && event.code === 'Tab')) {
|
||||
this.setPreviousFocus(index);
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.code === 'ArrowRight' || (!event.shiftKey && event.code === 'Tab')) {
|
||||
this.setNextFocus(index);
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((event.ctrlKey || event.metaKey) && event.code === 'KeyV') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.code === 'Backspace' || event.code === 'Delete' || event.code === 'Del') {
|
||||
for (let i = index; i < this.codes.length; i++) {
|
||||
this.codes[i].value = '';
|
||||
this.setInputType(i);
|
||||
}
|
||||
|
||||
if (event.code === 'Backspace') {
|
||||
this.setPreviousFocus(index);
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.code.indexOf('Digit') === 0 && event.code.length === 6) {
|
||||
this.codes[index].value = event.key;
|
||||
this.setInputType(index);
|
||||
this.setNextFocus(index);
|
||||
|
||||
if (this.finalPinCode.length === this.length) {
|
||||
this.$emit('pincode:confirm', this.finalPinCode);
|
||||
}
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
},
|
||||
onPaste(index, event) {
|
||||
if (!event.clipboardData) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
const text = event.clipboardData.getData('Text');
|
||||
|
||||
if (!text) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
this.autoFillText(index, text);
|
||||
|
||||
event.preventDefault();
|
||||
},
|
||||
onInput(index, event) {
|
||||
if (!event.target.value) {
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
this.autoFillText(index, event.target.value);
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.pin-code-input input {
|
||||
text-align: center;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
height: 60px !important;
|
||||
}
|
||||
|
||||
.pin-code-input.grid.grid-gap {
|
||||
--f7-grid-gap: 4px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,15 +1,16 @@
|
||||
<template>
|
||||
<f7-sheet style="height:auto" :opened="show"
|
||||
@sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-page-content>
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler" style="height:auto"
|
||||
:opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<div class="swipe-handler"></div>
|
||||
<f7-page-content class="margin-top no-padding-top">
|
||||
<div class="display-flex padding justify-content-space-between align-items-center">
|
||||
<div style="font-size: 18px"><b>{{ title }}</b></div>
|
||||
</div>
|
||||
<div class="padding-horizontal padding-bottom">
|
||||
<p class="no-margin-top margin-bottom-half">{{ hint }}</p>
|
||||
<f7-list no-hairlines class="no-margin-top margin-bottom">
|
||||
<p class="no-margin">{{ hint }}</p>
|
||||
<f7-list no-hairlines class="no-margin">
|
||||
<f7-list-item class="list-item-pincode-input">
|
||||
<pincode-input secure :length="6" v-model="currentPinCode" />
|
||||
<pin-code-input :secure="true" :length="6" v-model="currentPinCode"/>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
<f7-button large fill
|
||||
@@ -28,13 +29,18 @@
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'value',
|
||||
'modelValue',
|
||||
'title',
|
||||
'hint',
|
||||
'confirmDisabled',
|
||||
'cancelDisabled',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show',
|
||||
'pincode:confirm'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
currentPinCode: ''
|
||||
@@ -57,7 +63,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$emit('input', this.currentPinCode);
|
||||
this.$emit('update:modelValue', this.currentPinCode);
|
||||
this.$emit('pincode:confirm', this.currentPinCode);
|
||||
},
|
||||
cancel() {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<f7-sheet :class="{ 'tag-selection-huge-sheet': hugeListItemRows }" :opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler"
|
||||
:opened="show" :class="{ 'tag-selection-huge-sheet': hugeListItemRows }"
|
||||
@sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-toolbar>
|
||||
<div class="swipe-handler"></div>
|
||||
<div class="left">
|
||||
<f7-link sheet-close :text="$t('Cancel')"></f7-link>
|
||||
</div>
|
||||
@@ -12,22 +15,25 @@
|
||||
<f7-list no-hairlines class="no-margin-top no-margin-bottom" v-if="!items || !items.length || noAvailableTag">
|
||||
<f7-list-item :title="$t('No available tag')"></f7-list-item>
|
||||
</f7-list>
|
||||
<f7-list no-hairlines class="no-margin-top no-margin-bottom" v-else-if="items && items.length && !noAvailableTag">
|
||||
<f7-list-item checkbox v-for="item in items"
|
||||
<f7-list dividers no-hairlines class="no-margin-top no-margin-bottom" v-else-if="items && items.length && !noAvailableTag">
|
||||
<f7-list-item checkbox
|
||||
v-show="!item.hidden"
|
||||
:key="item.id"
|
||||
:class="item.id | tagItemClass(selectedItemIds)"
|
||||
:class="isChecked(item.id) ? 'list-item-selected' : ''"
|
||||
:value="item.id"
|
||||
:checked="item.id | isChecked(selectedItemIds)"
|
||||
:checked="isChecked(item.id)"
|
||||
:key="item.id"
|
||||
v-for="item in items"
|
||||
@change="changeItemSelection">
|
||||
<f7-block slot="title" class="no-padding no-margin">
|
||||
<div class="display-flex">
|
||||
<f7-icon slot="media" f7="number"></f7-icon>
|
||||
<div class="tag-selection-list-item list-item-valign-middle padding-left-half">
|
||||
{{ item.name }}
|
||||
<template #title>
|
||||
<f7-block class="no-padding no-margin">
|
||||
<div class="display-flex">
|
||||
<f7-icon f7="number"></f7-icon>
|
||||
<div class="tag-selection-list-item list-item-valign-middle padding-left-half">
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</f7-block>
|
||||
</f7-block>
|
||||
</template>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</f7-page-content>
|
||||
@@ -37,15 +43,19 @@
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'value',
|
||||
'modelValue',
|
||||
'items',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show'
|
||||
],
|
||||
data() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
selectedItemIds: self.$utilities.copyArrayTo(self.value, [])
|
||||
selectedItemIds: self.$utilities.copyArrayTo(self.modelValue, [])
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -64,11 +74,11 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
save() {
|
||||
this.$emit('input', this.selectedItemIds);
|
||||
this.$emit('update:modelValue', this.selectedItemIds);
|
||||
this.$emit('update:show', false);
|
||||
},
|
||||
onSheetOpen(event) {
|
||||
this.selectedItemIds = this.$utilities.copyArrayTo(this.value, []);
|
||||
this.selectedItemIds = this.$utilities.copyArrayTo(this.modelValue, []);
|
||||
this.scrollToSelectedItem(event.$el);
|
||||
},
|
||||
onSheetClosed() {
|
||||
@@ -95,9 +105,6 @@ export default {
|
||||
}
|
||||
},
|
||||
scrollToSelectedItem(parent) {
|
||||
const app = this.$f7;
|
||||
const $$ = app.$;
|
||||
|
||||
if (!parent || !parent.length) {
|
||||
return;
|
||||
}
|
||||
@@ -113,8 +120,8 @@ export default {
|
||||
let lastSelectedItem = selectedItem;
|
||||
|
||||
if (selectedItem.length > 0) {
|
||||
firstSelectedItem = $$(selectedItem[0]);
|
||||
lastSelectedItem = $$(selectedItem[selectedItem.length - 1]);
|
||||
firstSelectedItem = this.$ui.elements(selectedItem[0]);
|
||||
lastSelectedItem = this.$ui.elements(selectedItem[selectedItem.length - 1]);
|
||||
}
|
||||
|
||||
let firstSelectedItemInTop = firstSelectedItem.offset().top - container.offset().top - parseInt(container.css('padding-top'), 10);
|
||||
@@ -133,26 +140,15 @@ export default {
|
||||
}
|
||||
|
||||
container.scrollTop(targetPos);
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
isChecked(itemId, selectedItemIds) {
|
||||
for (let i = 0; i < selectedItemIds.length; i++) {
|
||||
if (selectedItemIds[i] === itemId) {
|
||||
},
|
||||
isChecked(itemId) {
|
||||
for (let i = 0; i < this.selectedItemIds.length; i++) {
|
||||
if (this.selectedItemIds[i] === itemId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
tagItemClass(itemId, selectedItemIds) {
|
||||
for (let i = 0; i < selectedItemIds.length; i++) {
|
||||
if (selectedItemIds[i] === itemId) {
|
||||
return 'list-item-selected';
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,4 +166,3 @@ export default {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
</style>
|
||||
self
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<f7-sheet :class="{ 'tree-view-selection-huge-sheet': hugeTreeViewItems }" :opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler"
|
||||
:class="{ 'tree-view-selection-huge-sheet': hugeTreeViewItems }"
|
||||
:opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-toolbar>
|
||||
<div class="swipe-handler"></div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<f7-link sheet-close :text="$t('Done')"></f7-link>
|
||||
@@ -8,26 +11,26 @@
|
||||
</f7-toolbar>
|
||||
<f7-page-content>
|
||||
<f7-treeview>
|
||||
<f7-treeview-item v-for="item in items"
|
||||
item-toggle
|
||||
<f7-treeview-item item-toggle
|
||||
:opened="isPrimaryItemHasSecondaryValue(item)"
|
||||
:key="item | itemFieldContent(primaryKeyField, item, false)"
|
||||
:label="item | itemFieldContent(primaryTitleField, item, primaryTitleI18n)">
|
||||
<f7-icon slot="media"
|
||||
:icon="item[primaryIconField] | icon(primaryIconType)"
|
||||
:style="item[primaryColorField] | iconStyle(primaryIconType, 'var(--default-icon-color)')"
|
||||
v-if="primaryIconField"></f7-icon>
|
||||
:label="$tIf((primaryTitleField ? item[primaryTitleField] : item), primaryTitleI18n)"
|
||||
:key="primaryKeyField ? item[primaryKeyField] : item"
|
||||
v-for="item in items">
|
||||
<template #media>
|
||||
<ItemIcon :icon-type="primaryIconType" :icon-id="item[primaryIconField]"
|
||||
:color="item[primaryColorField]" v-if="primaryIconField"></ItemIcon>
|
||||
</template>
|
||||
|
||||
<f7-treeview-item v-for="subItem in item[primarySubItemsField]"
|
||||
selectable
|
||||
<f7-treeview-item selectable
|
||||
:selected="isSecondarySelected(subItem)"
|
||||
:key="subItem | itemFieldContent(secondaryKeyField, subItem, false)"
|
||||
:label="subItem | itemFieldContent(secondaryTitleField, subItem, secondaryTitleI18n)"
|
||||
:label="$tIf((secondaryTitleField ? subItem[secondaryTitleField] : subItem), secondaryTitleI18n)"
|
||||
:key="secondaryKeyField ? subItem[secondaryKeyField] : subItem"
|
||||
v-for="subItem in item[primarySubItemsField]"
|
||||
@click="onSecondaryItemClicked(subItem)">
|
||||
<f7-icon slot="media"
|
||||
:icon="subItem[secondaryIconField] | icon(secondaryIconType)"
|
||||
:style="subItem[secondaryColorField] | iconStyle(secondaryIconType, 'var(--default-icon-color)')"
|
||||
v-if="secondaryIconField"></f7-icon>
|
||||
<template #media>
|
||||
<ItemIcon :icon-type="secondaryIconType" :icon-id="subItem[secondaryIconField]"
|
||||
:color="subItem[secondaryColorField]" v-if="secondaryIconField"></ItemIcon>
|
||||
</template>
|
||||
</f7-treeview-item>
|
||||
</f7-treeview-item>
|
||||
</f7-treeview>
|
||||
@@ -38,7 +41,7 @@
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'value',
|
||||
'modelValue',
|
||||
'primaryKeyField',
|
||||
'primaryValueField',
|
||||
'primaryTitleField',
|
||||
@@ -57,11 +60,15 @@ export default {
|
||||
'items',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show'
|
||||
],
|
||||
data() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
currentValue: self.value
|
||||
currentValue: self.modelValue
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -85,7 +92,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
onSheetOpen(event) {
|
||||
this.currentValue = this.value;
|
||||
this.currentValue = this.modelValue;
|
||||
this.scrollToSelectedItem(event.$el);
|
||||
},
|
||||
onSheetClosed() {
|
||||
@@ -98,7 +105,7 @@ export default {
|
||||
this.currentValue = subItem;
|
||||
}
|
||||
|
||||
this.$emit('input', this.currentValue);
|
||||
this.$emit('update:modelValue', this.currentValue);
|
||||
this.$emit('update:show', false);
|
||||
},
|
||||
isPrimaryItemHasSecondaryValue(primaryItem) {
|
||||
|
||||
@@ -1,56 +1,60 @@
|
||||
<template>
|
||||
<f7-sheet style="height: auto" :opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-sheet swipe-to-close swipe-handler=".swipe-handler"
|
||||
style="height: auto" :opened="show" @sheet:open="onSheetOpen" @sheet:closed="onSheetClosed">
|
||||
<f7-toolbar>
|
||||
<div class="swipe-handler"></div>
|
||||
<div class="left"></div>
|
||||
<div class="right">
|
||||
<f7-link sheet-close :text="$t('Done')"></f7-link>
|
||||
</div>
|
||||
</f7-toolbar>
|
||||
<f7-page-content>
|
||||
<f7-row>
|
||||
<f7-col width="50">
|
||||
<div class="grid grid-cols-2 grid-gap">
|
||||
<div>
|
||||
<div class="primary-list-container">
|
||||
<f7-list no-hairlines class="primary-list no-margin-top no-margin-bottom">
|
||||
<f7-list dividers no-hairlines class="primary-list no-margin-vertical">
|
||||
<f7-list-item link="#" no-chevron
|
||||
v-for="item in items"
|
||||
:key="item | itemFieldContent(primaryKeyField, item, false)"
|
||||
:class="{ 'primary-list-item-selected': item === selectedPrimaryItem }"
|
||||
:value="item | itemFieldContent(primaryValueField, item, false)"
|
||||
:title="item | itemFieldContent(primaryTitleField, null, primaryTitleI18n)"
|
||||
:header="item | itemFieldContent(primaryHeaderField, null, primaryHeaderI18n)"
|
||||
:footer="item | itemFieldContent(primaryFooterField, null, primaryFooterI18n)"
|
||||
:value="primaryValueField ? item[primaryValueField] : item"
|
||||
:title="$tIf(item[primaryTitleField], primaryTitleI18n)"
|
||||
:header="$tIf(item[primaryHeaderField], primaryHeaderI18n)"
|
||||
:footer="$tIf(item[primaryFooterField], primaryFooterI18n)"
|
||||
:key="primaryKeyField ? item[primaryKeyField] : item"
|
||||
v-for="item in items"
|
||||
@click="onPrimaryItemClicked(item)">
|
||||
<f7-icon slot="media"
|
||||
:icon="item[primaryIconField] | icon(primaryIconType)"
|
||||
:style="item[primaryColorField] | iconStyle(primaryIconType, 'var(--default-icon-color)')"
|
||||
v-if="primaryIconField"></f7-icon>
|
||||
<f7-icon slot="after" class="list-item-showing" f7="chevron_right" v-if="item === selectedPrimaryItem"></f7-icon>
|
||||
<template #media>
|
||||
<ItemIcon :icon-type="primaryIconType" :icon-id="item[primaryIconField]" :color="item[primaryColorField]"></ItemIcon>
|
||||
</template>
|
||||
<template #after>
|
||||
<f7-icon class="list-item-showing" f7="chevron_right" v-if="item === selectedPrimaryItem"></f7-icon>
|
||||
</template>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</div>
|
||||
</f7-col>
|
||||
<f7-col width="50">
|
||||
</div>
|
||||
<div>
|
||||
<div class="secondary-list-container">
|
||||
<f7-list no-hairlines class="secondary-list no-margin-top no-margin-bottom" v-if="selectedPrimaryItem && primarySubItemsField && selectedPrimaryItem[primarySubItemsField]">
|
||||
<f7-list dividers no-hairlines class="secondary-list no-margin-vertical" v-if="selectedPrimaryItem && primarySubItemsField && selectedPrimaryItem[primarySubItemsField]">
|
||||
<f7-list-item link="#" no-chevron
|
||||
v-for="subItem in selectedPrimaryItem[primarySubItemsField]"
|
||||
:key="subItem | itemFieldContent(secondaryKeyField, subItem, false)"
|
||||
:class="{ 'secondary-list-item-selected': isSecondarySelected(subItem) }"
|
||||
:value="subItem | itemFieldContent(secondaryValueField, subItem, false)"
|
||||
:title="subItem | itemFieldContent(secondaryTitleField, null, secondaryTitleI18n)"
|
||||
:header="subItem | itemFieldContent(secondaryHeaderField, null, secondaryHeaderI18n)"
|
||||
:footer="subItem | itemFieldContent(secondaryFooterField, null, secondaryFooterI18n)"
|
||||
:value="secondaryValueField ? subItem[secondaryValueField] : subItem"
|
||||
:title="$tIf(subItem[secondaryTitleField], secondaryTitleI18n)"
|
||||
:header="$tIf(subItem[secondaryHeaderField], secondaryHeaderI18n)"
|
||||
:footer="$tIf(subItem[secondaryFooterField], secondaryFooterI18n)"
|
||||
:key="secondaryKeyField ? subItem[secondaryKeyField] : subItem"
|
||||
v-for="subItem in selectedPrimaryItem[primarySubItemsField]"
|
||||
@click="onSecondaryItemClicked(subItem)">
|
||||
<f7-icon slot="media"
|
||||
:icon="subItem[secondaryIconField] | icon(secondaryIconType)"
|
||||
:style="subItem[secondaryColorField] | iconStyle(secondaryIconType, 'var(--default-icon-color)')"
|
||||
v-if="secondaryIconField"></f7-icon>
|
||||
<f7-icon slot="after" class="list-item-checked-icon" f7="checkmark_alt" v-if="isSecondarySelected(subItem)"></f7-icon>
|
||||
<template #media>
|
||||
<ItemIcon :icon-type="secondaryIconType" :icon-id="subItem[secondaryIconField]" :color="subItem[secondaryColorField]"></ItemIcon>
|
||||
</template>
|
||||
<template #after>
|
||||
<f7-icon class="list-item-checked-icon" f7="checkmark_alt" v-if="isSecondarySelected(subItem)"></f7-icon>
|
||||
</template>
|
||||
</f7-list-item>
|
||||
</f7-list>
|
||||
</div>
|
||||
</f7-col>
|
||||
</f7-row>
|
||||
</div>
|
||||
</div>
|
||||
</f7-page-content>
|
||||
</f7-sheet>
|
||||
</template>
|
||||
@@ -58,7 +62,7 @@
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'value',
|
||||
'modelValue',
|
||||
'primaryKeyField',
|
||||
'primaryValueField',
|
||||
'primaryTitleField',
|
||||
@@ -85,12 +89,16 @@ export default {
|
||||
'items',
|
||||
'show'
|
||||
],
|
||||
emits: [
|
||||
'update:modelValue',
|
||||
'update:show'
|
||||
],
|
||||
data() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
currentPrimaryValue: self.getPrimaryValueBySecondaryValue(self.value),
|
||||
currentSecondaryValue: self.value
|
||||
currentPrimaryValue: self.getPrimaryValueBySecondaryValue(self.modelValue),
|
||||
currentSecondaryValue: self.modelValue
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -126,13 +134,13 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
onSheetOpen(event) {
|
||||
this.currentPrimaryValue = this.getPrimaryValueBySecondaryValue(this.value);
|
||||
this.currentSecondaryValue = this.value;
|
||||
this.currentPrimaryValue = this.getPrimaryValueBySecondaryValue(this.modelValue);
|
||||
this.currentSecondaryValue = this.modelValue;
|
||||
this.scrollToSelectedItem(event.$el, '.primary-list-container', 'li.primary-list-item-selected');
|
||||
this.scrollToSelectedItem(event.$el, '.secondary-list-container', 'li.secondary-list-item-selected');
|
||||
},
|
||||
onSheetClosed() {
|
||||
this.$emit('update:show', false);
|
||||
this.close();
|
||||
},
|
||||
onPrimaryItemClicked(item) {
|
||||
if (this.primaryValueField) {
|
||||
@@ -148,8 +156,8 @@ export default {
|
||||
this.currentSecondaryValue = subItem;
|
||||
}
|
||||
|
||||
this.$emit('input', this.currentSecondaryValue);
|
||||
this.$emit('update:show', false);
|
||||
this.$emit('update:modelValue', this.currentSecondaryValue);
|
||||
this.close();
|
||||
},
|
||||
isSecondarySelected(subItem) {
|
||||
if (this.secondaryValueField) {
|
||||
@@ -226,6 +234,9 @@ export default {
|
||||
}
|
||||
|
||||
container.scrollTop(targetPos);
|
||||
},
|
||||
close() {
|
||||
this.$emit('update:show', false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user