From 1640029e3472a32d35734531e729f1982fb4ba3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BA=91=E9=A3=9E?= Date: Wed, 10 Aug 2022 17:25:43 +0800 Subject: [PATCH 1/9] feat:add date particle --- src/editor/core/draw/Draw.ts | 6 +++ .../core/draw/particle/date/DateParticle.ts | 15 ++++++ src/editor/dataset/constant/Element.ts | 6 ++- src/editor/dataset/enum/Element.ts | 3 +- src/editor/interface/Element.ts | 6 +++ src/editor/utils/element.ts | 46 +++++++++++++++++++ src/mock.ts | 14 ++++++ 7 files changed, 93 insertions(+), 3 deletions(-) create mode 100644 src/editor/core/draw/particle/date/DateParticle.ts diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts index 74e3d86..4aa098a 100644 --- a/src/editor/core/draw/Draw.ts +++ b/src/editor/core/draw/Draw.ts @@ -44,6 +44,7 @@ import { ControlComponent } from '../../dataset/enum/Control' import { formatElementList } from '../../utils/element' import { WorkerManager } from '../worker/WorkerManager' import { Previewer } from './particle/previewer/Previewer' +import { DateParticle } from './particle/date/DateParticle' export class Draw { @@ -78,6 +79,7 @@ export class Draw { private waterMark: Watermark private header: Header private hyperlinkParticle: HyperlinkParticle + private dateParticle: DateParticle private separatorParticle: SeparatorParticle private pageBreakParticle: PageBreakParticle private superscriptParticle: SuperscriptParticle @@ -130,6 +132,7 @@ export class Draw { this.waterMark = new Watermark(this) this.header = new Header(this) this.hyperlinkParticle = new HyperlinkParticle(this) + this.dateParticle = new DateParticle() this.separatorParticle = new SeparatorParticle() this.pageBreakParticle = new PageBreakParticle(this) this.superscriptParticle = new SuperscriptParticle() @@ -801,6 +804,9 @@ export class Draw { } else if (element.type === ElementType.HYPERLINK) { this.textParticle.complete() this.hyperlinkParticle.render(ctx, element, x, y + offsetY) + } else if (element.type === ElementType.DATE) { + this.textParticle.complete() + this.dateParticle.render(ctx, element, x, y + offsetY) } else if (element.type === ElementType.SUPERSCRIPT) { this.textParticle.complete() this.superscriptParticle.render(ctx, element, x, y + offsetY) diff --git a/src/editor/core/draw/particle/date/DateParticle.ts b/src/editor/core/draw/particle/date/DateParticle.ts new file mode 100644 index 0000000..98f0722 --- /dev/null +++ b/src/editor/core/draw/particle/date/DateParticle.ts @@ -0,0 +1,15 @@ +import { IRowElement } from '../../../../interface/Row' + +export class DateParticle { + + public render(ctx: CanvasRenderingContext2D, element: IRowElement, x: number, y: number) { + ctx.save() + ctx.font = element.style + if (element.color) { + ctx.fillStyle = element.color + } + ctx.fillText(element.value, x, y) + ctx.restore() + } + +} \ No newline at end of file diff --git a/src/editor/dataset/constant/Element.ts b/src/editor/dataset/constant/Element.ts index 0bafd61..b1d59fd 100644 --- a/src/editor/dataset/constant/Element.ts +++ b/src/editor/dataset/constant/Element.ts @@ -47,7 +47,8 @@ export const EDITOR_ELEMENT_ZIP_ATTR: Array = [ 'colgroup', 'valueList', 'control', - 'checkbox' + 'checkbox', + 'dateFormat' ] export const TEXTLIKE_ELEMENT_TYPE: ElementType[] = [ @@ -55,5 +56,6 @@ export const TEXTLIKE_ELEMENT_TYPE: ElementType[] = [ ElementType.HYPERLINK, ElementType.SUBSCRIPT, ElementType.SUPERSCRIPT, - ElementType.CONTROL + ElementType.CONTROL, + ElementType.DATE ] \ No newline at end of file diff --git a/src/editor/dataset/enum/Element.ts b/src/editor/dataset/enum/Element.ts index f7490dc..972654f 100644 --- a/src/editor/dataset/enum/Element.ts +++ b/src/editor/dataset/enum/Element.ts @@ -10,5 +10,6 @@ export enum ElementType { CONTROL = 'control', CHECKBOX = 'checkbox', LATEX = 'latex', - TAB = 'tab' + TAB = 'tab', + DATE = 'date' } \ No newline at end of file diff --git a/src/editor/interface/Element.ts b/src/editor/interface/Element.ts index 0121b6e..8279961 100644 --- a/src/editor/interface/Element.ts +++ b/src/editor/interface/Element.ts @@ -69,6 +69,11 @@ export interface ILaTexElement { laTexSVG?: string; } +export interface IDateElement { + dateFormat?: string; + dateId?: string; +} + export type IElement = IElementBasic & IElementStyle & ITable @@ -78,6 +83,7 @@ export type IElement = IElementBasic & IControlElement & ICheckboxElement & ILaTexElement + & IDateElement export interface IElementMetrics { width: number; diff --git a/src/editor/utils/element.ts b/src/editor/utils/element.ts index cc53a44..65f771c 100644 --- a/src/editor/utils/element.ts +++ b/src/editor/utils/element.ts @@ -72,6 +72,31 @@ export function formatElementList(elementList: IElement[], options: IFormatEleme } } i-- + } else if (el.type === ElementType.DATE) { + const valueList = el.valueList || [] + // 移除父节点 + elementList.splice(i, 1) + // 追加字节点 + if (valueList.length) { + // 元素展开 + if (valueList[0].value.length > 1) { + const deleteValue = valueList.splice(0, 1)[0] + const deleteTextList = splitText(deleteValue.value) + for (let d = 0; d < deleteTextList.length; d++) { + valueList.splice(d, 0, { ...deleteValue, value: deleteTextList[d] }) + } + } + const dateId = getUUID() + for (let v = 0; v < valueList.length; v++) { + const value = valueList[v] + value.type = el.type + value.dateFormat = el.dateFormat + value.dateId = dateId + elementList.splice(i, 0, value) + i++ + } + } + i-- } else if (el.type === ElementType.CONTROL) { const { prefix, postfix, value, placeholder, code, type, valueSets } = el.control! const controlId = getUUID() @@ -302,6 +327,27 @@ export function zipElementList(payload: IElement[]): IElement[] { } hyperlinkElement.valueList = zipElementList(valueList) element = hyperlinkElement + } else if (element.type === ElementType.DATE) { + const dateId = element.dateId + const dateElement: IElement = { + type: ElementType.DATE, + value: '', + dateFormat: element.dateFormat + } + const valueList: IElement[] = [] + while (e < elementList.length) { + const dateE = elementList[e] + if (dateId !== dateE.dateId) { + e-- + break + } + delete dateE.type + delete dateE.dateFormat + valueList.push(dateE) + e++ + } + dateElement.valueList = zipElementList(valueList) + element = dateElement } else if (element.type === ElementType.CONTROL) { // 控件处理 const controlId = element.controlId diff --git a/src/mock.ts b/src/mock.ts index 7958818..0924fcc 100644 --- a/src/mock.ts +++ b/src/mock.ts @@ -279,6 +279,20 @@ elementList.push(...[{ value: '\n' }]) +// 日期选择 +elementList.push(...[{ + value: '签署日期:' +}, +{ + value: '', + valueList: [{ + value: `2022-08-10 17:30:01` + }], + type: ElementType.DATE +}, { + value: '\n' +}]) + // 模拟结尾文本 elementList.push(...[{ value: '', From f52f05cb3c7e1717aa562c53420ed2e1bf271e05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BA=91=E9=A3=9E?= Date: Tue, 16 Aug 2022 18:34:52 +0800 Subject: [PATCH 2/9] feat:add date picker pure logic code --- src/editor/assets/css/date/datePicker.css | 7 + src/editor/assets/css/index.css | 1 + src/editor/core/draw/Draw.ts | 6 +- .../core/draw/particle/date/DateParticle.ts | 21 ++ .../core/draw/particle/date/DatePicker.ts | 223 ++++++++++++++++++ src/editor/core/event/CanvasEvent.ts | 8 + 6 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 src/editor/assets/css/date/datePicker.css create mode 100644 src/editor/core/draw/particle/date/DatePicker.ts diff --git a/src/editor/assets/css/date/datePicker.css b/src/editor/assets/css/date/datePicker.css new file mode 100644 index 0000000..1917dac --- /dev/null +++ b/src/editor/assets/css/date/datePicker.css @@ -0,0 +1,7 @@ +.date-container { + display: none; +} + +.date-container.active { + display: block; +} \ No newline at end of file diff --git a/src/editor/assets/css/index.css b/src/editor/assets/css/index.css index eb68cf1..1720cf1 100644 --- a/src/editor/assets/css/index.css +++ b/src/editor/assets/css/index.css @@ -1,4 +1,5 @@ @import './control/select.css'; +@import './date/datePicker.css'; .inputarea { width: 0; diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts index 4aa098a..44613b1 100644 --- a/src/editor/core/draw/Draw.ts +++ b/src/editor/core/draw/Draw.ts @@ -132,7 +132,7 @@ export class Draw { this.waterMark = new Watermark(this) this.header = new Header(this) this.hyperlinkParticle = new HyperlinkParticle(this) - this.dateParticle = new DateParticle() + this.dateParticle = new DateParticle(this) this.separatorParticle = new SeparatorParticle() this.pageBreakParticle = new PageBreakParticle(this) this.superscriptParticle = new SuperscriptParticle() @@ -376,6 +376,10 @@ export class Draw { return this.hyperlinkParticle } + public getDateParticle(): DateParticle { + return this.dateParticle + } + public getControl(): Control { return this.control } diff --git a/src/editor/core/draw/particle/date/DateParticle.ts b/src/editor/core/draw/particle/date/DateParticle.ts index 98f0722..dadec21 100644 --- a/src/editor/core/draw/particle/date/DateParticle.ts +++ b/src/editor/core/draw/particle/date/DateParticle.ts @@ -1,7 +1,28 @@ +import { IElement, IElementPosition } from '../../../../interface/Element' import { IRowElement } from '../../../../interface/Row' +import { Draw } from '../../Draw' +import { DatePicker } from './DatePicker' export class DateParticle { + private datePicker: DatePicker + + constructor(draw: Draw) { + this.datePicker = new DatePicker({ + mountDom: draw.getContainer() + }) + } + + public clearDatePicker() { + this.datePicker.dispose() + } + + public renderDatePicker(element: IElement, position: IElementPosition) { + console.log('element: ', element) + console.log('position: ', position) + this.datePicker.render() + } + public render(ctx: CanvasRenderingContext2D, element: IRowElement, x: number, y: number) { ctx.save() ctx.font = element.style diff --git a/src/editor/core/draw/particle/date/DatePicker.ts b/src/editor/core/draw/particle/date/DatePicker.ts new file mode 100644 index 0000000..8b9e78a --- /dev/null +++ b/src/editor/core/draw/particle/date/DatePicker.ts @@ -0,0 +1,223 @@ +export interface IDatePickerOption { + mountDom?: HTMLElement +} + +interface IDatePickerDom { + container: HTMLDivElement; + title: { + preYear: HTMLSpanElement; + preMonth: HTMLSpanElement; + now: HTMLSpanElement; + nextMonth: HTMLSpanElement; + nextYear: HTMLSpanElement; + }; + day: HTMLDivElement; + menu: { + time: HTMLButtonElement; + now: HTMLButtonElement; + submit: HTMLButtonElement; + }; +} + +export class DatePicker { + + private options: IDatePickerOption + private now: Date + private dom: IDatePickerDom + + constructor(options: IDatePickerOption = {}) { + this.options = { + mountDom: document.body, + ...options + } + this.now = new Date() + this.dom = this._createDom() + this._bindEvent() + } + + private _createDom(): IDatePickerDom { + const datePickerContainer = document.createElement('div') + datePickerContainer.classList.add('date-container') + // title-切换年月、年月显示 + const datePickerTitle = document.createElement('div') + datePickerTitle.classList.add('date-title') + const preYearTitle = document.createElement('span') + preYearTitle.classList.add('date-title__pre-year') + preYearTitle.innerText = `<<` + const preMonthTitle = document.createElement('span') + preMonthTitle.classList.add('date-title__pre-month') + preMonthTitle.innerText = `<` + const nowTitle = document.createElement('span') + nowTitle.classList.add('date-title__now') + const nextMonthTitle = document.createElement('span') + nextMonthTitle.classList.add('date-title__next-month') + nextMonthTitle.innerText = `>` + const nextYearTitle = document.createElement('span') + nextYearTitle.classList.add('date-title__next-year') + nextYearTitle.innerText = `>>` + datePickerTitle.append(preYearTitle) + datePickerTitle.append(preMonthTitle) + datePickerTitle.append(nowTitle) + datePickerTitle.append(nextMonthTitle) + datePickerTitle.append(nextYearTitle) + // week-星期显示 + const datePickerWeek = document.createElement('div') + datePickerWeek.classList.add('date-week') + const weekList = ['日', '一', '二', '三', '四', '五', '六'] + weekList.forEach(week => { + const weekDom = document.createElement('span') + weekDom.innerText = `${week}` + datePickerWeek.append(weekDom) + }) + // day-天数显示 + const datePickerDay = document.createElement('div') + datePickerDay.classList.add('date-day') + // menu-选择时间、现在、确定 + const datePickerMenu = document.createElement('div') + datePickerMenu.classList.add('date-menu') + const timeMenu = document.createElement('button') + timeMenu.classList.add('date-menu__time') + timeMenu.innerText = '时间' + const nowMenu = document.createElement('button') + nowMenu.classList.add('date-menu__now') + nowMenu.innerText = '此刻' + const submitMenu = document.createElement('button') + submitMenu.classList.add('date-menu__submit') + submitMenu.innerText = '确定' + datePickerMenu.append(timeMenu) + datePickerMenu.append(nowMenu) + datePickerMenu.append(submitMenu) + // 构建 + datePickerContainer.append(datePickerTitle) + datePickerContainer.append(datePickerWeek) + datePickerContainer.append(datePickerDay) + datePickerContainer.append(datePickerMenu) + this.options.mountDom!.append(datePickerContainer) + return { + container: datePickerContainer, + title: { + preYear: preMonthTitle, + preMonth: preMonthTitle, + now: nowTitle, + nextMonth: nextMonthTitle, + nextYear: nextYearTitle + }, + day: datePickerDay, + menu: { + time: timeMenu, + now: nowMenu, + submit: submitMenu + } + } + } + + private _bindEvent() { + this.dom.title.preYear.onclick = () => { + this._preYear() + } + this.dom.title.preMonth.onclick = () => { + this._preMonth() + } + this.dom.title.nextMonth.onclick = () => { + this._nextMonth() + } + this.dom.title.nextYear.onclick = () => { + this._nextYear() + } + this.dom.menu.time.onclick = () => { + this._now() + } + this.dom.menu.submit.onclick = () => { + this.dispose() + } + } + + private _setNow() { + this.now = new Date() + } + + private _update() { + // 当前年月日 + const year = this.now.getFullYear() + const month = this.now.getMonth() + 1 + const day = this.now.getDate() + this.dom.title.now.innerText = `${year}年 ${String(month).padStart(2, '0')}月` + // 日期补差 + const curDate = new Date(year, month, 0) // 当月日期 + const curDay = curDate.getDate() // 当月总天数 + let curWeek = new Date(year, month - 1, 1).getDay() // 当月第一天星期几 + if (curWeek === 0) { + curWeek = 7 + } + const preDay = new Date(year, month - 1, 0).getDate() // 上个月天数 + // 渲染上个月日期 + const preStartDay = preDay - curWeek + 1 + for (let i = preStartDay; i <= preDay; i++) { + const dayDom = document.createElement('div') + dayDom.classList.add('disable') + dayDom.innerText = `${i}` + this.dom.day.append(dayDom) + } + // 渲染当月日期 + for (let i = 1; i <= curDay; i++) { + const dayDom = document.createElement('div') + if (i === day) { + dayDom.classList.add('active') + } + dayDom.innerText = `${i}` + this.dom.day.append(dayDom) + } + // 渲染下月日期 + const nextEndDay = 6 * 7 - curWeek - curDay + for (let i = 1; i <= nextEndDay; i++) { + const dayDom = document.createElement('div') + dayDom.classList.add('disable') + dayDom.innerText = `${i}` + this.dom.day.append(dayDom) + } + } + + private _preMonth() { + this.now.setMonth(this.now.getMonth() - 1) + this._update() + } + + private _nextMonth() { + this.now.setMonth(this.now.getMonth() + 1) + this._update() + } + + private _preYear() { + this.now.setFullYear(this.now.getFullYear() - 1) + this._update() + } + + private _nextYear() { + this.now.setFullYear(this.now.getFullYear() + 1) + this._update() + } + + private _now() { + this.now = new Date() + this._update() + } + + private _toggleVisible(isVisible: boolean) { + if (isVisible) { + this.dom.container.classList.add('active') + } else { + this.dom.container.classList.remove('active') + } + } + + public render() { + this._setNow() + this._update() + this._toggleVisible(true) + } + + public dispose() { + this._toggleVisible(false) + } + +} \ No newline at end of file diff --git a/src/editor/core/event/CanvasEvent.ts b/src/editor/core/event/CanvasEvent.ts index bed2cae..3f8793e 100644 --- a/src/editor/core/event/CanvasEvent.ts +++ b/src/editor/core/event/CanvasEvent.ts @@ -21,6 +21,7 @@ import { CheckboxControl } from '../draw/control/checkbox/CheckboxControl' import { splitText } from '../../utils' import { Previewer } from '../draw/particle/previewer/Previewer' import { DeepRequired } from '../../interface/Common' +import { DateParticle } from '../draw/particle/date/DateParticle' export class CanvasEvent { @@ -39,6 +40,7 @@ export class CanvasEvent { private previewer: Previewer private tableTool: TableTool private hyperlinkParticle: HyperlinkParticle + private dateParticle: DateParticle private listener: Listener private control: Control @@ -58,6 +60,7 @@ export class CanvasEvent { this.previewer = this.draw.getPreviewer() this.tableTool = this.draw.getTableTool() this.hyperlinkParticle = this.draw.getHyperlinkParticle() + this.dateParticle = this.draw.getDateParticle() this.listener = this.draw.getListener() this.control = this.draw.getControl() } @@ -284,6 +287,11 @@ export class CanvasEvent { if (curElement.type === ElementType.HYPERLINK) { this.hyperlinkParticle.drawHyperlinkPopup(curElement, positionList[curIndex]) } + // 日期控件 + this.dateParticle.clearDatePicker() + if (curElement.type === ElementType.DATE) { + this.dateParticle.renderDatePicker(curElement, positionList[curIndex]) + } } public mouseleave(evt: MouseEvent) { From 60740e1cf0e13916312c7a4ca724940b41f14a25 Mon Sep 17 00:00:00 2001 From: Hufe921 Date: Tue, 16 Aug 2022 23:15:57 +0800 Subject: [PATCH 3/9] feat: date picker event --- .../core/draw/particle/date/DatePicker.ts | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/editor/core/draw/particle/date/DatePicker.ts b/src/editor/core/draw/particle/date/DatePicker.ts index 8b9e78a..dad1b60 100644 --- a/src/editor/core/draw/particle/date/DatePicker.ts +++ b/src/editor/core/draw/particle/date/DatePicker.ts @@ -96,7 +96,7 @@ export class DatePicker { return { container: datePickerContainer, title: { - preYear: preMonthTitle, + preYear: preYearTitle, preMonth: preMonthTitle, now: nowTitle, nextMonth: nextMonthTitle, @@ -124,7 +124,7 @@ export class DatePicker { this.dom.title.nextYear.onclick = () => { this._nextYear() } - this.dom.menu.time.onclick = () => { + this.dom.menu.now.onclick = () => { this._now() } this.dom.menu.submit.onclick = () => { @@ -137,6 +137,10 @@ export class DatePicker { } private _update() { + // 本地年月 + const localDate = new Date() + const localYear = localDate.getFullYear() + const localMonth = localDate.getMonth() + 1 // 当前年月日 const year = this.now.getFullYear() const month = this.now.getMonth() + 1 @@ -150,21 +154,30 @@ export class DatePicker { curWeek = 7 } const preDay = new Date(year, month - 1, 0).getDate() // 上个月天数 + this.dom.day.innerHTML = '' // 渲染上个月日期 const preStartDay = preDay - curWeek + 1 for (let i = preStartDay; i <= preDay; i++) { const dayDom = document.createElement('div') dayDom.classList.add('disable') dayDom.innerText = `${i}` + dayDom.onclick = () => { + this.now = new Date(year, month - 2, i) + this.dispose() + } this.dom.day.append(dayDom) } // 渲染当月日期 for (let i = 1; i <= curDay; i++) { const dayDom = document.createElement('div') - if (i === day) { + if (localYear === year && localMonth === month && i === day) { dayDom.classList.add('active') } dayDom.innerText = `${i}` + dayDom.onclick = () => { + this.now = new Date(year, month - 1, i) + this.dispose() + } this.dom.day.append(dayDom) } // 渲染下月日期 @@ -173,6 +186,10 @@ export class DatePicker { const dayDom = document.createElement('div') dayDom.classList.add('disable') dayDom.innerText = `${i}` + dayDom.onclick = () => { + this.now = new Date(year, month, i) + this.dispose() + } this.dom.day.append(dayDom) } } @@ -218,6 +235,7 @@ export class DatePicker { public dispose() { this._toggleVisible(false) + return this.now } } \ No newline at end of file From 687d36d548c5fc3671d45d07af754f457bb87cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BA=91=E9=A3=9E?= Date: Wed, 17 Aug 2022 18:11:28 +0800 Subject: [PATCH 4/9] feat:create date picker dom --- src/editor/assets/css/date/datePicker.css | 208 ++++++++++++++++++ .../core/draw/particle/date/DateParticle.ts | 55 ++++- .../core/draw/particle/date/DatePicker.ts | 123 ++++++++++- 3 files changed, 373 insertions(+), 13 deletions(-) diff --git a/src/editor/assets/css/date/datePicker.css b/src/editor/assets/css/date/datePicker.css index 1917dac..ffdad15 100644 --- a/src/editor/assets/css/date/datePicker.css +++ b/src/editor/assets/css/date/datePicker.css @@ -1,7 +1,215 @@ .date-container { display: none; + width: 300px; + overflow: hidden; + left: 0; + right: 0; + position: absolute; + color: #606266; + background: #ffffff; + border-radius: 4px; + padding: 10px; + user-select: none; + border: 1px solid #e4e7ed; + box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); } .date-container.active { display: block; +} + +.date-wrap { + display: none; +} + +.date-wrap.active { + display: block; +} + +.date-title { + display: flex; + justify-content: center; + align-items: center; + text-align: center; + color: #606266; + font-size: 16px; +} + +.date-title>span { + display: inline-block; +} + +.date-title>span:not(.date-title__now) { + font-family: cursive; + cursor: pointer; +} + +.date-title>span:not(.date-title__now):hover { + color: #5175F4; +} + +.date-title .date-title__pre-year { + width: 15%; +} + +.date-title .date-title__pre-month { + width: 15%; +} + +.date-title .date-title__now { + width: 40%; +} + +.date-title .date-title__next-year { + width: 15%; +} + +.date-title .date-title__next-month { + width: 15%; +} + +.date-week { + width: 100%; + display: flex; + justify-content: center; + margin-top: 15px; + padding-bottom: 5px; + border-bottom: 1px solid #e4e7ed; +} + +.date-week>span { + list-style: none; + width: calc(100%/7); + text-align: center; + color: #606266; + font-size: 14px; +} + +.date-day { + width: 100%; + display: flex; + flex-wrap: wrap; + align-items: center; + margin-top: 5px; +} + +.date-day>div { + width: calc(100%/7); + height: 40px; + text-align: center; + color: #606266; + font-size: 14px; + cursor: pointer; + line-height: 40px; + border-radius: 4px; +} + +.date-day>div:hover { + color: #5175F4; + opacity: .8; +} + +.date-day>div.active { + color: #5175F4; + font-weight: 700; +} + +.date-day>div.disable { + color: #c0c4cc; +} + +.date-day>div.select { + color: #fff; + background-color: #5175F4; +} + +.time-wrap { + display: none; + padding: 10px; + height: 286px; +} + +.time-wrap ::-webkit-scrollbar { + width: 0; +} + +.time-wrap.active { + display: flex; +} + +.time-wrap li { + list-style: none; +} + +.time-wrap>li { + width: 33.3%; + height: 100%; + text-align: center; +} + +.time-wrap>li>span { + transform: translateY(-5px); + display: inline-block; +} + +.time-wrap>li>ol { + height: calc(100% - 20px); + overflow-y: auto; + border: 1px solid #e2e2e2; +} + +.time-wrap>li:first-child>ol { + border-right: 0; +} + +.time-wrap>li:last-child>ol { + border-left: 0; +} + +.time-wrap>li>ol>li { + line-height: 30px; +} + +.date-menu { + width: 100%; + height: 28px; + display: flex; + justify-content: flex-end; + align-items: center; + padding-top: 10px; + position: relative; + border-top: 1px solid #e4e7ed; +} + +.date-menu button { + display: inline-block; + line-height: 1; + white-space: nowrap; + cursor: pointer; + background: #fff; + border: 1px solid #dcdfe6; + color: #606266; + appearance: none; + text-align: center; + box-sizing: border-box; + outline: none; + margin: 0; + transition: .1s; + font-weight: 500; + user-select: none; + padding: 7px 15px; + font-size: 12px; + border-radius: 3px; + margin-left: 10px; +} + +.date-menu button.date-menu__time { + border: 1px solid transparent; + position: absolute; + left: 0; + margin-left: 0; +} + +.date-menu button.date-menu__time:hover { + color: #5175F4; } \ No newline at end of file diff --git a/src/editor/core/draw/particle/date/DateParticle.ts b/src/editor/core/draw/particle/date/DateParticle.ts index dadec21..c62270e 100644 --- a/src/editor/core/draw/particle/date/DateParticle.ts +++ b/src/editor/core/draw/particle/date/DateParticle.ts @@ -1,26 +1,75 @@ +import { ElementType } from '../../../../dataset/enum/Element' import { IElement, IElementPosition } from '../../../../interface/Element' import { IRowElement } from '../../../../interface/Row' +import { RangeManager } from '../../../range/RangeManager' import { Draw } from '../../Draw' import { DatePicker } from './DatePicker' export class DateParticle { + private draw: Draw + private range: RangeManager private datePicker: DatePicker constructor(draw: Draw) { + this.draw = draw + this.range = draw.getRange() this.datePicker = new DatePicker({ mountDom: draw.getContainer() }) } + public getDateElementList(): IElement[] { + let leftIndex = -1 + let rightIndex = -1 + const { startIndex, endIndex } = this.range.getRange() + if (!~startIndex && !~endIndex) return [] + const elementList = this.draw.getElementList() + const startElement = elementList[startIndex] + if (startElement.type !== ElementType.DATE) return [] + // 向左查找 + let preIndex = startIndex + while (preIndex > 0) { + const preElement = elementList[preIndex] + if (preElement.dateId !== startElement.dateId) { + leftIndex = preIndex + break + } + preIndex-- + } + // 向右查找 + let nextIndex = startIndex + 1 + while (nextIndex < elementList.length) { + const nextElement = elementList[nextIndex] + if (nextElement.dateId !== startElement.dateId) { + rightIndex = nextIndex - 1 + break + } + nextIndex++ + } + // 控件在最后 + if (nextIndex === elementList.length) { + rightIndex = nextIndex - 1 + } + if (!~leftIndex || !~rightIndex) return [] + return elementList.slice(leftIndex + 1, rightIndex + 1) + } + public clearDatePicker() { this.datePicker.dispose() } public renderDatePicker(element: IElement, position: IElementPosition) { - console.log('element: ', element) - console.log('position: ', position) - this.datePicker.render() + const height = this.draw.getHeight() + const pageGap = this.draw.getPageGap() + const startTop = this.draw.getPageNo() * (height + pageGap) + const value = this.getDateElementList().map(el => el.value).join('') + this.datePicker.render({ + value, + element, + position, + startTop + }) } public render(ctx: CanvasRenderingContext2D, element: IRowElement, x: number, y: number) { diff --git a/src/editor/core/draw/particle/date/DatePicker.ts b/src/editor/core/draw/particle/date/DatePicker.ts index dad1b60..09a2683 100644 --- a/src/editor/core/draw/particle/date/DatePicker.ts +++ b/src/editor/core/draw/particle/date/DatePicker.ts @@ -1,9 +1,13 @@ +import { IElement, IElementPosition } from '../../../../interface/Element' + export interface IDatePickerOption { mountDom?: HTMLElement } interface IDatePickerDom { container: HTMLDivElement; + dateWrap: HTMLDivElement; + timeWrap: HTMLUListElement; title: { preYear: HTMLSpanElement; preMonth: HTMLSpanElement; @@ -12,6 +16,11 @@ interface IDatePickerDom { nextYear: HTMLSpanElement; }; day: HTMLDivElement; + time: { + hour: HTMLOListElement; + minute: HTMLOListElement; + second: HTMLOListElement; + }; menu: { time: HTMLButtonElement; now: HTMLButtonElement; @@ -19,11 +28,20 @@ interface IDatePickerDom { }; } +interface IRenderOption { + value: string; + element: IElement; + position: IElementPosition; + startTop: number; +} + export class DatePicker { private options: IDatePickerOption private now: Date private dom: IDatePickerDom + private renderOptions: IRenderOption | null + private isDatePicker: boolean constructor(options: IDatePickerOption = {}) { this.options = { @@ -32,6 +50,8 @@ export class DatePicker { } this.now = new Date() this.dom = this._createDom() + this.renderOptions = null + this.isDatePicker = true this._bindEvent() } @@ -39,6 +59,8 @@ export class DatePicker { const datePickerContainer = document.createElement('div') datePickerContainer.classList.add('date-container') // title-切换年月、年月显示 + const dateWrap = document.createElement('div') + dateWrap.classList.add('date-wrap') const datePickerTitle = document.createElement('div') datePickerTitle.classList.add('date-title') const preYearTitle = document.createElement('span') @@ -72,12 +94,47 @@ export class DatePicker { // day-天数显示 const datePickerDay = document.createElement('div') datePickerDay.classList.add('date-day') + // 日期内容构建 + dateWrap.append(datePickerTitle) + dateWrap.append(datePickerWeek) + dateWrap.append(datePickerDay) + // time-时间选择 + const timeWrap = document.createElement('ul') + timeWrap.classList.add('time-wrap') + let hourTime: HTMLOListElement + let minuteTime: HTMLOListElement + let secondTime: HTMLOListElement + const timeList = ['时', '分', '秒'] + timeList.forEach((t, i) => { + const li = document.createElement('li') + const timeText = document.createElement('span') + timeText.innerText = t + li.append(timeText) + const ol = document.createElement('ol') + const isHour = i === 0 + const isMinute = i === 1 + const endIndex = isHour ? 24 : 60 + for (let i = 0; i < endIndex; i++) { + const time = document.createElement('li') + time.innerText = `${String(i).padStart(2, '0')}` + ol.append(time) + } + if (isHour) { + hourTime = ol + } else if (isMinute) { + minuteTime = ol + } else { + secondTime = ol + } + li.append(ol) + timeWrap.append(li) + }) // menu-选择时间、现在、确定 const datePickerMenu = document.createElement('div') datePickerMenu.classList.add('date-menu') const timeMenu = document.createElement('button') timeMenu.classList.add('date-menu__time') - timeMenu.innerText = '时间' + timeMenu.innerText = '时间选择' const nowMenu = document.createElement('button') nowMenu.classList.add('date-menu__now') nowMenu.innerText = '此刻' @@ -88,13 +145,14 @@ export class DatePicker { datePickerMenu.append(nowMenu) datePickerMenu.append(submitMenu) // 构建 - datePickerContainer.append(datePickerTitle) - datePickerContainer.append(datePickerWeek) - datePickerContainer.append(datePickerDay) + datePickerContainer.append(dateWrap) + datePickerContainer.append(timeWrap) datePickerContainer.append(datePickerMenu) this.options.mountDom!.append(datePickerContainer) return { container: datePickerContainer, + dateWrap, + timeWrap, title: { preYear: preYearTitle, preMonth: preMonthTitle, @@ -103,6 +161,11 @@ export class DatePicker { nextYear: nextYearTitle }, day: datePickerDay, + time: { + hour: hourTime!, + minute: minuteTime!, + second: secondTime! + }, menu: { time: timeMenu, now: nowMenu, @@ -124,6 +187,10 @@ export class DatePicker { this.dom.title.nextYear.onclick = () => { this._nextYear() } + this.dom.menu.time.onclick = () => { + this.isDatePicker = !this.isDatePicker + this._toggleDateTimePicker() + } this.dom.menu.now.onclick = () => { this._now() } @@ -132,15 +199,32 @@ export class DatePicker { } } + private _setPosition() { + if (!this.renderOptions) return + const { + position: { + coordinate: { + leftTop: [left, top] + }, + lineHeight + }, + startTop + } = this.renderOptions + // 位置 + this.dom.container.style.left = `${left}px` + this.dom.container.style.top = `${top + startTop + lineHeight}px` + } + private _setNow() { this.now = new Date() } private _update() { - // 本地年月 + // 本地年月日 const localDate = new Date() const localYear = localDate.getFullYear() const localMonth = localDate.getMonth() + 1 + const localDay = localDate.getDate() // 当前年月日 const year = this.now.getFullYear() const month = this.now.getMonth() + 1 @@ -163,20 +247,23 @@ export class DatePicker { dayDom.innerText = `${i}` dayDom.onclick = () => { this.now = new Date(year, month - 2, i) - this.dispose() + this._update() } this.dom.day.append(dayDom) } // 渲染当月日期 for (let i = 1; i <= curDay; i++) { const dayDom = document.createElement('div') - if (localYear === year && localMonth === month && i === day) { + if (localYear === year && localMonth === month && localDay === i) { dayDom.classList.add('active') } + if (i === day) { + dayDom.classList.add('select') + } dayDom.innerText = `${i}` dayDom.onclick = () => { this.now = new Date(year, month - 1, i) - this.dispose() + this._update() } this.dom.day.append(dayDom) } @@ -188,12 +275,24 @@ export class DatePicker { dayDom.innerText = `${i}` dayDom.onclick = () => { this.now = new Date(year, month, i) - this.dispose() + this._update() } this.dom.day.append(dayDom) } } + private _toggleDateTimePicker() { + if (this.isDatePicker) { + this.dom.dateWrap.classList.add('active') + this.dom.timeWrap.classList.remove('active') + this.dom.menu.time.innerText = `时间选择` + } else { + this.dom.dateWrap.classList.remove('active') + this.dom.timeWrap.classList.add('active') + this.dom.menu.time.innerText = `返回日期` + } + } + private _preMonth() { this.now.setMonth(this.now.getMonth() - 1) this._update() @@ -227,9 +326,13 @@ export class DatePicker { } } - public render() { + public render(option: IRenderOption) { + this.renderOptions = option this._setNow() this._update() + this._setPosition() + this.isDatePicker = true + this._toggleDateTimePicker() this._toggleVisible(true) } From 81d3b4ccee9d6af0befbf92c62250ac93a9f3afd Mon Sep 17 00:00:00 2001 From: Hufe921 Date: Wed, 17 Aug 2022 22:22:46 +0800 Subject: [PATCH 5/9] feat:add time pick for date picker --- src/editor/assets/css/date/datePicker.css | 11 ++ .../core/draw/particle/date/DatePicker.ts | 105 +++++++++++++++--- src/editor/core/event/CanvasEvent.ts | 3 +- src/editor/dataset/constant/Element.ts | 4 +- 4 files changed, 108 insertions(+), 15 deletions(-) diff --git a/src/editor/assets/css/date/datePicker.css b/src/editor/assets/css/date/datePicker.css index ffdad15..7fce570 100644 --- a/src/editor/assets/css/date/datePicker.css +++ b/src/editor/assets/css/date/datePicker.css @@ -168,6 +168,17 @@ .time-wrap>li>ol>li { line-height: 30px; + cursor: pointer; + transition: all .3s; +} + +.time-wrap>li>ol>li:hover { + background-color: #eaeaea; +} + +.time-wrap>li>ol>li.active { + color: #ffffff; + background: #5175F4; } .date-menu { diff --git a/src/editor/core/draw/particle/date/DatePicker.ts b/src/editor/core/draw/particle/date/DatePicker.ts index 09a2683..444c8bd 100644 --- a/src/editor/core/draw/particle/date/DatePicker.ts +++ b/src/editor/core/draw/particle/date/DatePicker.ts @@ -42,6 +42,7 @@ export class DatePicker { private dom: IDatePickerDom private renderOptions: IRenderOption | null private isDatePicker: boolean + private pickDate: Date | null constructor(options: IDatePickerOption = {}) { this.options = { @@ -52,6 +53,7 @@ export class DatePicker { this.dom = this._createDom() this.renderOptions = null this.isDatePicker = true + this.pickDate = null this._bindEvent() } @@ -117,6 +119,7 @@ export class DatePicker { for (let i = 0; i < endIndex; i++) { const time = document.createElement('li') time.innerText = `${String(i).padStart(2, '0')}` + time.setAttribute('data-id', `${i}`) ol.append(time) } if (isHour) { @@ -197,6 +200,30 @@ export class DatePicker { this.dom.menu.submit.onclick = () => { this.dispose() } + this.dom.time.hour.onclick = (evt) => { + if (!this.pickDate) return + const li = evt.target + const id = li.dataset.id + if (!id) return + this.pickDate.setHours(Number(id)) + this._setTimePick(false) + } + this.dom.time.minute.onclick = (evt) => { + if (!this.pickDate) return + const li = evt.target + const id = li.dataset.id + if (!id) return + this.pickDate.setMinutes(Number(id)) + this._setTimePick(false) + } + this.dom.time.second.onclick = (evt) => { + if (!this.pickDate) return + const li = evt.target + const id = li.dataset.id + if (!id) return + this.pickDate.setSeconds(Number(id)) + this._setTimePick(false) + } } private _setPosition() { @@ -215,8 +242,19 @@ export class DatePicker { this.dom.container.style.top = `${top + startTop + lineHeight}px` } - private _setNow() { - this.now = new Date() + public isInvalidDate(value: Date): boolean { + return value.toDateString() === 'Invalid Date' + } + + private _setValue() { + const value = this.renderOptions?.value + if (value) { + const setDate = new Date(value) + this.now = this.isInvalidDate(setDate) ? new Date() : setDate + } else { + this.now = new Date() + } + this.pickDate = new Date(this.now) } private _update() { @@ -225,10 +263,18 @@ export class DatePicker { const localYear = localDate.getFullYear() const localMonth = localDate.getMonth() + 1 const localDay = localDate.getDate() + // 选择年月日 + let pickYear: number | null = null + let pickMonth: number | null = null + let pickDay: number | null = null + if (this.pickDate) { + pickYear = this.pickDate.getFullYear() + pickMonth = this.pickDate.getMonth() + 1 + pickDay = this.pickDate.getDate() + } // 当前年月日 const year = this.now.getFullYear() const month = this.now.getMonth() + 1 - const day = this.now.getDate() this.dom.title.now.innerText = `${year}年 ${String(month).padStart(2, '0')}月` // 日期补差 const curDate = new Date(year, month, 0) // 当月日期 @@ -246,8 +292,9 @@ export class DatePicker { dayDom.classList.add('disable') dayDom.innerText = `${i}` dayDom.onclick = () => { - this.now = new Date(year, month - 2, i) - this._update() + const newMonth = month - 2 + this.now = new Date(year, newMonth, i) + this._setDatePick(year, newMonth, i) } this.dom.day.append(dayDom) } @@ -257,13 +304,14 @@ export class DatePicker { if (localYear === year && localMonth === month && localDay === i) { dayDom.classList.add('active') } - if (i === day) { + if (this.pickDate && pickYear === year && pickMonth === month && pickDay === i) { dayDom.classList.add('select') } dayDom.innerText = `${i}` dayDom.onclick = () => { - this.now = new Date(year, month - 1, i) - this._update() + const newMonth = month - 1 + this.now = new Date(year, newMonth, i) + this._setDatePick(year, newMonth, i) } this.dom.day.append(dayDom) } @@ -275,7 +323,7 @@ export class DatePicker { dayDom.innerText = `${i}` dayDom.onclick = () => { this.now = new Date(year, month, i) - this._update() + this._setDatePick(year, month, i) } this.dom.day.append(dayDom) } @@ -290,9 +338,40 @@ export class DatePicker { this.dom.dateWrap.classList.remove('active') this.dom.timeWrap.classList.add('active') this.dom.menu.time.innerText = `返回日期` + // 设置时分秒选择 + this._setTimePick() } } + private _setDatePick(year: number, month: number, day: number) { + this.now = new Date(year, month, day) + this.pickDate?.setFullYear(year) + this.pickDate?.setMonth(month) + this.pickDate?.setDate(day) + this._update() + } + + private _setTimePick(isIntoView = true) { + const hour = this.pickDate?.getHours() || 0 + const minute = this.pickDate?.getMinutes() || 0 + const second = this.pickDate?.getSeconds() || 0 + const { hour: hourDom, minute: minuteDom, second: secondDom } = this.dom.time + const timeDomList = [hourDom, minuteDom, secondDom] + // 清空 + timeDomList.forEach(timeDom => { + timeDom.querySelectorAll('li') + .forEach(li => li.classList.remove('active')) + }) + const pickList: [HTMLOListElement, number][] = [[hourDom, hour], [minuteDom, minute], [secondDom, second]] + pickList.forEach(([dom, time]) => { + const pickDom = dom.querySelector(`[data-id='${time}']`)! + pickDom.classList.add('active') + if (isIntoView) { + pickDom.scrollIntoView() + } + }) + } + private _preMonth() { this.now.setMonth(this.now.getMonth() - 1) this._update() @@ -314,8 +393,8 @@ export class DatePicker { } private _now() { - this.now = new Date() - this._update() + this.pickDate = new Date() + this.dispose() } private _toggleVisible(isVisible: boolean) { @@ -328,7 +407,7 @@ export class DatePicker { public render(option: IRenderOption) { this.renderOptions = option - this._setNow() + this._setValue() this._update() this._setPosition() this.isDatePicker = true @@ -338,7 +417,7 @@ export class DatePicker { public dispose() { this._toggleVisible(false) - return this.now + return this.pickDate } } \ No newline at end of file diff --git a/src/editor/core/event/CanvasEvent.ts b/src/editor/core/event/CanvasEvent.ts index 3f8793e..df33b05 100644 --- a/src/editor/core/event/CanvasEvent.ts +++ b/src/editor/core/event/CanvasEvent.ts @@ -527,7 +527,7 @@ export class CanvasEvent { return } const activeControl = this.control.getActiveControl() - const { TEXT, HYPERLINK, SUBSCRIPT, SUPERSCRIPT } = ElementType + const { TEXT, HYPERLINK, SUBSCRIPT, SUPERSCRIPT, DATE } = ElementType const text = data.replaceAll(`\n`, ZERO) const elementList = this.draw.getElementList() const agentDom = this.cursor.getAgentDom() @@ -553,6 +553,7 @@ export class CanvasEvent { element.type === TEXT || (!element.type && element.value !== ZERO) || (element.type === HYPERLINK && nextElement?.type === HYPERLINK) + || (element.type === DATE && nextElement?.type === DATE) || (element.type === SUBSCRIPT && nextElement?.type === SUBSCRIPT) || (element.type === SUPERSCRIPT && nextElement?.type === SUPERSCRIPT) ) { diff --git a/src/editor/dataset/constant/Element.ts b/src/editor/dataset/constant/Element.ts index b1d59fd..4725e30 100644 --- a/src/editor/dataset/constant/Element.ts +++ b/src/editor/dataset/constant/Element.ts @@ -24,7 +24,9 @@ export const EDITOR_ELEMENT_COPY_ATTR: Array = [ 'strikeout', 'rowFlex', 'url', - 'hyperlinkId' + 'hyperlinkId', + 'dateId', + 'dateFormat' ] export const EDITOR_ELEMENT_ZIP_ATTR: Array = [ From 460c9bcbaa0c4dc6a14f22a5c81ab8efc0494213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BA=91=E9=A3=9E?= Date: Thu, 18 Aug 2022 14:06:28 +0800 Subject: [PATCH 6/9] feat:date picker and editor debug --- src/editor/assets/css/date/datePicker.css | 5 ++ .../core/draw/particle/date/DateParticle.ts | 40 +++++++++++++--- .../core/draw/particle/date/DatePicker.ts | 46 +++++++++++++++++-- 3 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/editor/assets/css/date/datePicker.css b/src/editor/assets/css/date/datePicker.css index 7fce570..9ec3583 100644 --- a/src/editor/assets/css/date/datePicker.css +++ b/src/editor/assets/css/date/datePicker.css @@ -214,6 +214,11 @@ margin-left: 10px; } +.date-menu button:hover { + color: #5175F4; + border-color: #5175F4; +} + .date-menu button.date-menu__time { border: 1px solid transparent; position: absolute; diff --git a/src/editor/core/draw/particle/date/DateParticle.ts b/src/editor/core/draw/particle/date/DateParticle.ts index c62270e..7e5180e 100644 --- a/src/editor/core/draw/particle/date/DateParticle.ts +++ b/src/editor/core/draw/particle/date/DateParticle.ts @@ -15,18 +15,40 @@ export class DateParticle { this.draw = draw this.range = draw.getRange() this.datePicker = new DatePicker({ - mountDom: draw.getContainer() + mountDom: draw.getContainer(), + onSubmit: this._setValue.bind(this) }) } - public getDateElementList(): IElement[] { + private _setValue(date: string) { + if (!date) return + const range = this.getDateElementRange() + if (!range) return + const [leftIndex, rightIndex] = range + const elementList = this.draw.getElementList() + const startElement = elementList[leftIndex + 1] + // 删除旧时间 + elementList.splice(leftIndex + 1, rightIndex - leftIndex) + this.range.setRange(leftIndex, leftIndex) + // 插入新时间 + this.draw.insertElementList([{ + type: ElementType.DATE, + value: '', + dateFormat: startElement.dateFormat, + valueList: [{ + value: date + }] + }]) + } + + public getDateElementRange(): [number, number] | null { let leftIndex = -1 let rightIndex = -1 const { startIndex, endIndex } = this.range.getRange() - if (!~startIndex && !~endIndex) return [] + if (!~startIndex && !~endIndex) return null const elementList = this.draw.getElementList() const startElement = elementList[startIndex] - if (startElement.type !== ElementType.DATE) return [] + if (startElement.type !== ElementType.DATE) return null // 向左查找 let preIndex = startIndex while (preIndex > 0) { @@ -51,8 +73,8 @@ export class DateParticle { if (nextIndex === elementList.length) { rightIndex = nextIndex - 1 } - if (!~leftIndex || !~rightIndex) return [] - return elementList.slice(leftIndex + 1, rightIndex + 1) + if (!~leftIndex || !~rightIndex) return null + return [leftIndex, rightIndex] } public clearDatePicker() { @@ -63,7 +85,11 @@ export class DateParticle { const height = this.draw.getHeight() const pageGap = this.draw.getPageGap() const startTop = this.draw.getPageNo() * (height + pageGap) - const value = this.getDateElementList().map(el => el.value).join('') + const elementList = this.draw.getElementList() + const range = this.getDateElementRange() + const value = range + ? elementList.slice(range[0] + 1, range[1] + 1).map(el => el.value).join('') + : '' this.datePicker.render({ value, element, diff --git a/src/editor/core/draw/particle/date/DatePicker.ts b/src/editor/core/draw/particle/date/DatePicker.ts index 444c8bd..e3ea616 100644 --- a/src/editor/core/draw/particle/date/DatePicker.ts +++ b/src/editor/core/draw/particle/date/DatePicker.ts @@ -1,7 +1,8 @@ import { IElement, IElementPosition } from '../../../../interface/Element' export interface IDatePickerOption { - mountDom?: HTMLElement + mountDom?: HTMLElement; + onSubmit?: (date: string) => any; } interface IDatePickerDom { @@ -32,7 +33,7 @@ interface IRenderOption { value: string; element: IElement; position: IElementPosition; - startTop: number; + startTop?: number; } export class DatePicker { @@ -196,9 +197,11 @@ export class DatePicker { } this.dom.menu.now.onclick = () => { this._now() + this._submit() } this.dom.menu.submit.onclick = () => { this.dispose() + this._submit() } this.dom.time.hour.onclick = (evt) => { if (!this.pickDate) return @@ -239,7 +242,7 @@ export class DatePicker { } = this.renderOptions // 位置 this.dom.container.style.left = `${left}px` - this.dom.container.style.top = `${top + startTop + lineHeight}px` + this.dom.container.style.top = `${top + (startTop || 0) + lineHeight}px` } public isInvalidDate(value: Date): boolean { @@ -308,10 +311,11 @@ export class DatePicker { dayDom.classList.add('select') } dayDom.innerText = `${i}` - dayDom.onclick = () => { + dayDom.onclick = (evt) => { const newMonth = month - 1 this.now = new Date(year, newMonth, i) this._setDatePick(year, newMonth, i) + evt.stopPropagation() } this.dom.day.append(dayDom) } @@ -405,6 +409,39 @@ export class DatePicker { } } + private _submit() { + if (this.options.onSubmit && this.pickDate) { + const format = this.renderOptions?.element.dateFormat + const pickDateString = this.formatDate(this.pickDate, format) + this.options.onSubmit(pickDateString) + } + } + + public formatDate(date: Date, format = 'yyyy-MM-dd hh:mm:ss'): string { + let dateString = format + const dateOption = { + 'y+': date.getFullYear().toString(), + 'M+': (date.getMonth() + 1).toString(), + 'd+': date.getDate().toString(), + 'h+': date.getHours().toString(), + 'm+': date.getMinutes().toString(), + 's+': date.getSeconds().toString() + } + for (const k in dateOption) { + const reg = new RegExp('(' + k + ')').exec(format) + const key = k + if (reg) { + dateString = dateString.replace( + reg[1], + reg[1].length === 1 + ? (dateOption[key]) + : (dateOption[key].padStart(reg[1].length, '0')) + ) + } + } + return dateString + } + public render(option: IRenderOption) { this.renderOptions = option this._setValue() @@ -417,7 +454,6 @@ export class DatePicker { public dispose() { this._toggleVisible(false) - return this.pickDate } } \ No newline at end of file From 3958eca9eade0e8d63314dce8edf71554b67c275 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BA=91=E9=A3=9E?= Date: Thu, 18 Aug 2022 18:50:46 +0800 Subject: [PATCH 7/9] feat:date picker scroll time into view --- .../core/draw/particle/date/DatePicker.ts | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/editor/core/draw/particle/date/DatePicker.ts b/src/editor/core/draw/particle/date/DatePicker.ts index e3ea616..4bbf79e 100644 --- a/src/editor/core/draw/particle/date/DatePicker.ts +++ b/src/editor/core/draw/particle/date/DatePicker.ts @@ -368,14 +368,36 @@ export class DatePicker { }) const pickList: [HTMLOListElement, number][] = [[hourDom, hour], [minuteDom, minute], [secondDom, second]] pickList.forEach(([dom, time]) => { - const pickDom = dom.querySelector(`[data-id='${time}']`)! + const pickDom = dom.querySelector(`[data-id='${time}']`)! pickDom.classList.add('active') if (isIntoView) { - pickDom.scrollIntoView() + this._scrollIntoView(dom, pickDom) } }) } + private _scrollIntoView(container: HTMLElement, selected: HTMLElement) { + if (!selected) { + container.scrollTop = 0 + return + } + const offsetParents: HTMLElement[] = [] + let pointer = selected.offsetParent + while (pointer && container !== pointer && container.contains(pointer)) { + offsetParents.push(pointer) + pointer = pointer.offsetParent + } + const top = selected.offsetTop + offsetParents.reduce((prev, curr) => (prev + curr.offsetTop), 0) + const bottom = top + selected.offsetHeight + const viewRectTop = container.scrollTop + const viewRectBottom = viewRectTop + container.clientHeight + if (top < viewRectTop) { + container.scrollTop = top + } else if (bottom > viewRectBottom) { + container.scrollTop = bottom - container.clientHeight + } + } + private _preMonth() { this.now.setMonth(this.now.getMonth() - 1) this._update() From 9d140627f3a59c90686fdde5dc0383cfcb4fe434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E4=BA=91=E9=A3=9E?= Date: Thu, 18 Aug 2022 18:51:33 +0800 Subject: [PATCH 8/9] feat:add date menu --- index.html | 9 +++++ src/assets/images/date.svg | 1 + src/editor/assets/css/date/datePicker.css | 1 + src/main.ts | 44 ++++++++++++++++++++++- src/style.css | 16 +++++++-- 5 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/assets/images/date.svg diff --git a/index.html b/index.html index 9a8fc0c..3e5d89c 100644 --- a/index.html +++ b/index.html @@ -176,6 +176,15 @@ +