diff --git a/CHANGELOG.md b/CHANGELOG.md index 331662192b4076f434820421261aca25454417d4..15402e37b1dfc0c2ad8c2b6f56aabf5ad9b6c9eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ### Change +- 更新全局抽屉在关闭页面时同时也关闭自身 - 更新时间选择器使用的rolldate插件包为ibiz-mob-rolldate插件包 - 更新编辑器提供清除能力,更新富文本是否已折叠状态持久化,更新移动端列表如果支持排序,会给视图设置class - 返回顶部按钮、气泡工具栏按钮添加底部安全距离 diff --git a/src/common/md-ctrl-setting/md-ctrl-setting.tsx b/src/common/md-ctrl-setting/md-ctrl-setting.tsx index e5939efab1c625cbd06d5933016c603f1c020bba..363df1bdcc9ddead06eaa9c65a95a3bcf0f61a53 100644 --- a/src/common/md-ctrl-setting/md-ctrl-setting.tsx +++ b/src/common/md-ctrl-setting/md-ctrl-setting.tsx @@ -185,6 +185,7 @@ export const IBizMdCtrlSetting = defineComponent({ const renderPopup = () => { return ( { + visible.value = false; + }; + + // 监听popstate事件 + usePopstateListener(closeDrawer); return { c, @@ -398,6 +405,7 @@ export const CalendarControl = defineComponent({ )} - + { diff --git a/src/editor/data-picker/ibiz-picker/ibiz-picker.tsx b/src/editor/data-picker/ibiz-picker/ibiz-picker.tsx index dfbe092491a3fc31342a0a0b7d0d7e02fb5ca047..6ca2b09c7259c4441d99977a6a48e0d1db5de318 100644 --- a/src/editor/data-picker/ibiz-picker/ibiz-picker.tsx +++ b/src/editor/data-picker/ibiz-picker/ibiz-picker.tsx @@ -7,6 +7,7 @@ import { import './ibiz-picker.scss'; import { debounce, isEmpty } from 'lodash-es'; import { PickerEditorController } from '../picker-editor.controller'; +import { usePopstateListener } from '../../../util'; export const IBizPicker = defineComponent({ name: 'IBizPicker', @@ -323,6 +324,13 @@ export const IBizPicker = defineComponent({ ); }; + const closeDrawer = () => { + showPicker.value = false; + }; + + // 监听popstate事件 + usePopstateListener(closeDrawer); + return { ns, c, @@ -399,6 +407,7 @@ export const IBizPicker = defineComponent({ diff --git a/src/editor/date-picker/ibiz-date-picker/ibiz-date-picker.tsx b/src/editor/date-picker/ibiz-date-picker/ibiz-date-picker.tsx index 15145590e2d633e57c11041f3d312c8d6d8cbe37..0efdb28cf4875c0b67ce636215df2069fb0af844 100644 --- a/src/editor/date-picker/ibiz-date-picker/ibiz-date-picker.tsx +++ b/src/editor/date-picker/ibiz-date-picker/ibiz-date-picker.tsx @@ -10,6 +10,7 @@ import dayjs from 'dayjs'; import RollDate from 'ibiz-mob-rolldate'; import { DatePickerEditorController } from '../date-picker-editor.controller'; import { IBizCommonRightIcon } from '../../common/right-icon/right-icon'; +import { usePopstateListener } from '../../../util'; export const IBizDatePicker = defineComponent({ name: 'IBizDatePicker', @@ -107,6 +108,16 @@ export const IBizDatePicker = defineComponent({ } }; + // 页面关闭时关闭时间选择抽屉 + const closeDrawer = () => { + if (rollDateInstance.value) { + rollDateInstance.value.hide?.(); + } + }; + + // 监听popstate事件 + usePopstateListener(closeDrawer); + onMounted(() => { const el = editorRef.value; if (el) { diff --git a/src/editor/date-range/ibiz-date-range-picker/ibiz-date-range-picker.tsx b/src/editor/date-range/ibiz-date-range-picker/ibiz-date-range-picker.tsx index 92199eead8392b99039643fcdcd48a6361e544f4..1311ff027e657aba9901e899aa9c2c200afdb2cd 100644 --- a/src/editor/date-range/ibiz-date-range-picker/ibiz-date-range-picker.tsx +++ b/src/editor/date-range/ibiz-date-range-picker/ibiz-date-range-picker.tsx @@ -9,6 +9,7 @@ import './ibiz-date-range-picker.scss'; import RollDate from 'ibiz-mob-rolldate'; import dayjs from 'dayjs'; import { DateRangeEditorController } from '../date-range-editor.controller'; +import { usePopstateListener } from '../../../util'; export const IBizDateRangePicker = defineComponent({ name: 'IBizDateRangePicker', @@ -203,6 +204,14 @@ export const IBizDateRangePicker = defineComponent({ } }); + const closeDrawer = () => { + startEditorRef.value?.hide?.(); + endEditorRef.value?.hide?.(); + }; + + // 监听popstate事件 + usePopstateListener(closeDrawer); + // 绘制隐藏元素,用于撑开父元素高度,使输入框根据父元素自适应宽度 const expandHidden = (text: string) => { return {text}; diff --git a/src/editor/dropdown-list/ibiz-dropdown-list/ibiz-dropdown-list.tsx b/src/editor/dropdown-list/ibiz-dropdown-list/ibiz-dropdown-list.tsx index 26627e474971bae27071da2ab1b077f8a1b522d0..1291eaeb0282a2239ecd26d94dd651a86adcd414 100644 --- a/src/editor/dropdown-list/ibiz-dropdown-list/ibiz-dropdown-list.tsx +++ b/src/editor/dropdown-list/ibiz-dropdown-list/ibiz-dropdown-list.tsx @@ -8,6 +8,7 @@ import './ibiz-dropdown-list.scss'; import { DropDownListEditorController } from '../dropdown-list-editor.controller'; import { IBizCommonRightIcon } from '../../common/right-icon/right-icon'; import { IBizDataMPicker } from '../../common/data-mpicker/ibiz-data-mpicker'; +import { usePopstateListener } from '../../../util'; export const IBizDropdownList = defineComponent({ name: 'IBizDropdownList', @@ -94,6 +95,13 @@ export const IBizDropdownList = defineComponent({ return selectItems.value.map(item => item.text).join(','); }); + const closeDrawer = () => { + showPicker.value = false; + }; + + // 监听popstate事件 + usePopstateListener(closeDrawer); + return { ns, c, diff --git a/src/editor/dropdown-list/ibiz-dropdown/ibiz-dropdown.tsx b/src/editor/dropdown-list/ibiz-dropdown/ibiz-dropdown.tsx index 1d939d19f90139452d7b6d57762882a6ef5a3f71..75d630b4442804177084f72bc18f4b6db81d4de3 100644 --- a/src/editor/dropdown-list/ibiz-dropdown/ibiz-dropdown.tsx +++ b/src/editor/dropdown-list/ibiz-dropdown/ibiz-dropdown.tsx @@ -7,6 +7,7 @@ import { import './ibiz-dropdown.scss'; import { DropDownListEditorController } from '../dropdown-list-editor.controller'; import { IBizCommonRightIcon } from '../../common/right-icon/right-icon'; +import { usePopstateListener } from '../../../util'; export const IBizDropdown = defineComponent({ name: 'IBizDropdown', @@ -227,6 +228,13 @@ export const IBizDropdown = defineComponent({ ); }; + const closeDrawer = () => { + showPicker.value = false; + }; + + // 监听popstate事件 + usePopstateListener(closeDrawer); + return { ns, c, @@ -325,6 +333,7 @@ export const IBizDropdown = defineComponent({ diff --git a/src/editor/dropdown-list/ibiz-emoji-picker/ibiz-emoji-picker.tsx b/src/editor/dropdown-list/ibiz-emoji-picker/ibiz-emoji-picker.tsx index 5b88028abf5ef19b35bf932bbcc1065309d8744d..8c69abcb8c0afc2b7245b78ab3005a950d6d33de 100644 --- a/src/editor/dropdown-list/ibiz-emoji-picker/ibiz-emoji-picker.tsx +++ b/src/editor/dropdown-list/ibiz-emoji-picker/ibiz-emoji-picker.tsx @@ -7,6 +7,7 @@ import { import { base64ToStr, strToBase64, isEmoji } from '@ibiz-template/core'; import './ibiz-emoji-picker.scss'; import { DropDownListEditorController } from '../dropdown-list-editor.controller'; +import { usePopstateListener } from '../../../util'; export const IBizEmojiPicker = defineComponent({ name: 'IBizEmojiPicker', @@ -127,6 +128,13 @@ export const IBizEmojiPicker = defineComponent({ ); }; + const closeDrawer = () => { + visible.value = false; + }; + + // 监听popstate事件 + usePopstateListener(closeDrawer); + return { ns, c, @@ -142,7 +150,12 @@ export const IBizEmojiPicker = defineComponent({ render() { let content: JSX.Element | JSX.Element[] = [ this.renderReference(), - + diff --git a/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.scss b/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.scss index b9bb05e38f86da900c20a2967ee56a7059e758f3..abe2c5d6da9f7c88c00cb4a5f20516539ab053c4 100644 --- a/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.scss +++ b/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.scss @@ -14,6 +14,11 @@ $markdown: ( } } + @include b(markdown-image-popup){ + background-color: transparent; + overflow: visible; + } + @include b(markdown-dialog) { top: 50%; display: flex; diff --git a/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.tsx b/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.tsx index c7c53dfecc7083b61244383078ee0f1153774cae..6294d3571974dfdc1b8f24db3d3aeae5543857ff 100644 --- a/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.tsx +++ b/src/editor/markdown/ibiz-markdown-editor/ibiz-markdown-editor.tsx @@ -55,6 +55,9 @@ const IBizMarkDown: any = defineComponent({ // 编辑器模式 const defaultModel = ref('editOnly'); + // 预览态预览图片地址 + const previewImage: Ref = ref(''); + // 样式变量 const cssVars = ref({}); @@ -63,7 +66,12 @@ const IBizMarkDown: any = defineComponent({ () => props.data, newVal => { if (newVal) { - const urls = c.calcBaseUrl(newVal); + const urls = ibiz.util.file.calcFileUpDownUrl( + c.context, + c.params, + newVal, + c.editorParams, + ); uploadUrl.value = urls.uploadUrl; downloadUrl.value = urls.downloadUrl; } @@ -72,25 +80,14 @@ const IBizMarkDown: any = defineComponent({ ); // // 自定义图片上传 - const fileUpload = (file: Blob, callback: (_url: string) => void) => { - const formData = new FormData(); - formData.append('file', file); - ibiz.net - .axios({ - url: uploadUrl.value, - method: 'post', - headers: headers.value, - data: formData, - }) - .then((res: IData) => { - if (res.status === 200 && res.data.fileid) { - const url = downloadUrl.value.replace('%fileId%', res.data.fileid); - callback(url); - } - }) - .catch(error => { - ibiz.log.error('上传出错', error); - }); + const fileUpload = async (file: Blob, callback: (_url: string) => void) => { + const data = await ibiz.util.file.fileUpload( + uploadUrl.value, + file, + headers.value, + ); + const url = downloadUrl.value.replace('%fileId%', data.fileid); + callback(url); }; // 获取渲染后html内容 @@ -198,6 +195,7 @@ const IBizMarkDown: any = defineComponent({ }, }; + // 默认编辑态 const editorInit = () => { const cherryOptions = { id, @@ -212,6 +210,8 @@ const IBizMarkDown: any = defineComponent({ editor.value = new Cherry(cherryOptions as IData); }); }; + + // 初始界面预览态 const editorPreviewInit = () => { const cherryOptions = { id: previewId, @@ -241,15 +241,74 @@ const IBizMarkDown: any = defineComponent({ }); const isOpen = ref(false); - const openPicker = async () => { + // 计算触发元素类型 + const calcTargetType = ( + target: HTMLElement, + ): { + type: string; + url: string; + } => { + const result = { + type: '', + url: '', + }; + if (target.nodeName === 'A') { + result.type = 'A'; + result.url = (target as HTMLAnchorElement).hash; + } else if (target.parentNode && target.parentNode.nodeName === 'A') { + result.type = 'A'; + result.url = (target.parentNode as HTMLAnchorElement).hash; + } else if (target.nodeName === 'IMG') { + result.type = 'IMG'; + result.url = (target as HTMLImageElement).src; + } + return result; + }; + + const openPicker = async (event: TouchEvent) => { + // 如果点击项是a标签,并且有href,值为#开头,且后续值为页面内的元素的id,就走页面滚动导航 + // 如果是图片,则进行放大预览 + // 其他情况,就走打开编辑界面 + const { target } = event; + if (target) { + const result = calcTargetType(target as HTMLElement); + if (result.type === 'A' && result.url.startsWith('#')) { + // 点击a标签,本页面内滑动,阻止其他变化 + event.preventDefault(); + event.stopPropagation(); + const targetid = result.url.slice(1); + if (targetid) { + const preview = document.getElementById(previewId); + if (preview) { + const anchor = document.getElementById(targetid); + if (anchor) { + anchor.scrollIntoView({ behavior: 'smooth' }); + } + } + return; + } + } + if (result.type === 'IMG' && result.url) { + // 点击图片,展开预览 + previewImage.value = result.url; + return; + } + } if (props.disabled || props.readonly) { return; } + // 其他情况打开编辑态 isOpen.value = true; if (!editor.value) { editorInit(); } }; + + // 关闭图片预览时清除预览图片地址 + const handlePreviewClose = () => { + previewImage.value = ''; + }; + return { ns, currentVal, @@ -265,6 +324,8 @@ const IBizMarkDown: any = defineComponent({ setCherryContent, openPicker, isOpen, + previewImage, + handlePreviewClose, }; }, render() { @@ -288,7 +349,19 @@ const IBizMarkDown: any = defineComponent({ }} - + + + +
{}; + // 关闭飘窗 + const closeCurrentPopover = () => { + modal?.dismiss(); + }; + + onMounted(() => { + window.addEventListener('popstate', closeCurrentPopover); + }); + onUnmounted(() => { cleanUpAutoUpdate(); + window.removeEventListener('popstate', closeCurrentPopover); }); /** diff --git a/src/util/index.ts b/src/util/index.ts index 5b6160309d4358403d28219ac4a7fb4914bbdd39..6e8090c21e005183ef0e89362d3136c4ba843392 100644 --- a/src/util/index.ts +++ b/src/util/index.ts @@ -10,3 +10,4 @@ export { AppUtil } from './app-util/app-util'; export { usePagination } from './pagination/use-pagination'; export { FullscreenUtil } from './fullscreen/fullscreen-util'; export * from './store'; +export { usePopstateListener } from './use-popstate-util/use-popstate-util'; diff --git a/src/util/use-popstate-util/use-popstate-util.ts b/src/util/use-popstate-util/use-popstate-util.ts new file mode 100644 index 0000000000000000000000000000000000000000..6451e97bb60275c26192e712d49ba85a9a72d8af --- /dev/null +++ b/src/util/use-popstate-util/use-popstate-util.ts @@ -0,0 +1,19 @@ +import { onMounted, onBeforeUnmount } from 'vue'; + +/** + * 监听popstate事件 + * @param callback + */ +export const usePopstateListener = (callback: () => void): void => { + const handlePopstate = () => { + callback(); + }; + + onMounted(() => { + window.addEventListener('popstate', handlePopstate); + }); + + onBeforeUnmount(() => { + window.removeEventListener('popstate', handlePopstate); + }); +};