antd-dayjs-jalali2
Version:
antd persian (Jalali, Khorshidi) Day.js calander
309 lines (281 loc) • 8.57 kB
JavaScript
import jdate from './calendar'
import * as C from './constant'
export default (o, Dayjs, dayjs) => {
const proto = Dayjs.prototype
const U = proto.$utils()
const $isJalali = (v) => v.$C === 'jalali'
const $prettyUnit = U.prettyUnit || U.p
const $isUndefined = U.isUndefined || U.u
const $padStart = U.padStart || U.s
const $monthDiff = U.monthDiff || U.m
const $absFloor = U.absFloor || U.a
const wrapperOfTruth = (action) => function (...args) {
const unsure = action.bind(this)(...args)
unsure.$C = this.$C
if (unsure.isJalali()) {
unsure.InitJalali()
}
return unsure
}
// keep calendar on date manipulation
proto.startOf = wrapperOfTruth(proto.startOf)
proto.endOf = wrapperOfTruth(proto.endOf)
proto.add = wrapperOfTruth(proto.add)
proto.subtract = wrapperOfTruth(proto.subtract)
proto.set = wrapperOfTruth(proto.set)
const oldParse = proto.parse
const oldInit = proto.init
const oldStartOf = proto.startOf
const old$Set = proto.$set
const oldAdd = proto.add
const oldFormat = proto.format
const oldDiff = proto.diff
const oldYear = proto.year
const oldMonth = proto.month
const oldDate = proto.date
const oldDaysInMonth = proto.daysInMonth
const oldToArray = proto.toArray
dayjs.$C = 'gregory'
// First Day Of Week
// dayjs.$fdow = 6 // 0: sunday, ...
dayjs.calendar = function (calendar) {
dayjs.$C = calendar
return dayjs
}
proto.calendar = function (calendar) {
const that = this.clone()
that.$C = calendar
if (that.isJalali()) {
that.InitJalali()
}
return that
}
proto.isJalali = function () {
return $isJalali(this)
}
dayjs.locale(C.fa)
const wrapper = function (date, instance) {
return dayjs(date, {
locale: instance.$L,
calendar: instance.$C
})
}
proto.init = function (cfg = {}) {
oldInit.bind(this)(cfg)
if (this.isJalali()) {
this.InitJalali()
}
}
proto.parse = function (cfg) {
let reg
this.$C = cfg.calendar || this.$C || dayjs.$C
// eslint-disable-next-line no-cond-assign
if (cfg.jalali && (typeof cfg.date === 'string')
&& (/.*[^Z]$/i.test(cfg.date)) // looking for a better way
&& (reg = cfg.date.match(C.REGEX_PARSE))) {
// 1397-08-08 or 13970808
const [y, m, d] = jdate.G(
parseInt(reg[1], 10),
parseInt(reg[2], 10),
parseInt(reg[3] || 1, 10)
)
cfg.date = `${y}-${m}-${d}${reg[4] || ''}`
}
return oldParse.bind(this)(cfg)
}
proto.InitJalali = function () {
const [jy, jm, jd] = jdate.J(this.$y, this.$M + 1, this.$D)
this.$jy = jy
this.$jM = jm - 1
this.$jD = jd
}
proto.startOf = function (units, startOf) { // startOf -> endOf
if (!$isJalali(this)) {
return oldStartOf.bind(this)(units, startOf)
}
const isStartOf = !$isUndefined(startOf) ? startOf : true
const unit = $prettyUnit(units)
const instanceFactory = (d, m, y = this.$jy) => {
const [gy, gm, gd] = jdate.G(y, m + 1, d)
const ins = wrapper(new Date(gy, gm - 1, gd), this)
return isStartOf ? ins : ins.endOf(C.D)
}
const fdow = this.$locale().weekStart || 0
const WModifier = (this.$W + (7 - fdow)) % 7
switch (unit) {
case C.Y:
return isStartOf ? instanceFactory(1, 0)
: instanceFactory(0, 0, this.$jy + 1)
case C.M:
return isStartOf ? instanceFactory(1, this.$jM)
: instanceFactory(
0,
(this.$jM + 1) % 12,
this.$jy + parseInt((this.$jM + 1) / 12, 10)
)
case C.W:
return isStartOf ? instanceFactory(this.$jD - WModifier, this.$jM)
: instanceFactory(this.$jD + (6 - WModifier), this.$jM)
default:
return oldStartOf.bind(this)(units, startOf)
}
}
proto.$set = function (units, int) {
if (!$isJalali(this)) {
return old$Set.bind(this)(units, int)
}
const unit = $prettyUnit(units)
const instanceFactory = (d, m, y = this.$jy) => {
const [gy, gm, gd] = jdate.G(y, m + 1, d)
this.$d.setFullYear(gy)
this.$d.setMonth(gm - 1)
this.$d.setDate(gd)
return this
}
switch (unit) {
case C.W:
instanceFactory(this.$jD - ((this.$W + 1) % 7) + int, this.$jM)
break
case C.DATE:
case C.D:
instanceFactory(int, this.$jM)
break
case C.M:
instanceFactory(this.$jD, int)
break
case C.Y:
instanceFactory(this.$jD, this.$jM, int)
break
default:
return old$Set.bind(this)(units, int)
}
this.init()
return this
}
proto.add = function (number, units) {
if (!$isJalali(this)) {
return oldAdd.bind(this)(number, units)
}
number = Number(number) // eslint-disable-line no-param-reassign
// units === 'ms' hard code here, will update in next release
const unit = (units && (units.length === 1 || units === 'ms')) ? units : $prettyUnit(units)
const instanceFactory = (u, n) => {
const date = this.set(C.DATE, 1).set(u, n + number)
return date.set(C.DATE, Math.min(this.$jD, date.daysInMonth()))
}
if (['M', C.M].indexOf(unit) > -1) {
const n = this.$jM + number
const y = n < 0 ? -Math.ceil(-n / 12) : parseInt(n / 12, 10)
const d = this.$jD
const x = this.set(C.D, 1).add(y, C.Y).set(C.M, n - (y * 12))
return x.set(C.D, Math.min(x.daysInMonth(), d))
}
if (['y', C.Y].indexOf(unit) > -1) {
return instanceFactory(C.Y, this.$jy)
}
if (['d', C.D].indexOf(unit) > -1) {
const date = new Date(this.$d)
date.setDate(date.getDate() + number)
return wrapper(date, this)
}
return oldAdd.bind(this)(number, units)
}
proto.format = function (formatStr, localeObject) {
if (!$isJalali(this)) {
return oldFormat.bind(this)(formatStr, localeObject)
}
const str = formatStr || C.FORMAT_DEFAULT
const locale = localeObject || this.$locale()
const months = locale.jmonths || locale.months
return str.replace(C.REGEX_FORMAT, (match) => {
if (match.indexOf('[') > -1) return match.replace(/\[|\]/g, '')
switch (match) {
case 'YY':
return String(this.$jy).slice(-2)
case 'YYYY':
return String(this.$jy)
case 'M':
return String(this.$jM + 1)
case 'MM':
return $padStart(this.$jM + 1, 2, '0')
case 'MMM':
return months[this.$jM].slice(0, 3)
case 'MMMM':
return months[this.$jM]
case 'D':
return String(this.$jD)
case 'DD':
return $padStart(this.$jD, 2, '0')
default:
return oldFormat.bind(this)(match, localeObject)
}
})
}
proto.diff = function (input, units, float) {
if (!$isJalali(this)) {
return oldDiff.bind(this)(input, units, float)
}
const unit = $prettyUnit(units)
const that = dayjs(input)
let result = $monthDiff(this, that)
switch (unit) {
case C.Y:
result /= 12
break
case C.M:
break
default: // milliseconds
return oldDiff.bind(this)(input, units, float)
}
return float ? result : $absFloor(result)
}
proto.$g = function (input, get, set) {
if ($isUndefined(input)) return this[get]
return this.set(set, input)
}
proto.year = function (input) {
if (!$isJalali(this)) {
return oldYear.bind(this)(input)
}
return this.$g(input, '$jy', C.Y)
}
proto.month = function (input) {
if (!$isJalali(this)) {
return oldMonth.bind(this)(input)
}
return this.$g(input, '$jM', C.M)
}
proto.day = function (input) {
if (!$isJalali(this)) {
return oldMonth.bind(this)(input)
}
return this.$g(input, '$W', C.W)
}
proto.date = function (input) {
if (!$isJalali(this)) {
return oldDate.bind(this)(input)
}
return this.$g(input, '$jD', C.D)
}
proto.daysInMonth = function () {
if (!$isJalali(this)) {
return oldDaysInMonth.bind(this)()
}
return this.endOf(C.M).$jD
}
/**
* toArray function moved to official plugin
* Check function existence before override
*/
if (oldToArray) {
proto.toArray = function () {
if (!$isJalali(this)) {
return oldToArray.bind(this)()
}
return [this.$jy, this.$jM, this.$jD, this.$H, this.$m, this.$s, this.$ms]
}
}
proto.clone = function () {
return wrapper(this.toDate(), this)
}
}