From cbb35f73edbbba61d63b7676d722cf5ac85f21aa Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Sat, 9 May 2026 00:17:25 +0200 Subject: [PATCH] feat(frontend): jalali calendar + drop legacy moment-jalali MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Wire Calendar Type setting to a real Jalali datepicker via vue3-persian-datetime-picker, gated by useDatepicker composable - DateTimePicker wrapper swaps between AD-Vue and Persian picker; keeps dayjs v-model contract so existing forms/setters work unchanged - Theme picker popup explicitly per body.dark / data-theme=ultra-dark (AD-Vue 4 doesn't expose CSS vars, so var() fallbacks defaulted to white); fix invisible disabled days, SVG arrow fills, popup clipping via append-to="body" - Replace stray moment() calls in dbinbound/inbound models with dayjs; the legacy global was undefined under ESM and broke the inbounds list whenever any inbound had expiryTime > 0 - Remove legacy moment-jalali / persian-datepicker / aPersianDatepicker assets — replaced by the Vue 3 picker Note: dark/ultra background of the date popup still renders white in some cases — pending follow-up. Co-Authored-By: Claude Opus 4.7 --- frontend/package-lock.json | 122 +++++- frontend/package.json | 3 +- frontend/src/components/DateTimePicker.vue | 383 ++++++++++++++++++ frontend/src/composables/useDatepicker.js | 45 ++ frontend/src/models/dbinbound.js | 3 +- frontend/src/models/inbound.js | 3 +- .../src/pages/inbounds/ClientBulkModal.vue | 4 +- .../src/pages/inbounds/ClientFormModal.vue | 4 +- .../src/pages/inbounds/InboundFormModal.vue | 7 +- frontend/src/pages/inbounds/useInbounds.js | 4 + frontend/vite.config.js | 8 + web/assets/moment/moment-jalali.min.js | 1 - .../persian-datepicker.min.css | 1 - .../persian-datepicker.min.js | 1 - web/html/component/aPersianDatepicker.html | 73 ---- 15 files changed, 568 insertions(+), 94 deletions(-) create mode 100644 frontend/src/components/DateTimePicker.vue create mode 100644 frontend/src/composables/useDatepicker.js delete mode 100644 web/assets/moment/moment-jalali.min.js delete mode 100644 web/assets/persian-datepicker/persian-datepicker.min.css delete mode 100644 web/assets/persian-datepicker/persian-datepicker.min.js delete mode 100644 web/html/component/aPersianDatepicker.html diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 66d89ca4..96a565c6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17,7 +17,8 @@ "qrious": "^4.0.2", "qs": "^6.13.1", "vue": "^3.5.13", - "vue-i18n": "^11.1.4" + "vue-i18n": "^11.1.4", + "vue3-persian-datetime-picker": "^1.2.2" }, "devDependencies": { "@vitejs/plugin-vue": "^6.0.6", @@ -961,8 +962,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/boolbase": { "version": "1.0.0", @@ -974,7 +974,6 @@ "version": "1.1.14", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1069,8 +1068,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/core-js": { "version": "3.49.0", @@ -1549,6 +1547,11 @@ "node": ">= 6" } }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -1606,6 +1609,26 @@ "node": ">= 0.4" } }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -1720,6 +1743,21 @@ "node": ">=0.8.19" } }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -1755,6 +1793,11 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/jalaali-js": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/jalaali-js/-/jalaali-js-1.2.8.tgz", + "integrity": "sha512-Jl/EwY84JwjW2wsWqeU4pNd22VNQ7EkjI36bDuLw31wH98WQW4fPjD0+mG7cdCK+Y8D6s9R3zLiQ3LaKu6bD8A==" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2142,7 +2185,6 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -2158,6 +2200,28 @@ "node": "*" } }, + "node_modules/moment-jalaali": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/moment-jalaali/-/moment-jalaali-0.9.6.tgz", + "integrity": "sha512-v8wXjQplvk5ez+sUqgsWIrafwIf1BEXXvzTYwsg1wHcqh27nSgKPCJ6FnZRrCz03MoNyB9N31L0oms+vE8Rq7g==", + "dependencies": { + "jalaali-js": "^1.1.0", + "moment": "^2.22.2", + "moment-timezone": "^0.5.21", + "rimraf": "^3.0.2" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.48.tgz", + "integrity": "sha512-f22b8LV1gbTO2ms2j2z13MuPogNoh5UzxL3nzNAYKGraILnbGc9NEE6dyiiiLv46DGRb8A4kg8UKWLjPthxBHw==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -2215,6 +2279,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -2294,6 +2366,14 @@ "node": ">=8" } }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -2419,6 +2499,21 @@ "node": ">=4" } }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/rolldown": { "version": "1.0.0-rc.18", "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.18.tgz", @@ -2879,6 +2974,14 @@ "vue": "^3.0.0" } }, + "node_modules/vue3-persian-datetime-picker": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/vue3-persian-datetime-picker/-/vue3-persian-datetime-picker-1.2.2.tgz", + "integrity": "sha512-d7nkj5vgtUvEXZboSdRmP1uwBfXvXgXqdvsOOMQb34jiMZU/aBDrTYWTEe1N+XKF9pvTTJn8Rws9ttJmyhK/hw==", + "dependencies": { + "moment-jalaali": "^0.9.4" + } + }, "node_modules/warning": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", @@ -2911,6 +3014,11 @@ "node": ">=0.10.0" } }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, "node_modules/xml-name-validator": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index c59727f5..a835827a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -20,7 +20,8 @@ "qrious": "^4.0.2", "qs": "^6.13.1", "vue": "^3.5.13", - "vue-i18n": "^11.1.4" + "vue-i18n": "^11.1.4", + "vue3-persian-datetime-picker": "^1.2.2" }, "devDependencies": { "@vitejs/plugin-vue": "^6.0.6", diff --git a/frontend/src/components/DateTimePicker.vue b/frontend/src/components/DateTimePicker.vue new file mode 100644 index 00000000..c17bb457 --- /dev/null +++ b/frontend/src/components/DateTimePicker.vue @@ -0,0 +1,383 @@ + + + + + + + + diff --git a/frontend/src/composables/useDatepicker.js b/frontend/src/composables/useDatepicker.js new file mode 100644 index 00000000..03eba91c --- /dev/null +++ b/frontend/src/composables/useDatepicker.js @@ -0,0 +1,45 @@ +// Module-scoped reactive ref for the panel's "Calendar Type" setting. +// Loaded from /panel/setting/defaultSettings on first use, so any +// component (modals, inbound forms, future pages) can read the same +// value without prop-drilling and without re-fetching. +// +// useInbounds (which already reads defaultSettings for its own state) +// calls setDatepicker() after its fetch so we don't issue a second +// HTTP round-trip on the inbounds page. + +import { readonly, ref } from 'vue'; +import { HttpUtil } from '@/utils'; + +const datepicker = ref('gregorian'); +let fetched = false; +let pending = null; + +async function loadOnce() { + if (fetched) return; + if (pending) { + await pending; + return; + } + pending = (async () => { + try { + const msg = await HttpUtil.post('/panel/setting/defaultSettings'); + if (msg?.success) { + datepicker.value = msg.obj?.datepicker || 'gregorian'; + } + } finally { + fetched = true; + pending = null; + } + })(); + await pending; +} + +export function setDatepicker(value) { + fetched = true; + datepicker.value = value || 'gregorian'; +} + +export function useDatepicker() { + loadOnce(); + return { datepicker: readonly(datepicker) }; +} diff --git a/frontend/src/models/dbinbound.js b/frontend/src/models/dbinbound.js index 404498eb..61e08c8b 100644 --- a/frontend/src/models/dbinbound.js +++ b/frontend/src/models/dbinbound.js @@ -1,3 +1,4 @@ +import dayjs from 'dayjs'; import { ObjectUtil, NumberFormatter, SizeFormatter } from '@/utils'; import { Inbound, Protocols } from './inbound.js'; @@ -78,7 +79,7 @@ export class DBInbound { if (this.expiryTime === 0) { return null; } - return moment(this.expiryTime); + return dayjs(this.expiryTime); } set _expiryTime(t) { diff --git a/frontend/src/models/inbound.js b/frontend/src/models/inbound.js index 791885e9..c17c894e 100644 --- a/frontend/src/models/inbound.js +++ b/frontend/src/models/inbound.js @@ -1,3 +1,4 @@ +import dayjs from 'dayjs'; import { ObjectUtil, RandomUtil, Base64, NumberFormatter, SizeFormatter, Wireguard } from '@/utils'; export const Protocols = { @@ -2523,7 +2524,7 @@ Inbound.ClientBase = class extends XrayCommonClass { if (this.expiryTime < 0) { return this.expiryTime / -86400000; } - return moment(this.expiryTime); + return dayjs(this.expiryTime); } set _expiryTime(t) { diff --git a/frontend/src/pages/inbounds/ClientBulkModal.vue b/frontend/src/pages/inbounds/ClientBulkModal.vue index 8c94c849..1f9ca72f 100644 --- a/frontend/src/pages/inbounds/ClientBulkModal.vue +++ b/frontend/src/pages/inbounds/ClientBulkModal.vue @@ -13,6 +13,7 @@ import { USERS_SECURITY, TLS_FLOW_CONTROL, } from '@/models/inbound.js'; +import DateTimePicker from '@/components/DateTimePicker.vue'; // Bulk-add up to 500 clients in one go. The legacy panel offers five // generation modes — this component preserves them all: @@ -250,8 +251,7 @@ async function submit() { {{ t('pages.inbounds.expireDate') }} - + diff --git a/frontend/src/pages/inbounds/ClientFormModal.vue b/frontend/src/pages/inbounds/ClientFormModal.vue index 2ae3d658..a70e69f0 100644 --- a/frontend/src/pages/inbounds/ClientFormModal.vue +++ b/frontend/src/pages/inbounds/ClientFormModal.vue @@ -11,6 +11,7 @@ import { ColorUtils, } from '@/utils'; import { Inbound, Protocols, USERS_SECURITY, TLS_FLOW_CONTROL } from '@/models/inbound.js'; +import DateTimePicker from '@/components/DateTimePicker.vue'; const { t } = useI18n(); @@ -363,8 +364,7 @@ const title = computed(() => {{ t('pages.inbounds.expireDate') }} - + {{ t('depleted') }} diff --git a/frontend/src/pages/inbounds/InboundFormModal.vue b/frontend/src/pages/inbounds/InboundFormModal.vue index f2fd332c..227ae68e 100644 --- a/frontend/src/pages/inbounds/InboundFormModal.vue +++ b/frontend/src/pages/inbounds/InboundFormModal.vue @@ -30,6 +30,7 @@ import { } from '@/models/inbound.js'; import { DBInbound } from '@/models/dbinbound.js'; import FinalMaskForm from '@/components/FinalMaskForm.vue'; +import DateTimePicker from '@/components/DateTimePicker.vue'; const { t } = useI18n(); @@ -572,8 +573,7 @@ watch( {{ t('pages.inbounds.expireDate') }} - + @@ -667,8 +667,7 @@ watch( - + diff --git a/frontend/src/pages/inbounds/useInbounds.js b/frontend/src/pages/inbounds/useInbounds.js index 3e6af2d2..d5bb982f 100644 --- a/frontend/src/pages/inbounds/useInbounds.js +++ b/frontend/src/pages/inbounds/useInbounds.js @@ -9,6 +9,7 @@ import { computed, ref, shallowRef } from 'vue'; import { HttpUtil, ObjectUtil } from '@/utils'; import { DBInbound } from '@/models/dbinbound.js'; import { Protocols } from '@/models/inbound.js'; +import { setDatepicker } from '@/composables/useDatepicker.js'; const ONLINE_GRACE_MS = 60_000; @@ -146,6 +147,9 @@ export function useInbounds() { pageSize.value = s.pageSize ?? 0; remarkModel.value = s.remarkModel || '-ieo'; datepicker.value = s.datepicker || 'gregorian'; + // Mirror into the global composable so date-pickers in modals can + // pick the right calendar without re-fetching the settings. + setDatepicker(datepicker.value); ipLimitEnable.value = !!s.ipLimitEnable; } diff --git a/frontend/vite.config.js b/frontend/vite.config.js index 663770ff..8f49efa9 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -127,6 +127,14 @@ export default defineConfig({ if (id.includes('dayjs')) return 'vendor-dayjs'; if (id.includes('qrious')) return 'vendor-qrious'; if (id.includes('axios')) return 'vendor-axios'; + // The persian datepicker pulls in moment + moment-jalaali; bundle + // the trio together so unrelated pages don't pay the cost. + if ( + id.includes('vue3-persian-datetime-picker') + || id.includes('moment-jalaali') + || id.includes('jalaali-js') + || id.includes('/node_modules/moment/') + ) return 'vendor-jalali'; return 'vendor'; }, }, diff --git a/web/assets/moment/moment-jalali.min.js b/web/assets/moment/moment-jalali.min.js deleted file mode 100644 index 8b6ebfde..00000000 --- a/web/assets/moment/moment-jalali.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(){function t(e){var n=t.modules[e];if(!n)throw new Error('failed to require "'+e+'"');return"exports"in n||"function"!=typeof n.definition||(n.client=n.component=!0,n.definition.call(this,n.exports={},n),delete n.definition),n.exports}t.modules={moment:{exports:moment}},t.register=function(e,n){t.modules[e]={definition:n}},t.define=function(e,n){t.modules[e]={exports:n}},t.register("jalaali-js",(function(t,e){function n(t){return 0===a(t).leap}function r(t,e){return e<=6?31:e<=11||n(t)?30:29}function a(t){var e,n,r,a,i,s,o=[-61,9,38,199,426,686,756,818,1111,1181,1210,1635,2060,2097,2192,2262,2324,2394,2456,3178],u=o.length,f=t+621,l=-14,j=o[0];if(t=o[u-1])throw new Error("Invalid Jalaali year "+t);for(s=1;s=0){if(e<=185)return{jy:r,jm:1+c(e,31),jd:h(e,31)+1};e-=186}else r-=1,e+=179,1===i.leap&&(e+=1);return{jy:r,jm:7+c(e,30),jd:h(e,30)+1}}function o(t,e,n){var r=c(1461*(t+c(e-8,6)+100100),4)+c(153*h(e+9,12)+2,5)+n-34840408;return r=r-c(3*c(t+100100+c(e-8,6),100),4)+752}function u(t){var e,n,r,a;return e=(e=4*t+139361631)+4*c(3*c(4*t+183187720,146097),4)-3908,n=5*c(h(e,1461),4)+308,r=c(h(n,153),5)+1,a=h(c(n,153),12)+1,{gy:c(e,1461)-100100+c(8-a,6),gm:a,gd:r}}function c(t,e){return~~(t/e)}function h(t,e){return t-~~(t/e)*e}e.exports={toJalaali:function(t,e,n){"[object Date]"===Object.prototype.toString.call(t)&&(n=t.getDate(),e=t.getMonth()+1,t=t.getFullYear());return s(o(t,e,n))},toGregorian:function(t,e,n){return u(i(t,e,n))},isValidJalaaliDate:function(t,e,n){return t>=-61&&t<=3177&&e>=1&&e<=12&&n>=1&&n<=r(t,e)},isLeapJalaaliYear:n,jalaaliMonthLength:r,jalCal:a,j2d:i,d2j:s,g2d:o,d2g:u}})),t.register("moment-jalaali",(function(e,n){n.exports=W;var r,a=t("moment"),i=t("jalaali-js"),s=/(\[[^\[]*\])|(\\)?j(Mo|MM?M?M?|Do|DDDo|DD?D?D?|w[o|w]?|YYYYY|YYYY|YY|gg(ggg?)?|)|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|SS?S?|X|zz?|ZZ?|.)/g,o=/(\[[^\[]*\])|(\\)?(LTS?|LL?L?L?|l{1,4})/g,u=/\d\d?/,c=/\d{1,3}/,h=/\d{3}/,f=/\d{1,4}/,l=/[+\-]?\d{1,6}/,j=/[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,_=/Z|[\+\-]\d\d:?\d\d/i,d=/T/i,D=/[\+\-]?\d+(\.\d{1,3})?/,M={1:"۱",2:"۲",3:"۳",4:"۴",5:"۵",6:"۶",7:"۷",8:"۸",9:"۹",0:"۰"},Y={"۱":"1","۲":"2","۳":"3","۴":"4","۵":"5","۶":"6","۷":"7","۸":"8","۹":"9","۰":"0"},m={jm:"jmonth",jmonths:"jmonth",jy:"jyear",jyears:"jyear"},g={},p="DDD w M D".split(" "),y="M D w".split(" "),v={jM:function(){return this.jMonth()+1},jMMM:function(t){return this.localeData().jMonthsShort(this,t)},jMMMM:function(t){return this.localeData().jMonths(this,t)},jD:function(){return this.jDate()},jDDD:function(){return this.jDayOfYear()},jw:function(){return this.jWeek()},jYY:function(){return S(this.jYear()%100,2)},jYYYY:function(){return S(this.jYear(),4)},jYYYYY:function(){return S(this.jYear(),5)},jgg:function(){return S(this.jWeekYear()%100,2)},jgggg:function(){return this.jWeekYear()},jggggg:function(){return S(this.jWeekYear(),5)}};function w(t,e){return function(n){return S(t.call(this,n),e)}}function L(t,e){return function(n){return this.localeData().ordinal(t.call(this,n),e)}}function O(t,e){var n;for(n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t}function S(t,e){for(var n=t+"";n.length47?1300:1400);break;case"jYYYY":case"jYYYYY":i[0]=~~e}null==e&&(n._isValid=!1)}function x(t){var e,n,r,a=t._f.match(s),i=t._i+"",o=a.length;for(t._a=[],e=0;eW.jDaysInMonth(r,a)||a<0||a>11)&&(t._isValid=!1),n=A((e=E(r,a,i)).gy,e.gm,e.gd),isNaN(e.gy)&&(t._isValid=!1),t._jDiff=0,~~n.jy!==r&&(t._jDiff+=1),~~n.jm!==a&&(t._jDiff+=1),~~n.jd!==i&&(t._jDiff+=1),[e.gy,e.gm,e.gd])}(t)}function P(t,e,n){var r,a=n-e,i=n-t.day();return i>a&&(i-=7),i57724432199999&&(c._isValid=!1),c}function W(t,e,n,r){return V(t,e,n,r,!1)}function C(t,e){for(var n=5,r=function(t){return e.localeData().longDateFormat(t)||t};n>0&&o.test(t);)n-=1,t=t.replace(o,r);return t}function A(t,e,n){try{var r=i.toJalaali(t,e+1,n);return r.jm-=1,r}catch(t){return{jy:NaN,jm:NaN,jd:NaN}}}function E(t,e,n){try{var r=i.toGregorian(t,e+1,n);return r.gm-=1,r}catch(t){return{gy:NaN,gm:NaN,gd:NaN}}}function H(t,e){return~~(t/e)}function G(t,e){return t-~~(t/e)*e}O(W,a),W.fn=F(a.fn),W.utc=function(t,e,n,r){return V(t,e,n,r,!0)},W.unix=function(t){return V(1e3*t)},W.fn.format=function(t){return t&&(t=C(t,this),g[t]||(g[t]=function(t){var e,n=t.match(s),r=n.length;for(e=0;e1&&void 0!==arguments[1]?arguments[1]:2,e=String(Math.abs(t)),i=e.length,o="";for(t<0&&(o+="-");i1999?u=o.year:ua.year&&(u=a.year),isNaN(h)||h<1||h>12?h=o.month:u<=r.year&&h=a.year&&h>a.month&&(h=a.month),isNaN(d)||d<1?d=o.day:h<=r.month&&d=a.month&&d>a.day&&(d=a.day),{year:parseInt(u),month:parseInt(h),day:parseInt(d)}},c=function(t,n,e){var i=s(n,e),o=t.initTime,a=t.options.maxTime,r=t.options.minTime,u=i.hour,h=i.minute,d=i.second;return isNaN(u)||u<0||u>23?u=o.hour:ua.hour&&(u=a.hour),isNaN(h)||h<0||h>59?h=o.minute:u<=r.hour&&h=a.hour&&h>a.minute&&(h=a.minute),isNaN(d)||d<0||d>59?d=o.second:u<=r.hour&&h<=r.minute&&d=a.hour&&h>=a.minute&&d>a.second&&(d=a.second),{hour:parseInt(u),minute:parseInt(h),second:parseInt(d)}},p=function(t,n,e,i){var o=t.options.minDate,a=t.options.maxDate,s=l(t,{year:n,month:e,day:i});return o=r(o)?s:l(t,{year:o.year,month:o.month,day:o.day}),s<=(a=r(a)?s:l(t,{year:a.year,month:a.month,day:a.day}))&&s>=o},m=function(t,n){var e=t.options.separatorChars,i=n.split(e.between),o=t.options.date?i[0].split(e.date):{},a=t.options.date?t.options.time&&i[1]?i[1].split(e.time):{}:i[0].split(e.time);return{year:parseInt(o[0]),month:parseInt(o[1]),day:parseInt(o[2]),hour:parseInt(a[0]),minute:parseInt(a[1]),second:parseInt(a[2])}},l=function(t,n){var e=t.options.separatorChars;return"".concat(n.year).concat(e.date).concat(h(n.month)).concat(e.date).concat(h(n.day))},y=function(t,n){if(!n)return!1;var e=n.substr(0,10).split(t.options.separatorChars.date);return 3===e.length&&4===e[0].length&&2===e[1].length&&2===e[2].length},f=function(t,n){if(!n)return!1;var e=n.substr(t.options.date?11:0,8).split(t.options.separatorChars.time);return e.length===(t.options.hasSecond?3:2)&&!e.find((function(t){return 2!==t.toString().length}))},v="jdp",g="".concat(v,"-container"),D="".concat(v,"-overlay"),w="div.".concat(v,"-years"),_="div.".concat(v,"-year"),b="div.".concat(v,"-months"),C="div.".concat(v,"-month"),T="div.".concat(v,"-days"),x="div.".concat(v,"-day"),I="div.".concat(v,"-day.not-in-month"),M="div.".concat(v,"-day.disabled-day"),S="".concat(I,".disabled-day"),A="div.".concat(v,"-day-name"),E="div.".concat(v,"-icon-plus"),O="div.".concat(v,"-icon-minus"),j="div.".concat(v,"-footer"),N="div.".concat(v,"-btn-today"),P="div.".concat(v,"-btn-empty"),V="div.".concat(v,"-btn-close"),B="div.".concat(v,"-time-container"),H="div.".concat(v,"-time"),Y="not-in-range",L="holly-day",k="".concat(v,":change"),z="click",R="focusin",J="today",W="attr",q="data-jdp-only-date",F="data-jdp-only-time",X=("data-".concat(v),"visible"),G="block",K="none",Q=function t(n){if(["html","body","#document"].indexOf((n.nodeName||"").toLowerCase())>=0)return window;if(n instanceof HTMLElement){var e=window.getComputedStyle(n),i=e.overflow,o=e.overflowX,a=e.overflowY;if(/auto|scroll|overlay/.test(i+a+o))return n}return t(n.parentNode)},U=function(t){var n=document.createEvent("Event");return n.initEvent(t,!0,!0),n},Z=function(t,n){t&&(t.dispatchEvent(U(n)),n===k&&(t.dispatchEvent(U("change")),t.dispatchEvent(U("input"))))},$=function(t,n,i,a,r){var s=t.split(".");t=s.shift()||"div";var u=s,h=window.document.createElement(t);return o(n)?window.document.querySelector(n).appendChild(h):n.appendChild(h),u.length&&(h.className=u.join(" ")),i&&a&&function(t,n,e){for(var i=n.split(" "),o=0,a=i.length;o2e3||t.yearChange(n.target.value)}));if(i)for(var a=function(t){function n(t){return 100*Math.round(t/100)}var e=t.initDate.year;return{min:t.options.minDate.year||n(e-200),max:t.options.maxDate.year||n(e+200)}}(t),r=a.min;r<=a.max;r++){var s=$("option",o);s.value=r,s.text=nt(r,t.options.persianDigits),s.selected=r===t.initDate.year}else o.tabIndex=-1,o.value=t.initDate.year,o.type="number"},mt=function(t){pt(t),function(t){var n=$(b,t.dpContainer);dt(t,n,!1);var e=$(C,n);ct(t,n,!1);var i=$("select",e,"change",(function(n){t.monthChange(n.target.value)}));i.tabIndex=-1;for(var o=function(t){var n=t.initDate.year,e=t.options.minDate,i=t.options.maxDate,o=[],a=1,r=12;n===e.year?(a=e.month,n===i.year&&(r=i.month)):n===i.year&&(a=1,r=i.month);for(var s=a;s<=r;s++)o.push(s);return o}(t),a=t.options.months,r=0;r=r+f,(a.inBeforeMonth||a.inAfterMonth)&&(a.inBeforeMonth?(v++,a.day=v,a.year=m,a.month=d):(g++,a.day=g,a.year=l,a.month=c)),a.isValid=p(t,a.year,a.month,a.day),a.className=ht(it(a.year,a.month,a.day)),t.inputValue.day===a.day&&t.inputValue.year===a.year&&t.inputValue.month===a.month&&(a.className+=".".concat("selected")),t.today.day===a.day&&t.today.year===a.year&&t.today.month===a.month&&(a.className+=".".concat("today")),i(t.options.dayRendering)&&s(a,t.options.dayRendering(a,t.input)),a.isHollyDay&&(a.className+=".".concat(L));var u=a.isValid?x:M;(a.inBeforeMonth||a.inAfterMonth)&&(u=I,a.isValid||(u=S));var h=$(u+a.className,n,null,null,nt(a.day,t.options.persianDigits));h.day=a.day,h.month=a.month,h.year=a.year,a.isValid&&h.addEventListener(z,(function(){t.setValue({year:h.year,month:h.month,day:h.day})})),o(a)},w=0;w<=h;w++)D(w)}(t)},lt=function(t){var n,e=$(j,t.dpContainer);if(t.options.showTodayBtn&&t.options.date){var i=function(t){return p(t,t.today.year,t.today.month,t.today.day)}(t);$(N+(i?"":".disabled-btn"),e,z,(function(){i&&t.setValue(t.today)}),"امروز")}t.options.date||!t.options.time||null!==(n=t.input)&&void 0!==n&&n.value||$(N,e,z,(function(){t.setValue(t.initTime),t.hide()}),"انتخاب"),t.options.showEmptyBtn&&$(P,e,z,(function(){t.input.value="",Z(t.input,k),t.options.hideAfterChange&&t.hide()}),"خالی"),t.options.showCloseBtn&&$(V,e,z,(function(){t.hide()}),"بستن")},yt=function(t){tt(t.dpContainer,""),t.options.date&&mt(t),t.options.time&&function(t){var n=B+(t.options.time&&!t.options.date?".jdp-only-time":""),e=$(n,t.dpContainer);t.options.hasSecond&&ut(t,e,"second"),ut(t,e,"minute"),ut(t,e,"hour")}(t),lt(t)};var ft=/iphone|ipod|android|ie|blackberry|fennec/.test(null===(at=window.navigator)||void 0===at||null===(rt=at.userAgent)||void 0===rt?void 0:rt.toLowerCase()),vt={init:function(t){var n;this.updateOptions(t),Element.prototype.matches=Element.prototype.matchesSelector||Element.prototype.mozMatchesSelector||Element.prototype.msMatchesSelector||Element.prototype.oMatchesSelector||Element.prototype.webkitMatchesSelector,window.addEventListener("resize",(function(){vt.setPosition()})),this.options.autoHide&&document.body.addEventListener("click",(function(t){var n,e,o;vt.isShow&&(n=vt.dpContainer,!((o=(e=t).path||e.composedPath&&e.composedPath()||!1)?-1!==o.indexOf(n):n.outerHTML.indexOf(e.target.outerHTML)>-1))&&function(t){try{return i(t.composedPath)?t.composedPath()[0]:t.target}catch(n){return t.target}}(t)!==vt.input&&vt.hide()})),this.options.autoShow&&(n=this.options.selector,document.body.addEventListener(R,(function(t){t.target&&t.target.matches(n)&&vt.show(t.target)})))},updateOptions:function(t){this.options=Dt(t)},options:a({days:["ش","ی","د","س","چ","پ","ج"],months:["فروردین","اردیبهشت","خرداد","تیر","مرداد","شهریور","مهر","آبان","آذر","دی","بهمن","اسفند"],initDate:null,today:null,initTime:null,hasSecond:!0,time:!1,date:!0,minDate:{},maxDate:{},minTime:{},maxTime:{},separatorChars:{date:"/",between:" ",time:":"},persianDigits:!1,zIndex:1e3,container:"body",selector:"input[data-jdp]",autoShow:!0,autoHide:!0,hideAfterChange:!0,plusHtml:'',minusHtml:'',changeMonthRotateYear:!1,showTodayBtn:!0,showEmptyBtn:!0,showCloseBtn:ft,autoReadOnlyInput:ft,useDropDownYears:!0,topSpace:0,bottomSpace:0}),input:null,get dpContainer(){return this._dpContainer||(this._dpContainer=$(g,this.options.container),this.overlayElm=$(D,this.options.container),this.dpContainer.style.zIndex=this.options.zIndex,this.overlayElm.style.zIndex=this.options.zIndex-1),this._dpContainer},get today(){return this._today=this._today||this.options.today||function(){var t,n,e=new Date,i=parseInt(e.getFullYear()),o=parseInt(e.getMonth())+1,a=parseInt(e.getDate());i>1600?(t=979,i-=1600):(t=0,i-=621);var r=o>2?i+1:i;return n=365*i+parseInt((r+3)/4)-parseInt((r+99)/100)+parseInt((r+399)/400)-80+a+[0,31,59,90,120,151,181,212,243,273,304,334][o-1],t+=33*parseInt(n/12053),n%=12053,t+=4*parseInt(n/1461),(n%=1461)>365&&(t+=parseInt((n-1)/365),n=(n-1)%365),{year:t,month:n<186?1+parseInt(n/31):7+parseInt((n-186)/30),day:1+(n<186?n%31:(n-186)%30)}}(),this._today},get inputValue(){var t=a(this.input.value);return t=function(t,n){if(!n)return!1;var e=t.options.separatorChars,i=t.options.date?"\\d{4}".concat(e.date,"\\d{2}").concat(e.date,"\\d{2}"):"",o=t.options.time?"\\d{2}".concat(e.time,"\\d{2}")+(t.options.hasSecond?"".concat(e.time,"\\d{2}"):""):"";return new RegExp(i+(i&&o?e.between:"")+o).test(n,"g")}(this,t)||o(t)&&y(this,t)?m(this,t):{}},get initDate(){return this.options.initDate?this.options.initDate:(this._initDate||(this._initDate=a(this.input.value)||{},r(this._initDate)?this._initDate=this.options.initDate||a(this.today):o(this._initDate)&&y(this,this._initDate)?this._initDate=m(this,this._initDate):this._initDate=a(this.today),this._initDate=d(this,this._initDate)),this._initDate)},get initTime(){if(this._initTime)return this._initTime;var t=new Date,n={hour:t.getHours(),minute:t.getMinutes(),second:0};return this._initTime=a(this.input.value)||this.options.initTime||n,o(this._initTime)&&(f(this,this._initTime)?this._initTime=m(this,this._initTime):this._initTime=n),this._initTime=c(this,this._initTime),this._initTime},_draw:function(){yt(this)},show:function(t){var n=this;this._initDate=null,this._initTime=null,this._value=null,this.input=t,this._draw(),function(t,n){n.autoReadOnlyInput&&!t.readOnly&&(t.setAttribute("readonly","readonly"),t.readOnly=!0)}(t,this.options),this.dpContainer.style.visibility=X,this.dpContainer.style.display=G,this.overlayElm.style.display=G,setTimeout((function(){n.dpContainer.style.visibility=X,n.dpContainer.style.display=G,n.overlayElm.style.display=G,n.isShow=!0}),300),this.setPosition(),function(t){Q(t).addEventListener("scroll",(function(){vt.setPosition()}),{passive:!0})}(t)},hide:function(){this.dpContainer.style.visibility="hidden",this.dpContainer.style.display=K,this.overlayElm.style.display=K,this.isShow=!1},setPosition:function(){if(this.dpContainer.style.visibility===X){var t=this.input.getBoundingClientRect(),n=t.height,e=t.left,i=t.top+n;i+=this.options.topSpace;var o=window.document.body.offsetWidth,a=this.dpContainer.offsetWidth,r=this.dpContainer.offsetHeight;e+a>=o&&(e-=e+a-(o+10)),i-n>=r&&i+r>=window.innerHeight&&(i-=r+n+this.options.bottomSpace+this.options.topSpace),this.dpContainer.style.position="fixed",this.dpContainer.style.left=e+"px",this.dpContainer.style.top=i+"px"}},get getValue(){return this._value=this._value||this.inputValue||{},this._value},setValue:function(t){var n,e,i,o,a;this._value=s({year:this.today.year,month:this.today.month,day:this.today.day,hour:this.initTime.hour,minute:this.initTime.minute,second:this.initTime.second},s(this._value,t)),this._initTime=null,this.input.value=(n=this,e=this._value,i=n.options.separatorChars,o=n.options.date?"".concat(e.year).concat(i.date).concat(h(e.month)).concat(i.date).concat(h(e.day)):"",a=n.options.time?"".concat(h(e.hour)).concat(i.time).concat(h(e.minute))+(n.options.hasSecond?i.time+h(e.second):""):"",o+(o&&a?i.between:"")+a),Z(this.input,k),!this.options.time&&this.options.hideAfterChange?this.hide():this._draw()},increaseMonth:function(){var t=12===this._initDate.month;this.options.changeMonthRotateYear&&t&&this.increaseYear(),this.monthChange(t?1:this._initDate.month+1)},decreaseMonth:function(){var t=1===this._initDate.month;this.options.changeMonthRotateYear&&t&&this.decreaseYear(),this.monthChange(t?12:this._initDate.month-1)},monthChange:function(t){this._initDate=d(this,this._initDate,{month:t}),this._draw()},increaseYear:function(){this.yearChange(this._initDate.year+1)},decreaseYear:function(){this.yearChange(this._initDate.year-1)},yearChange:function(t){this._initDate=d(this,this._initDate,{year:t}),this._draw()}},gt=function(t,n){var e,i=null===(e=vt.input)||void 0===e?void 0:e.getAttribute(t);if(!n&&i===J)return a(vt.today);if(!o(i))return{};try{i=document.querySelector(i).value}catch(t){}return i=n?f(vt,i)?m(vt,i):{}:y(vt,i)?m(vt,i):{}},Dt=function(t){return!e(vt.options._date)&&e(t.date)&&(t.date=vt.options._date),!e(vt.options._time)&&e(t.time)&&(t.time=vt.options._time),t.separatorChars=s(vt.options.separatorChars,t.separatorChars),(t=s({},vt.options,t)).minDate===J&&(t.minDate=a(vt.today)),t.maxDate===J&&(t.maxDate=a(vt.today)),(t.initDate===W||t._initDateIsAttr)&&(delete t.initDate,t._initDateIsAttr=!0,window.Object.defineProperty(t,"initDate",{get:function(){return gt("data-jdp-init-date")},enumerable:!0})),(t.minDate===W||t._minDateIsAttr)&&(delete t.minDate,t._minDateIsAttr=!0,window.Object.defineProperty(t,"minDate",{get:function(){return gt("data-jdp-min-date")},enumerable:!0})),(t.maxDate===W||t._maxDateIsAttr)&&(delete t.maxDate,t._maxDateIsAttr=!0,window.Object.defineProperty(t,"maxDate",{get:function(){return gt("data-jdp-max-date")},enumerable:!0})),(t.minTime===W||t._minTimeIsAttr)&&(delete t.minTime,t._minTimeIsAttr=!0,window.Object.defineProperty(t,"minTime",{get:function(){return gt("data-jdp-min-time",!0)},enumerable:!0})),(t.maxTime===W||t._maxTimeIsAttr)&&(delete t.maxTime,t._maxTimeIsAttr=!0,window.Object.defineProperty(t,"maxTime",{get:function(){return gt("data-jdp-max-time",!0)},enumerable:!0})),t._date=t.date,delete t.date,window.Object.defineProperty(t,"date",{get:function(){var n,e;return!(null!==(n=vt.input)&&void 0!==n&&n.hasAttribute(F))&&(t._date||(null===(e=vt.input)||void 0===e?void 0:e.hasAttribute(q)))},enumerable:!0}),t._time=t.time,delete t.time,window.Object.defineProperty(t,"time",{get:function(){var n,e;return!(null!==(n=vt.input)&&void 0!==n&&n.hasAttribute(q))&&(t._time||(null===(e=vt.input)||void 0===e?void 0:e.hasAttribute(F)))},enumerable:!0}),t};window.jalaliDatepicker={startWatch:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};vt.init(t)},show:function(t){vt.show(t)},hide:function(){vt.hide()},updateOptions:function(t){vt.updateOptions(t)}}}()}(); \ No newline at end of file diff --git a/web/html/component/aPersianDatepicker.html b/web/html/component/aPersianDatepicker.html deleted file mode 100644 index cb4c2918..00000000 --- a/web/html/component/aPersianDatepicker.html +++ /dev/null @@ -1,73 +0,0 @@ -{{define "component/persianDatepickerTemplate"}} - -{{end}} - -{{define "component/aPersianDatepicker"}} - - - - -{{end}} \ No newline at end of file