mirror of
https://github.com/tenrok/vue-cron-editor-bootstrap.git
synced 2026-06-20 20:10:34 +03:00
refactoring
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
interface MinutesTabUpdatedEvent {
|
||||
type: 'minutes'
|
||||
minuteInterval: number
|
||||
}
|
||||
|
||||
interface HourlyTabUpdatedEvent {
|
||||
type: 'hourly'
|
||||
minutes: number
|
||||
hourInterval: number
|
||||
}
|
||||
|
||||
interface DailyTabUpdatedEvent {
|
||||
type: 'daily'
|
||||
minutes: number
|
||||
hours: number
|
||||
dayInterval: number
|
||||
}
|
||||
|
||||
interface WeeklyTabUpdatedEvent {
|
||||
type: 'weekly'
|
||||
minutes: number
|
||||
hours: number
|
||||
days: string[]
|
||||
}
|
||||
|
||||
interface MonthlyTabUpdatedEvent {
|
||||
type: 'monthly'
|
||||
minutes: number
|
||||
hours: number
|
||||
day: number
|
||||
monthInterval: number
|
||||
}
|
||||
|
||||
interface AdvancedTabUpdatedEvent {
|
||||
type: 'advanced'
|
||||
cronExpression: string
|
||||
}
|
||||
|
||||
export type TabUpdatedEvent =
|
||||
| MinutesTabUpdatedEvent
|
||||
| HourlyTabUpdatedEvent
|
||||
| DailyTabUpdatedEvent
|
||||
| WeeklyTabUpdatedEvent
|
||||
| MonthlyTabUpdatedEvent
|
||||
| AdvancedTabUpdatedEvent
|
||||
|
||||
export type TabKey = TabUpdatedEvent[keyof TabUpdatedEvent]
|
||||
|
||||
export const buildExpression = (event: TabUpdatedEvent): string => {
|
||||
if (event.type === 'minutes') {
|
||||
return `*/${event.minuteInterval} * * * *`
|
||||
}
|
||||
|
||||
if (event.type === 'hourly') {
|
||||
return `${event.minutes} */${event.hourInterval} * * *`
|
||||
}
|
||||
|
||||
if (event.type === 'daily') {
|
||||
return `${event.minutes} ${event.hours} */${event.dayInterval} * *`
|
||||
}
|
||||
|
||||
if (event.type === 'weekly') {
|
||||
if ([0, 7].includes(event.days.length)) {
|
||||
return `${event.minutes} ${event.hours} * * *`
|
||||
} else {
|
||||
return (
|
||||
`${event.minutes} ${event.hours} * * ` +
|
||||
`${event.days
|
||||
.filter(d => d)
|
||||
.sort()
|
||||
.join()}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (event.type === 'monthly') {
|
||||
return `${event.minutes} ${event.hours} ${event.day} */${event.monthInterval} *`
|
||||
}
|
||||
|
||||
if (event.type === 'advanced') {
|
||||
return event.cronExpression
|
||||
}
|
||||
|
||||
throw `unknown event type: ${event}`
|
||||
}
|
||||
|
||||
export const parseExpression = (expression: string): TabUpdatedEvent => {
|
||||
let groups = null
|
||||
|
||||
if (expression!.split(' ').length != 5) {
|
||||
return {
|
||||
type: 'advanced',
|
||||
cronExpression: expression,
|
||||
}
|
||||
}
|
||||
|
||||
if ((groups = expression.match(/^\*\/(\d+) \* \* \* \*$/))) {
|
||||
return {
|
||||
type: 'minutes',
|
||||
minuteInterval: Number(groups[1]),
|
||||
}
|
||||
}
|
||||
|
||||
if ((groups = expression.match(/^(\d+) \*\/(\d+) \* \* \*$/))) {
|
||||
return {
|
||||
type: 'hourly',
|
||||
minutes: Number(groups[1]),
|
||||
hourInterval: Number(groups[2]),
|
||||
}
|
||||
}
|
||||
|
||||
if ((groups = expression.match(/^(\d+) (\d+) \*\/(\d+) \* \*$/))) {
|
||||
return {
|
||||
type: 'daily',
|
||||
minutes: Number(groups[1]),
|
||||
hours: Number(groups[2]),
|
||||
dayInterval: Number(groups[3]),
|
||||
}
|
||||
}
|
||||
|
||||
if ((groups = expression.match(/^(\d+) (\d+) \* \* (\d)(,\d)?(,\d)?(,\d)?(,\d)?(,\d)?(,\d)?$/))) {
|
||||
const optionalDaysBeginIndex = 4
|
||||
const matchesEndIndex = 10
|
||||
return {
|
||||
type: 'weekly',
|
||||
minutes: Number(groups[1]),
|
||||
hours: Number(groups[2]),
|
||||
days: [groups[3]].concat(
|
||||
groups
|
||||
.slice(optionalDaysBeginIndex, matchesEndIndex)
|
||||
.map(d => d && d.replace(/,/, ''))
|
||||
.filter(d => d)
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
if ((groups = expression.match(/^(\d+) (\d+) (\d+) \*\/(\d+) \*$/))) {
|
||||
return {
|
||||
type: 'monthly',
|
||||
minutes: Number(groups[1]),
|
||||
hours: Number(groups[2]),
|
||||
day: Number(groups[3]),
|
||||
monthInterval: Number(groups[4]),
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'advanced',
|
||||
cronExpression: expression,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
export const defaultLocales: Record<string, Record<string, string>> = {
|
||||
en: {
|
||||
every: 'Every',
|
||||
mminutes: 'minute(s)',
|
||||
hoursOnMinute: 'hour(s) on minute',
|
||||
daysAt: 'day(s) at',
|
||||
at: 'at',
|
||||
onThe: 'On the',
|
||||
dayOfEvery: 'day, of every',
|
||||
monthsAt: 'month(s), at',
|
||||
// everyDay: 'Every',
|
||||
mon: 'Mon',
|
||||
tue: 'Tue',
|
||||
wed: 'Wed',
|
||||
thu: 'Thu',
|
||||
fri: 'Fri',
|
||||
sat: 'Sat',
|
||||
sun: 'Sun',
|
||||
// hasToBeBetween: 'Has to be between',
|
||||
// and: 'and',
|
||||
minutes: 'MINUTES',
|
||||
hourly: 'HOURLY',
|
||||
daily: 'DAILY',
|
||||
weekly: 'WEEKLY',
|
||||
monthly: 'MONTHLY',
|
||||
advanced: 'ADVANCED',
|
||||
cronExpression: 'cron expression:',
|
||||
onlyOn: 'Only on',
|
||||
},
|
||||
pl: {
|
||||
every: 'Co',
|
||||
mminutes: 'minut',
|
||||
hoursOnMinute: 'godzin w minucie',
|
||||
daysAt: 'dni o',
|
||||
at: 'o',
|
||||
onThe: '',
|
||||
dayOfEvery: 'dzień miesiąca, co',
|
||||
monthsAt: 'miesięcy, o godzinie',
|
||||
// everyDay: 'W każdy',
|
||||
mon: 'Pon',
|
||||
tue: 'Wt',
|
||||
wed: 'Śr',
|
||||
thu: 'Czw',
|
||||
fri: 'Pt',
|
||||
sat: 'So',
|
||||
sun: 'Nie',
|
||||
// hasToBeBetween: 'Wymagana wartość pomiędzy',
|
||||
// and: 'i',
|
||||
minutes: 'Minuty',
|
||||
hourly: 'Godziny',
|
||||
daily: 'Dni',
|
||||
weekly: 'Tygodnie',
|
||||
monthly: 'Miesiące',
|
||||
advanced: 'Zaawansowane',
|
||||
cronExpression: 'Wyrażenie cron:',
|
||||
onlyOn: 'Co',
|
||||
},
|
||||
}
|
||||
|
||||
export function createI18n(customLocales: Record<string, Record<string, string>>, locale: string): Record<string, string> {
|
||||
const allLocales = { ...defaultLocales, ...customLocales }
|
||||
return allLocales[locale]
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* vueCronEditorMixin
|
||||
* Core logic of a component.
|
||||
* Functionality dependent on UI frameworks should be implemented in derived components
|
||||
*/
|
||||
|
||||
import { buildExpression, parseExpression, TabUpdatedEvent, TabKey } from './cronExpressions'
|
||||
import * as cronValidator from 'cron-validator'
|
||||
import * as cronstrue from 'cronstrue/i18n'
|
||||
import { createI18n } from './i18n'
|
||||
|
||||
import Vue from 'vue'
|
||||
|
||||
const initialData: Record<TabKey, TabUpdatedEvent> = {
|
||||
minutes: {
|
||||
type: 'minutes',
|
||||
minuteInterval: 1,
|
||||
},
|
||||
hourly: {
|
||||
type: 'hourly',
|
||||
minutes: 0,
|
||||
hourInterval: 1,
|
||||
},
|
||||
daily: {
|
||||
type: 'daily',
|
||||
minutes: 0,
|
||||
hours: 0,
|
||||
dayInterval: 1,
|
||||
},
|
||||
weekly: {
|
||||
type: 'weekly',
|
||||
minutes: 0,
|
||||
hours: 0,
|
||||
days: ['1'],
|
||||
},
|
||||
monthly: {
|
||||
type: 'monthly',
|
||||
hours: 0,
|
||||
minutes: 0,
|
||||
day: 1,
|
||||
monthInterval: 1,
|
||||
},
|
||||
advanced: {
|
||||
type: 'advanced',
|
||||
cronExpression: '',
|
||||
},
|
||||
}
|
||||
|
||||
interface ComponentData {
|
||||
editorData: any
|
||||
currentTab: TabKey
|
||||
innerValue: string | null
|
||||
i18n: Record<string, string> | null
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
props: {
|
||||
value: { type: String, default: '*/1 * * * *' },
|
||||
isAdvancedTabVisible: { type: Boolean, default: true },
|
||||
preserveStateOnSwitchToAdvanced: { type: Boolean, default: false },
|
||||
locale: { type: String, default: 'en' },
|
||||
customLocales: { type: Object, default: null },
|
||||
},
|
||||
|
||||
data() {
|
||||
return <ComponentData>{
|
||||
innerValue: '*/1 * * * *',
|
||||
editorData: Object.assign({}, initialData.minutes),
|
||||
currentTab: 'minutes',
|
||||
i18n: null,
|
||||
}
|
||||
},
|
||||
|
||||
computed: {
|
||||
explanation(): string {
|
||||
if (!this.innerValue) {
|
||||
return ''
|
||||
}
|
||||
|
||||
return (cronstrue as any).toString(this.innerValue, {
|
||||
locale: this.locale,
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
watch: {
|
||||
value: {
|
||||
handler() {
|
||||
if (this.value == this.innerValue) {
|
||||
return
|
||||
}
|
||||
this.loadDataFromExpression()
|
||||
},
|
||||
},
|
||||
|
||||
editorData: {
|
||||
deep: true,
|
||||
handler(changedData) {
|
||||
this.updateCronExpression(changedData)
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.i18n = createI18n(this.customLocales, this.locale)
|
||||
this.innerValue = this.value
|
||||
this.loadDataFromExpression()
|
||||
},
|
||||
|
||||
methods: {
|
||||
translate(key: string) {
|
||||
return this.i18n![key]
|
||||
},
|
||||
|
||||
loadDataFromExpression() {
|
||||
const tabData = parseExpression(this.value)
|
||||
this.editorData = { ...tabData }
|
||||
this.currentTab = tabData.type
|
||||
},
|
||||
|
||||
updateCronExpression(event: TabUpdatedEvent) {
|
||||
const cronExpression = buildExpression({ ...event })
|
||||
|
||||
if (cronValidator.isValidCron(cronExpression)) {
|
||||
this.innerValue = cronExpression
|
||||
this.$emit('input', cronExpression)
|
||||
} else {
|
||||
this.innerValue = null
|
||||
this.$emit('input', null)
|
||||
}
|
||||
},
|
||||
|
||||
resetToTab(tabKey: TabKey) {
|
||||
this.currentTab = tabKey
|
||||
|
||||
if (this.preserveStateOnSwitchToAdvanced && tabKey === 'advanced') {
|
||||
this.editorData = {
|
||||
type: 'advanced',
|
||||
cronExpression: this.innerValue,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
const tabData = parseExpression(this.value)
|
||||
if (tabKey == tabData.type) {
|
||||
this.editorData = Object.assign({}, tabData)
|
||||
return
|
||||
}
|
||||
|
||||
this.editorData = Object.assign({}, initialData[tabKey])
|
||||
this.updateCronExpression(initialData[tabKey])
|
||||
},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user