| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 | // Utilsimport { raf } from '../utils/dom/raf';import { isDate } from '../utils/validate/date';import { getScrollTop } from '../utils/dom/scroll';import { t, bem, copyDate, copyDates, getNextDay, compareDay, calcDateNum, compareMonth, createComponent, getDayByOffset } from './utils'; // Componentsimport Popup from '../popup';import Button from '../button';import Toast from '../toast';import Month from './components/Month';import Header from './components/Header';export default createComponent({  props: {    title: String,    color: String,    value: Boolean,    readonly: Boolean,    formatter: Function,    rowHeight: [Number, String],    confirmText: String,    rangePrompt: String,    defaultDate: [Date, Array],    getContainer: [String, Function],    allowSameDay: Boolean,    confirmDisabledText: String,    type: {      type: String,      default: 'single'    },    round: {      type: Boolean,      default: true    },    position: {      type: String,      default: 'bottom'    },    poppable: {      type: Boolean,      default: true    },    maxRange: {      type: [Number, String],      default: null    },    lazyRender: {      type: Boolean,      default: true    },    showMark: {      type: Boolean,      default: true    },    showTitle: {      type: Boolean,      default: true    },    showConfirm: {      type: Boolean,      default: true    },    showSubtitle: {      type: Boolean,      default: true    },    closeOnPopstate: {      type: Boolean,      default: true    },    closeOnClickOverlay: {      type: Boolean,      default: true    },    safeAreaInsetBottom: {      type: Boolean,      default: true    },    minDate: {      type: Date,      validator: isDate,      default: function _default() {        return new Date();      }    },    maxDate: {      type: Date,      validator: isDate,      default: function _default() {        var now = new Date();        return new Date(now.getFullYear(), now.getMonth() + 6, now.getDate());      }    },    firstDayOfWeek: {      type: [Number, String],      default: 0,      validator: function validator(val) {        return val >= 0 && val <= 6;      }    }  },  inject: {    vanPopup: {      default: null    }  },  data: function data() {    return {      subtitle: '',      currentDate: this.getInitialDate()    };  },  computed: {    months: function months() {      var months = [];      var cursor = new Date(this.minDate);      cursor.setDate(1);      do {        months.push(new Date(cursor));        cursor.setMonth(cursor.getMonth() + 1);      } while (compareMonth(cursor, this.maxDate) !== 1);      return months;    },    buttonDisabled: function buttonDisabled() {      var type = this.type,          currentDate = this.currentDate;      if (currentDate) {        if (type === 'range') {          return !currentDate[0] || !currentDate[1];        }        if (type === 'multiple') {          return !currentDate.length;        }      }      return !currentDate;    },    dayOffset: function dayOffset() {      return this.firstDayOfWeek ? this.firstDayOfWeek % 7 : 0;    }  },  watch: {    value: 'init',    type: function type() {      this.reset();    },    defaultDate: function defaultDate(val) {      this.currentDate = val;      this.scrollIntoView();    }  },  mounted: function mounted() {    this.init(); // https://github.com/vant-ui/vant/issues/9845    if (!this.poppable) {      var _this$vanPopup;      (_this$vanPopup = this.vanPopup) == null ? void 0 : _this$vanPopup.$on('opened', this.onScroll);    }  },  /* istanbul ignore next */  activated: function activated() {    this.init();  },  methods: {    // @exposed-api    reset: function reset(date) {      if (date === void 0) {        date = this.getInitialDate();      }      this.currentDate = date;      this.scrollIntoView();    },    init: function init() {      var _this = this;      if (this.poppable && !this.value) {        return;      }      this.$nextTick(function () {        // add Math.floor to avoid decimal height issues        // https://github.com/vant-ui/vant/issues/5640        _this.bodyHeight = Math.floor(_this.$refs.body.getBoundingClientRect().height);        _this.onScroll();        _this.scrollIntoView();      });    },    // @exposed-api    scrollToDate: function scrollToDate(targetDate) {      var _this2 = this;      raf(function () {        var displayed = _this2.value || !_this2.poppable;        /* istanbul ignore if */        if (!targetDate || !displayed) {          return;        }        _this2.months.some(function (month, index) {          if (compareMonth(month, targetDate) === 0) {            var _this2$$refs = _this2.$refs,                body = _this2$$refs.body,                months = _this2$$refs.months;            months[index].scrollIntoView(body);            return true;          }          return false;        });        _this2.onScroll();      });    },    // scroll to current month    scrollIntoView: function scrollIntoView() {      var currentDate = this.currentDate;      if (currentDate) {        var targetDate = this.type === 'single' ? currentDate : currentDate[0];        this.scrollToDate(targetDate);      }    },    getInitialDate: function getInitialDate() {      var type = this.type,          minDate = this.minDate,          maxDate = this.maxDate,          defaultDate = this.defaultDate;      if (defaultDate === null) {        return defaultDate;      }      var defaultVal = new Date();      if (compareDay(defaultVal, minDate) === -1) {        defaultVal = minDate;      } else if (compareDay(defaultVal, maxDate) === 1) {        defaultVal = maxDate;      }      if (type === 'range') {        var _ref = defaultDate || [],            startDay = _ref[0],            endDay = _ref[1];        return [startDay || defaultVal, endDay || getNextDay(defaultVal)];      }      if (type === 'multiple') {        return defaultDate || [defaultVal];      }      return defaultDate || defaultVal;    },    // calculate the position of the elements    // and find the elements that needs to be rendered    onScroll: function onScroll() {      var _this$$refs = this.$refs,          body = _this$$refs.body,          months = _this$$refs.months;      var top = getScrollTop(body);      var bottom = top + this.bodyHeight;      var heights = months.map(function (item) {        return item.getHeight();      });      var heightSum = heights.reduce(function (a, b) {        return a + b;      }, 0); // iOS scroll bounce may exceed the range      if (bottom > heightSum && top > 0) {        return;      }      var height = 0;      var currentMonth;      var visibleRange = [-1, -1];      for (var i = 0; i < months.length; i++) {        var visible = height <= bottom && height + heights[i] >= top;        if (visible) {          visibleRange[1] = i;          if (!currentMonth) {            currentMonth = months[i];            visibleRange[0] = i;          }          if (!months[i].showed) {            months[i].showed = true;            this.$emit('month-show', {              date: months[i].date,              title: months[i].title            });          }        }        height += heights[i];      }      months.forEach(function (month, index) {        month.visible = index >= visibleRange[0] - 1 && index <= visibleRange[1] + 1;      });      /* istanbul ignore else */      if (currentMonth) {        this.subtitle = currentMonth.title;      }    },    onClickDay: function onClickDay(item) {      if (this.readonly) {        return;      }      var date = item.date;      var type = this.type,          currentDate = this.currentDate;      if (type === 'range') {        if (!currentDate) {          this.select([date, null]);          return;        }        var startDay = currentDate[0],            endDay = currentDate[1];        if (startDay && !endDay) {          var compareToStart = compareDay(date, startDay);          if (compareToStart === 1) {            this.select([startDay, date], true);          } else if (compareToStart === -1) {            this.select([date, null]);          } else if (this.allowSameDay) {            this.select([date, date], true);          }        } else {          this.select([date, null]);        }      } else if (type === 'multiple') {        if (!currentDate) {          this.select([date]);          return;        }        var selectedIndex;        var selected = this.currentDate.some(function (dateItem, index) {          var equal = compareDay(dateItem, date) === 0;          if (equal) {            selectedIndex = index;          }          return equal;        });        if (selected) {          var _currentDate$splice = currentDate.splice(selectedIndex, 1),              unselectedDate = _currentDate$splice[0];          this.$emit('unselect', copyDate(unselectedDate));        } else if (this.maxRange && currentDate.length >= this.maxRange) {          Toast(this.rangePrompt || t('rangePrompt', this.maxRange));        } else {          this.select([].concat(currentDate, [date]));        }      } else {        this.select(date, true);      }    },    togglePopup: function togglePopup(val) {      this.$emit('input', val);    },    select: function select(date, complete) {      var _this3 = this;      var emit = function emit(date) {        _this3.currentDate = date;        _this3.$emit('select', copyDates(_this3.currentDate));      };      if (complete && this.type === 'range') {        var valid = this.checkRange(date);        if (!valid) {          // auto selected to max range if showConfirm          if (this.showConfirm) {            emit([date[0], getDayByOffset(date[0], this.maxRange - 1)]);          } else {            emit(date);          }          return;        }      }      emit(date);      if (complete && !this.showConfirm) {        this.onConfirm();      }    },    checkRange: function checkRange(date) {      var maxRange = this.maxRange,          rangePrompt = this.rangePrompt;      if (maxRange && calcDateNum(date) > maxRange) {        Toast(rangePrompt || t('rangePrompt', maxRange));        return false;      }      return true;    },    onConfirm: function onConfirm() {      this.$emit('confirm', copyDates(this.currentDate));    },    genMonth: function genMonth(date, index) {      var h = this.$createElement;      var showMonthTitle = index !== 0 || !this.showSubtitle;      return h(Month, {        "ref": "months",        "refInFor": true,        "attrs": {          "date": date,          "type": this.type,          "color": this.color,          "minDate": this.minDate,          "maxDate": this.maxDate,          "showMark": this.showMark,          "formatter": this.formatter,          "rowHeight": this.rowHeight,          "lazyRender": this.lazyRender,          "currentDate": this.currentDate,          "showSubtitle": this.showSubtitle,          "allowSameDay": this.allowSameDay,          "showMonthTitle": showMonthTitle,          "firstDayOfWeek": this.dayOffset        },        "scopedSlots": {          'top-info': this.$scopedSlots['top-info'],          'bottom-info': this.$scopedSlots['bottom-info']        },        "on": {          "click": this.onClickDay        }      });    },    genFooterContent: function genFooterContent() {      var h = this.$createElement;      var slot = this.slots('footer');      if (slot) {        return slot;      }      if (this.showConfirm) {        var text = this.buttonDisabled ? this.confirmDisabledText : this.confirmText;        return h(Button, {          "attrs": {            "round": true,            "block": true,            "type": "danger",            "color": this.color,            "disabled": this.buttonDisabled,            "nativeType": "button"          },          "class": bem('confirm'),          "on": {            "click": this.onConfirm          }        }, [text || t('confirm')]);      }    },    genFooter: function genFooter() {      var h = this.$createElement;      return h("div", {        "class": bem('footer', {          unfit: !this.safeAreaInsetBottom        })      }, [this.genFooterContent()]);    },    genCalendar: function genCalendar() {      var _this4 = this;      var h = this.$createElement;      return h("div", {        "class": bem()      }, [h(Header, {        "attrs": {          "title": this.title,          "showTitle": this.showTitle,          "subtitle": this.subtitle,          "showSubtitle": this.showSubtitle,          "firstDayOfWeek": this.dayOffset        },        "scopedSlots": {          title: function title() {            return _this4.slots('title');          }        }      }), h("div", {        "ref": "body",        "class": bem('body'),        "on": {          "scroll": this.onScroll        }      }, [this.months.map(this.genMonth)]), this.genFooter()]);    }  },  render: function render() {    var _this5 = this;    var h = arguments[0];    if (this.poppable) {      var _attrs;      var createListener = function createListener(name) {        return function () {          return _this5.$emit(name);        };      };      return h(Popup, {        "attrs": (_attrs = {          "round": true,          "value": this.value        }, _attrs["round"] = this.round, _attrs["position"] = this.position, _attrs["closeable"] = this.showTitle || this.showSubtitle, _attrs["getContainer"] = this.getContainer, _attrs["closeOnPopstate"] = this.closeOnPopstate, _attrs["closeOnClickOverlay"] = this.closeOnClickOverlay, _attrs),        "class": bem('popup'),        "on": {          "input": this.togglePopup,          "open": createListener('open'),          "opened": createListener('opened'),          "close": createListener('close'),          "closed": createListener('closed')        }      }, [this.genCalendar()]);    }    return this.genCalendar();  }});
 |