2
0
mirror of https://github.com/tenrok/vue-cron-editor-bootstrap.git synced 2026-06-20 20:10:34 +03:00

rename package

This commit is contained in:
2022-11-09 19:49:47 +03:00
parent 42e11a5b93
commit c6417fea48
29 changed files with 12426 additions and 76071 deletions
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
presets: ['@vue/cli-plugin-babel/preset']
}
+1
View File
@@ -1,2 +1,3 @@
> 1% > 1%
last 2 versions last 2 versions
not dead
+19
View File
@@ -0,0 +1,19 @@
# EditorConfig is awesome: https://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
# Matches multiple files with brace expansion notation
# Set default charset
[*]
charset = utf-8
# Space indentation
[*]
indent_style = space
indent_size = 2
+2
View File
@@ -0,0 +1,2 @@
node_modules
/dist
+24 -24
View File
@@ -1,25 +1,25 @@
const isProd = process.env.NODE_ENV === 'production'
module.exports = { module.exports = {
root: true, root: true,
env: { env: {
node: true node: true,
}, },
extends: ["plugin:vue/essential", "@vue/prettier", "@vue/typescript"], parser: 'vue-eslint-parser',
rules: { parserOptions: {
"no-console": process.env.NODE_ENV === "production" ? "error" : "off", parser: '@typescript-eslint/parser',
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off" },
}, extends: [
parserOptions: { 'plugin:vue/recommended',
parser: "@typescript-eslint/parser" 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin
}, ],
overrides: [ rules: {
{ curly: 'warn',
files: [ 'no-console': isProd ? 'error' : 'off',
"**/__tests__/*.{j,t}s?(x)", 'no-debugger': isProd ? 'error' : 'off',
"**/tests/unit/**/*.spec.{j,t}s?(x)" 'vue/max-attributes-per-line': 'off',
], 'vue/singleline-html-element-content-newline': 'off',
env: { '@typescript-eslint/no-explicit-any': 'off',
jest: true '@typescript-eslint/no-non-null-assertion': 'off',
} },
} }
]
};
+6 -2
View File
@@ -1,5 +1,4 @@
.DS_Store .DS_Store
node_modules
# local env files # local env files
.env.local .env.local
@@ -18,4 +17,9 @@ yarn-error.log*
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
.vs/
# npm
node_modules
# Output directories
/dist
+8
View File
@@ -0,0 +1,8 @@
// https://prettier.io/docs/en/options.html
module.exports = {
arrowParens: 'avoid', // Include parentheses around a sole arrow function parameter
printWidth: 120, // Specify the line length that the printer will wrap on
semi: false, // Print semicolons at the ends of statements
singleQuote: true // Use single quotes instead of double quotes
}
-3
View File
@@ -1,3 +0,0 @@
{
"tabWidth": 4
}
-3
View File
@@ -1,3 +0,0 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"]
};
-17
View File
@@ -1,17 +0,0 @@
<meta charset="utf-8">
<title>vueCronEditorBootstrap demo</title>
<script src="https://unpkg.com/vue"></script>
<script src="./vueCronEditorBootstrap.umd.js"></script>
<div id="app">
<demo></demo>
</div>
<script>
new Vue({
components: {
demo: vueCronEditorBootstrap
}
}).$mount('#app')
</script>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-21376
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
-3
View File
@@ -1,3 +0,0 @@
module.exports = {
preset: "@vue/cli-plugin-unit-jest/presets/typescript-and-babel"
};
+11826 -32654
View File
File diff suppressed because it is too large Load Diff
+24 -29
View File
@@ -1,5 +1,5 @@
{ {
"name": "vue-cron-editor-bootstrap", "name": "@tenrok/vue-cron-editor-bootstrap",
"version": "0.2.1", "version": "0.2.1",
"private": false, "private": false,
"main": "dist/vueCronEditorBootstrap.umd.js", "main": "dist/vueCronEditorBootstrap.umd.js",
@@ -9,38 +9,33 @@
"./sfc": "src/VueCronEditorBootstrap.vue" "./sfc": "src/VueCronEditorBootstrap.vue"
}, },
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "build:npm": "vue-cli-service build --target lib --name vueCronEditorBootstrap src/VueCronEditorBootstrap.vue",
"build:npm": "vue-cli-service build --target lib --name vueCronEditorBootstrap src/VueCronEditorBootstrap.vue" "lint": "vue-cli-service lint --fix",
"serve": "vue-cli-service serve"
}, },
"dependencies": { "dependencies": {
"core-js": "^3.6.5", "core-js": "^3.26.0",
"cron-validator": "^1.1.1", "cron-validator": "^1.3.1",
"cronstrue": "^1.94.0", "cronstrue": "^2.14.0",
"vue": "^2.6.10" "vue": "^2.7.14"
}, },
"devDependencies": { "devDependencies": {
"@types/jest": "^24.0.19", "@typescript-eslint/eslint-plugin": "^5.42.1",
"@vue/cli-plugin-babel": "^4.3.1", "@typescript-eslint/parser": "^5.42.1",
"@vue/cli-plugin-eslint": "^4.3.1", "@vue/cli-plugin-babel": "^5.0.8",
"@vue/cli-plugin-typescript": "^4.3.1", "@vue/cli-plugin-eslint": "^5.0.8",
"@vue/cli-plugin-unit-jest": "^4.3.1", "@vue/cli-plugin-typescript": "^5.0.8",
"@vue/cli-service": "^4.3.1", "@vue/cli-service": "^5.0.8",
"@vue/eslint-config-prettier": "^5.0.0", "@vue/eslint-config-typescript": "^11.0.2",
"@vue/eslint-config-typescript": "^4.0.0", "eslint": "^7.32.0",
"@vue/test-utils": "1.0.0-beta.33", "eslint-plugin-prettier": "^4.2.1",
"eslint": "^5.16.0", "eslint-plugin-vue": "^9.6.0",
"eslint-plugin-prettier": "^3.1.3", "prettier": "^2.7.1",
"eslint-plugin-vue": "^5.0.0", "typescript": "^4.8.4",
"gh-pages": "^2.2.0", "vue-template-compiler": "^2.7.14"
"link-parent-bin": "^1.0.2", },
"lint-staged": "^10.2.4", "peerDependencies": {
"prettier": "^1.19.1", "bootstrap-vue": "^2.23.1"
"sass": "^1.46.0",
"sass-loader": "^8.0.2",
"standard-version": "^8.0.0",
"typescript": "~3.5.3",
"vue-template-compiler": "^2.6.10",
"bootstrap-vue": "^2.21.2"
}, },
"author": "alexmfreitas", "author": "alexmfreitas",
"license": "MIT", "license": "MIT",
+21 -23
View File
@@ -1,30 +1,28 @@
<template> <template>
<div id="app"> <div id="app">
<div class="flex-xl-nowrap"> <div class="p-3">
<main class="main-content py-3 ml-auto px-4" role="main"> <VueCronEditorBootstrap v-model="sample1CronExpression" preserve-state-on-switch-to-advanced />
<VueCronEditorBootstrap <b-form-input v-model="sample1CronExpression" readonly />
:preserveStateOnSwitchToAdvanced="true"
v-model="sample1CronExpression"
></VueCronEditorBootstrap>
<b-form-input v-model="sample1CronExpression" />
</main>
</div>
</div> </div>
</div>
</template> </template>
<script> <script>
import VueCronEditorBootstrap from "./VueCronEditorBootstrap.vue"; import VueCronEditorBootstrap from './VueCronEditorBootstrap.vue'
import { BFormInput } from "bootstrap-vue"; import { BFormInput } from 'bootstrap-vue'
import "bootstrap/dist/css/bootstrap.css"; import 'bootstrap/dist/css/bootstrap.css'
import "bootstrap-vue/dist/bootstrap-vue.css"; import 'bootstrap-vue/dist/bootstrap-vue.css'
export default { export default {
name: "App", name: 'App',
components: {
VueCronEditorBootstrap, components: {
BFormInput VueCronEditorBootstrap,
}, BFormInput,
data: () => ({ },
sample1CronExpression: "4 4 * * 0,2,3,5"
}) data: () => ({
}; sample1CronExpression: '4 4 * * 0,2,3,5',
}),
}
</script> </script>
+143 -196
View File
@@ -1,204 +1,151 @@
<template> <template>
<b-tabs v-model="activeTab" @input="reset" content-class="mt-3 mb-3"> <b-tabs v-model="activeTabIndex" content-class="p-2" @input="reset">
<b-tab :value="0" :title="_$t('minutes')" class="minutes-tab"> <b-tab :value="0" :title="translate('minutes')" class="minutes-tab">
<div class="row"> <b-row>
<div class="col d-flex" style="align-items: center;"> <b-col class="d-flex align-items-center">
<label class="me-2">{{ _$t("every") }}</label> <span class="mr-2">{{ translate('every') }}</span>
<b-form-input <b-form-input
type="number" v-model="editorData.minuteInterval"
v-model="editorData.minuteInterval" type="number"
v-bind:style="{ width: '80px' }" min="1"
/> max="59"
<label class="me-2 ms-2">{{ _$t("mminutes") }}</label> class="mr-2"
</div> style="width: 80px"
</div> />
</b-tab> <span>{{ translate('mminutes') }}</span>
<b-tab :value="1" :title="_$t('hourly')" class="hourly-tab"> </b-col>
<div class="row"> </b-row>
<div class="col d-flex" style="align-items: center;"> </b-tab>
<label class="me-2">{{ _$t("every") }}</label> <b-tab :value="1" :title="translate('hourly')" class="hourly-tab">
<b-form-input <b-row>
type="number" <b-col class="d-flex align-items-center">
v-model="editorData.hourInterval" <span class="mr-2">{{ translate('every') }}</span>
v-bind:style="{ width: '80px' }" <b-form-input
/> v-model="editorData.hourInterval"
<label class="me-2 ms-2">{{ type="number"
_$t("hoursOnMinute") min="1"
}}</label> max="24"
<b-form-input class="mr-2"
type="number" style="width: 80px"
max="59" />
min="0" <span class="mr-2">{{ translate('hoursOnMinute') }}</span>
v-model="editorData.minutes" <b-form-input v-model="editorData.minutes" type="number" min="0" max="59" style="width: 80px" />
v-bind:style="{ width: '80px' }" </b-col>
/> </b-row>
</div> </b-tab>
</div> <b-tab :value="2" :title="translate('daily')" class="daily-tab">
</b-tab> <b-row>
<b-tab :value="2" :title="_$t('daily')" class="daily-tab"> <b-col class="d-flex align-items-center">
<div class="row"> <span class="mr-2">{{ translate('every') }}</span>
<div class="col d-flex" style="align-items: center;"> <b-form-input v-model="editorData.dayInterval" type="number" class="mr-2" style="width: 80px" />
<label class="me-2">{{ _$t("every") }}</label> <span class="mr-2">{{ translate('daysAt') }}</span>
<b-form-input <b-form-timepicker :value="dateTime" :hour12="false" style="width: auto" @input="setDateTime" />
type="number" </b-col>
v-model="editorData.dayInterval" </b-row>
v-bind:style="{ width: '80px' }" </b-tab>
/> <b-tab :value="3" :title="translate('weekly')" class="weekly-tab">
<label class="me-2 ms-2">{{ <b-row>
_$t("daysAt") <b-col class="d-flex align-items-center">
}}</label> <span class="mr-2">{{ translate('every') }}</span>
<b-form-timepicker <b-form-checkbox v-model="editorData.days" value="0" class="mr-2">{{ translate('sun') }}</b-form-checkbox>
:value="dateTime" <b-form-checkbox v-model="editorData.days" value="1" class="mr-2">{{ translate('mon') }}</b-form-checkbox>
:hour12="false" <b-form-checkbox v-model="editorData.days" value="2" class="mr-2">{{ translate('tue') }}</b-form-checkbox>
@input="setDateTime" <b-form-checkbox v-model="editorData.days" value="3" class="mr-2">{{ translate('wed') }}</b-form-checkbox>
style="width: auto; display: flex;" <b-form-checkbox v-model="editorData.days" value="4" class="mr-2">{{ translate('thu') }}</b-form-checkbox>
/> <b-form-checkbox v-model="editorData.days" value="5" class="mr-2">{{ translate('fri') }}</b-form-checkbox>
</div> <b-form-checkbox v-model="editorData.days" value="6" class="mr-2">{{ translate('sat') }}</b-form-checkbox>
</div> <span class="mr-2">{{ translate('at') }}</span>
</b-tab> <b-form-timepicker :value="dateTime" :hour12="false" style="width: auto" @input="setDateTime" />
<b-tab :value="3" :title="_$t('weekly')" class="weekly-tab"> </b-col>
<div class="row"> </b-row>
<div class="col d-flex" style="align-items: center;"> </b-tab>
<label class="me-2">{{ _$t("every") }}</label> <b-tab :value="4" :title="translate('monthly')" class="monthly-tab">
<div class="form-check form-switch me-2"> <b-row>
<input :id="`toggle-editor-0`" type="checkbox" class="form-check-input" value="0" v-model="editorData.days"> <b-col class="d-flex align-items-center">
<label class="form-check-label" :for="`toggle-editor-0`">{{ _$t("sun") }}</label> <span class="mr-2">{{ translate('onThe') }}</span>
</div> <b-form-input v-model="editorData.day" type="number" class="mr-2" style="width: 80px" />
<div class="form-check form-switch me-2"> <span class="mr-2">{{ translate('dayOfEvery') }}</span>
<input :id="`toggle-editor-1`" type="checkbox" class="form-check-input" value="1" v-model="editorData.days"> <b-form-input v-model="editorData.monthInterval" type="number" class="mr-2" style="width: 80px" />
<label class="form-check-label" :for="`toggle-editor-1`">{{ _$t("mon") }}</label> <span class="mr-2">{{ translate('monthsAt') }}</span>
</div> <b-form-timepicker :value="dateTime" :hour12="false" style="width: auto" @input="setDateTime" />
<div class="form-check form-switch me-2"> </b-col>
<input :id="`toggle-editor-2`" type="checkbox" class="form-check-input" value="2" v-model="editorData.days"> </b-row>
<label class="form-check-label" :for="`toggle-editor-2`">{{ _$t("tue") }}</label> </b-tab>
</div> <b-tab :value="5" :title="translate('advanced')" class="advanced-tab">
<div class="form-check form-switch me-2"> <b-row>
<input :id="`toggle-editor-3`" type="checkbox" class="form-check-input" value="3" v-model="editorData.days"> <b-col class="d-flex" style="align-items: center">
<label class="form-check-label" :for="`toggle-editor-3`">{{ _$t("wed") }}</label> <span class="mr-2">{{ translate('cronExpression') }}</span>
</div> <b-form-input v-model="editorData.cronExpression" class="mr-2" style="width: auto" />
<div class="form-check form-switch me-2"> <span>{{ explanation }}</span>
<input :id="`toggle-editor-4`" type="checkbox" class="form-check-input" value="4" v-model="editorData.days"> </b-col>
<label class="form-check-label" :for="`toggle-editor-4`">{{ _$t("thu") }}</label> </b-row>
</div> </b-tab>
<div class="form-check form-switch me-2"> </b-tabs>
<input :id="`toggle-editor-5`" type="checkbox" class="form-check-input" value="5" v-model="editorData.days">
<label class="form-check-label" :for="`toggle-editor-5`">{{ _$t("fri") }}</label>
</div>
<div class="form-check form-switch me-2">
<input :id="`toggle-editor-6`" type="checkbox" class="form-check-input" value="6" v-model="editorData.days">
<label class="form-check-label" :for="`toggle-editor-6`">{{ _$t("sat") }}</label>
</div>
<label class="me-2">{{ _$t("at") }}</label>
<b-form-timepicker
:value="dateTime"
@input="setDateTime"
:hour12="false"
style="width: auto; display: flex;"
/>
</div>
</div>
</b-tab>
<b-tab :value="4" :title="_$t('monthly')" class="monthly-tab">
<div class="row">
<div class="col d-flex" style="align-items: center;">
<label class="me-2">{{ _$t("onThe") }}</label>
<b-form-input
type="number"
v-model="editorData.day"
v-bind:style="{ width: '80px' }"
/>
<label class="me-2 ms-2">{{
_$t("dayOfEvery")
}}</label>
<b-form-input
type="number"
v-model="editorData.monthInterval"
v-bind:style="{ width: '80px' }"
/><label class="me-2 ms-2">{{
_$t("monthsAt")
}}</label>
<b-form-timepicker
:value="dateTime"
@input="setDateTime"
:hour12="false"
style="width: auto; display: flex;"
/>
</div>
</div>
</b-tab>
<b-tab :value="4" :title="_$t('advanced')" class="advanced-tab">
<div class="row">
<div class="col d-flex" style="align-items: center;">
<label class="me-2">{{
_$t("cronExpression")
}}</label>
<b-form-input v-model="editorData.cronExpression" style="width:auto"/>
<label class="me-2 ms-2">
{{ explanation }}
</label>
</div>
</div>
</b-tab>
</b-tabs>
</template> </template>
<script> <script>
import vueCronEditorMixin from "./core/vueCronEditorMixin"; import vueCronEditorMixin from './core/vueCronEditorMixin'
import { import { BTabs, BTab, BRow, BCol, BFormCheckbox, BFormInput, BFormTimepicker } from 'bootstrap-vue'
BTabs,
BTab,
BFormInput,
BFormTimepicker,
} from "bootstrap-vue";
export default { export default {
name: "VueCronEditorBootstrap", name: 'VueCronEditorBootstrap',
mixins: [vueCronEditorMixin],
components: {
BFormInput,
BTabs,
BTab,
BFormTimepicker
},
data: () => ({
activeTab: null,
tabs: [
{ id: 0, key: "minutes" },
{ id: 1, key: "hourly" },
{ id: 2, key: "daily" },
{ id: 3, key: "weekly" },
{ id: 4, key: "monthly" },
{ id: 5, key: "advanced" }
]
}),
mounted() {
this.activeTab = this.tabs.find(t => t.key === this.currentTab).id;
},
watch: {
currentTab() {
this.activeTab = this.tabs.find(t => t.key === this.currentTab).id;
}
},
computed: {
dateTime() {
let dateTime = `${this.editorData.hours}:${this.editorData.minutes}:00`;
return dateTime;
}
},
methods: {
reset(e) {
const tabKey = this.tabs.find(t => t.id === e).key;
this._resetToTab(tabKey);
},
setDateTime(e) {
if (e == null) {
return;
}
const splittedTime = e.split(":");
this.editorData.hours = splittedTime[0]; components: {
this.editorData.minutes = splittedTime[1]; BTabs,
} BTab,
} BRow,
}; BCol,
BFormCheckbox,
BFormInput,
BFormTimepicker,
},
mixins: [vueCronEditorMixin],
data: () => ({
activeTabIndex: null,
tabs: [
{ idx: 0, key: 'minutes' },
{ idx: 1, key: 'hourly' },
{ idx: 2, key: 'daily' },
{ idx: 3, key: 'weekly' },
{ idx: 4, key: 'monthly' },
{ idx: 5, key: 'advanced' },
],
}),
computed: {
dateTime() {
return `${this.editorData.hours}:${this.editorData.minutes}:00`
},
},
watch: {
currentTab() {
this.activeTabIndex = this.tabs.find(t => t.key === this.currentTab).idx
},
},
created() {
this.activeTabIndex = this.tabs.find(t => t.key === this.currentTab).idx
},
methods: {
reset(tabIndex) {
const tab = this.tabs.find(t => t.idx === tabIndex)
if (tab) {
this.resetToTab(tab.key)
}
},
setDateTime(time) {
if (time == null) {
return
}
const splittedTime = time.split(':')
this.editorData.hours = splittedTime[0]
this.editorData.minutes = splittedTime[1]
},
},
}
</script> </script>
+125 -113
View File
@@ -1,135 +1,147 @@
interface MinutesTabUpdatedEvent { interface MinutesTabUpdatedEvent {
type: "minutes"; type: 'minutes'
minuteInterval: number; minuteInterval: number
} }
interface HourlyTabUpdatedEvent { interface HourlyTabUpdatedEvent {
type: "hourly"; type: 'hourly'
minutes: number; minutes: number
hourInterval: number; hourInterval: number
} }
interface DailyTabUpdatedEvent { interface DailyTabUpdatedEvent {
type: "daily"; type: 'daily'
minutes: number; minutes: number
hours: number; hours: number
dayInterval: number; dayInterval: number
} }
interface WeeklyTabUpdatedEvent { interface WeeklyTabUpdatedEvent {
type: "weekly"; type: 'weekly'
minutes: number; minutes: number
hours: number; hours: number
days: string[]; days: string[]
} }
interface MonthlyTabUpdatedEvent { interface MonthlyTabUpdatedEvent {
type: "monthly"; type: 'monthly'
minutes: number; minutes: number
hours: number; hours: number
day: number; day: number
monthInterval: number; monthInterval: number
} }
interface AdvancedTabUpdatedEvent { interface AdvancedTabUpdatedEvent {
type: "advanced"; type: 'advanced'
cronExpression: string; cronExpression: string
} }
export type TabUpdatedEvent = export type TabUpdatedEvent =
| MinutesTabUpdatedEvent | MinutesTabUpdatedEvent
| HourlyTabUpdatedEvent | HourlyTabUpdatedEvent
| DailyTabUpdatedEvent | DailyTabUpdatedEvent
| WeeklyTabUpdatedEvent | WeeklyTabUpdatedEvent
| MonthlyTabUpdatedEvent | MonthlyTabUpdatedEvent
| AdvancedTabUpdatedEvent; | AdvancedTabUpdatedEvent
export type TabKey = TabUpdatedEvent[keyof TabUpdatedEvent]; export type TabKey = TabUpdatedEvent[keyof TabUpdatedEvent]
export const buildExpression = (event: TabUpdatedEvent): string => { export const buildExpression = (event: TabUpdatedEvent): string => {
if (event.type === "minutes") { if (event.type === 'minutes') {
return `*/${event.minuteInterval} * * * *`; return `*/${event.minuteInterval} * * * *`
} }
if (event.type === "hourly") {
return `${event.minutes} */${event.hourInterval} * * *`; if (event.type === 'hourly') {
} return `${event.minutes} */${event.hourInterval} * * *`
if (event.type === "daily") { }
return `${event.minutes} ${event.hours} */${event.dayInterval} * *`;
} if (event.type === 'daily') {
if (event.type === "weekly") { return `${event.minutes} ${event.hours} */${event.dayInterval} * *`
return ( }
`${event.minutes} ${event.hours} * * ` +
`${event.days if (event.type === 'weekly') {
.filter(d => d) return (
.sort() `${event.minutes} ${event.hours} * * ` +
.join()}` `${event.days
); .filter(d => d)
} .sort()
if (event.type === "monthly") { .join()}`
return `${event.minutes} ${event.hours} ${event.day} */${event.monthInterval} *`; )
} }
if (event.type === "advanced") {
return event.cronExpression; if (event.type === 'monthly') {
} return `${event.minutes} ${event.hours} ${event.day} */${event.monthInterval} *`
throw `unknown event type: ${event}`; }
};
if (event.type === 'advanced') {
return event.cronExpression
}
throw `unknown event type: ${event}`
}
export const parseExpression = (expression: string): TabUpdatedEvent => { export const parseExpression = (expression: string): TabUpdatedEvent => {
let groups = null; let groups = null
if (expression.split(" ").length != 5) { 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 { return {
type: "advanced", type: 'advanced',
cronExpression: expression 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
}
}
+59 -59
View File
@@ -1,64 +1,64 @@
export const defaultLocales: Record<string, Record<string, string>> = { export const defaultLocales: Record<string, Record<string, string>> = {
en: { en: {
every: "Every", every: 'Every',
mminutes: "minute(s)", mminutes: 'minute(s)',
hoursOnMinute: "hour(s) on minute", hoursOnMinute: 'hour(s) on minute',
daysAt: "day(s) at", daysAt: 'day(s) at',
at: "at", at: 'at',
onThe: "On the", onThe: 'On the',
dayOfEvery: "day, of every", dayOfEvery: 'day, of every',
monthsAt: "month(s), at", monthsAt: 'month(s), at',
everyDay: "Every", everyDay: 'Every',
mon: "Mon", mon: 'Mon',
tue: "Tue", tue: 'Tue',
wed: "Wed", wed: 'Wed',
thu: "Thu", thu: 'Thu',
fri: "Fri", fri: 'Fri',
sat: "Sat", sat: 'Sat',
sun: "Sun", sun: 'Sun',
hasToBeBetween: "Has to be between", hasToBeBetween: 'Has to be between',
and: "and", and: 'and',
minutes: "MINUTES", minutes: 'MINUTES',
hourly: "HOURLY", hourly: 'HOURLY',
daily: "DAILY", daily: 'DAILY',
weekly: "WEEKLY", weekly: 'WEEKLY',
monthly: "MONTHLY", monthly: 'MONTHLY',
advanced: "ADVANCED", advanced: 'ADVANCED',
cronExpression: "cron expression:" cronExpression: 'cron expression:'
}, },
pl: { pl: {
every: "Co", every: 'Co',
mminutes: "minut", mminutes: 'minut',
hoursOnMinute: "godzin w minucie", hoursOnMinute: 'godzin w minucie',
daysAt: "dni o", daysAt: 'dni o',
at: "o", at: 'o',
onThe: "", onThe: '',
dayOfEvery: "dzień miesiąca, co", dayOfEvery: 'dzień miesiąca, co',
monthsAt: "miesięcy, o godzinie", monthsAt: 'miesięcy, o godzinie',
everyDay: "W każdy", everyDay: 'W każdy',
mon: "Pon", mon: 'Pon',
tue: "Wt", tue: 'Wt',
wed: "Śr", wed: 'Śr',
thu: "Czw", thu: 'Czw',
fri: "Pt", fri: 'Pt',
sat: "So", sat: 'So',
sun: "Nie", sun: 'Nie',
hasToBeBetween: "Wymagana wartość pomiędzy", hasToBeBetween: 'Wymagana wartość pomiędzy',
and: "i", and: 'i',
minutes: "Minuty", minutes: 'Minuty',
hourly: "Godziny", hourly: 'Godziny',
daily: "Dni", daily: 'Dni',
weekly: "Tygodnie", weekly: 'Tygodnie',
monthly: "Miesiące", monthly: 'Miesiące',
advanced: "Zaawansowane", advanced: 'Zaawansowane',
cronExpression: "Wyrażenie cron:" cronExpression: 'Wyrażenie cron:'
} }
}; }
export function createI18n( export function createI18n(
customLocales: Record<string, Record<string, string>>, customLocales: Record<string, Record<string, string>>,
locale: string locale: string
): Record<string, string> { ): Record<string, string> {
const allLocales = { ...defaultLocales, ...customLocales }; const allLocales = { ...defaultLocales, ...customLocales }
return allLocales[locale]; return allLocales[locale]
} }
+138 -130
View File
@@ -4,143 +4,151 @@
* Functionality dependent on UI frameworks should be implemented in derived components * Functionality dependent on UI frameworks should be implemented in derived components
*/ */
import { import { buildExpression, parseExpression, TabUpdatedEvent, TabKey } from './cronExpressions'
buildExpression, import * as cronValidator from 'cron-validator'
parseExpression, import * as cronstrue from 'cronstrue/i18n'
TabUpdatedEvent, import { createI18n } from './i18n'
TabKey
} from "./cronExpressions";
import * as cronValidator from "cron-validator";
import * as cronstrue from "cronstrue/i18n";
import { createI18n } from "./i18n";
import Vue from "vue"; import Vue from 'vue'
const initialData: Record<TabKey, TabUpdatedEvent> = { const initialData: Record<TabKey, TabUpdatedEvent> = {
minutes: { minutes: {
type: "minutes", type: 'minutes',
minuteInterval: 1 minuteInterval: 1
}, },
hourly: { hourly: {
type: "hourly", type: 'hourly',
minutes: 0, minutes: 0,
hourInterval: 1 hourInterval: 1
}, },
daily: { daily: {
type: "daily", type: 'daily',
minutes: 0, minutes: 0,
hours: 0, hours: 0,
dayInterval: 1 dayInterval: 1
}, },
weekly: { weekly: {
type: "weekly", type: 'weekly',
minutes: 0, minutes: 0,
hours: 0, hours: 0,
days: ["1"] days: ['1']
}, },
monthly: { monthly: {
type: "monthly", type: 'monthly',
hours: 0, hours: 0,
minutes: 0, minutes: 0,
day: 1, day: 1,
monthInterval: 1 monthInterval: 1
}, },
advanced: { advanced: {
type: "advanced", type: 'advanced',
cronExpression: "" cronExpression: ''
} }
}; }
interface ComponentData { interface ComponentData {
editorData: Object; editorData: any
currentTab: TabKey; currentTab: TabKey
innerValue: string | null; innerValue: string | null
i18n: Record<string, string> | null; i18n: Record<string, string> | null
} }
export default Vue.extend({ export default Vue.extend({
created() { props: {
this.i18n = createI18n(this.customLocales, this.locale); value: { type: String, default: '*/1 * * * *' },
this.innerValue = this.value; isAdvancedTabVisible: { type: Boolean, default: true },
this.__loadDataFromExpression(); preserveStateOnSwitchToAdvanced: { type: Boolean, default: false },
}, locale: { type: String, default: 'en' },
props: { customLocales: { type: Object, default: null }
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
});
}
},
methods: {
_$t(key: string) {
return this.i18n![key];
},
__loadDataFromExpression() {
const tabData = parseExpression(this.value);
this.$data.editorData = { ...tabData };
this.currentTab = tabData.type; data() {
}, return <ComponentData>{
__updateCronExpression(event: TabUpdatedEvent) { innerValue: '*/1 * * * *',
const cronExpression = buildExpression({ editorData: Object.assign({}, initialData.minutes),
...event currentTab: 'minutes',
}); i18n: null
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.$data.editorData = {
type: "advanced",
cronExpression: this.innerValue
};
return;
}
const tabData = parseExpression(this.value);
if (tabKey == tabData.type) return;
this.$data.editorData = Object.assign({}, initialData[tabKey]);
this.__updateCronExpression(initialData[tabKey]);
}
},
watch: {
value: {
handler() {
if (this.value == this.innerValue) {
return;
}
this.__loadDataFromExpression();
}
},
editorData: {
deep: true,
handler(changedData) {
this.__updateCronExpression(changedData);
}
}
} }
}); },
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])
}
}
})
+5 -5
View File
@@ -1,8 +1,8 @@
import Vue from "vue"; import Vue from 'vue'
import App from "./App.vue"; import App from './App.vue'
Vue.config.productionTip = false; Vue.config.productionTip = false
new Vue({ new Vue({
render: h => h(App) render: h => h(App)
}).$mount("#app"); }).$mount('#app')
+11 -9
View File
@@ -1,13 +1,15 @@
import Vue, { VNode } from "vue"; import Vue, { VNode } from 'vue'
declare global { declare global {
namespace JSX { namespace JSX {
// tslint:disable no-empty-interface // tslint:disable no-empty-interface
interface Element extends VNode {} type Element = VNode
// tslint:disable no-empty-interface
interface ElementClass extends Vue {} // tslint:disable no-empty-interface
interface IntrinsicElements { type ElementClass = Vue
[elem: string]: any;
} interface IntrinsicElements {
[elem: string]: any
} }
}
} }
+3 -3
View File
@@ -1,4 +1,4 @@
declare module "*.vue" { declare module '*.vue' {
import Vue from "vue"; import Vue from 'vue'
export default Vue; export default Vue
} }
+6 -24
View File
@@ -10,30 +10,12 @@
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"sourceMap": true, "sourceMap": true,
"baseUrl": ".", "baseUrl": ".",
"types": [ "types": ["webpack-env", "jest"],
"webpack-env",
"jest"
],
"paths": { "paths": {
"@/*": [ "@/*": ["src/*"]
"src/*"
]
}, },
"lib": [ "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
}, },
"include": [ "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "tests/**/*.ts", "tests/**/*.tsx"],
"src/**/*.ts", "exclude": ["node_modules"]
"src/**/*.tsx", }
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
+2 -2
View File
@@ -1,4 +1,4 @@
module.exports = { module.exports = {
publicPath: "/vue-cron-editor-bootstrap", publicPath: '/vue-cron-editor-bootstrap',
css: { extract: false } css: { extract: false },
}; };