Skip to content

Commit 0faae5d

Browse files
authored
Merge pull request #1684 from DevCloudFE/dev
chore: update main from dev
2 parents b4175ac + 75cfddb commit 0faae5d

File tree

11 files changed

+126
-22
lines changed

11 files changed

+126
-22
lines changed

packages/devui-vue/devui/avatar/src/avatar.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import './avatar.scss';
88
export default defineComponent({
99
name: 'DAvatar',
1010
props: avatarProps,
11-
setup(props: AvatarProps) {
11+
emits: ['loadError'],
12+
setup(props: AvatarProps, ctx) {
1213
const { name, width, height, customText, gender, imgSrc, isRound } = toRefs(props);
1314
const isNobody = ref<boolean>(true);
1415
const isErrorImg = ref<boolean>(false);
@@ -71,8 +72,9 @@ export default defineComponent({
7172
getBackgroundColor(nameValue.substr(0, 1));
7273
};
7374

74-
const showErrorAvatar = (): void => {
75+
const showErrorAvatar = (e: Event): void => {
7576
isErrorImg.value = true;
77+
ctx.emit('loadError', e);
7678
};
7779

7880
const calcValues = (nameInput: string): void => {
@@ -142,7 +144,7 @@ export default defineComponent({
142144
<AvatarNoBodyIcon width={width.value} height={height.value} />
143145
</span>
144146
);
145-
const noBody = (!imgSrc.value && isNobody.value) || isErrorImg.value ? noBodyElement : null;
147+
const noBody = (!imgSrc.value && isNobody.value) || (imgSrc.value && isErrorImg.value) ? noBodyElement : null;
146148
return (
147149
<span class={ns.b()}>
148150
{hasImgSrc}

packages/devui-vue/devui/editor-md/src/composables/use-editor-md.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import cloneDeep from 'lodash-es/cloneDeep';
12
import { computed, nextTick, onMounted, reactive, Ref, ref, SetupContext, toRefs, watch } from 'vue';
23
import { debounce } from '../../../shared/utils';
34
import { EditorMdProps, Mode } from '../editor-md-types';
@@ -20,7 +21,7 @@ export function useEditorMd(props: EditorMdProps, ctx: SetupContext) {
2021
modelValue,
2122
} = toRefs(props);
2223

23-
const toolbars = reactive(DEFAULT_TOOLBARS);
24+
const toolbars = reactive(cloneDeep(DEFAULT_TOOLBARS));
2425
const editorRef = ref();
2526
const renderRef = ref();
2627
const previewHtmlList: Ref<any[]> = ref([]);
@@ -289,7 +290,12 @@ export function useEditorMd(props: EditorMdProps, ctx: SetupContext) {
289290
if (toolbars['image'].params) {
290291
toolbars['image'].params.imageUploadToServer = val;
291292
}
292-
});
293+
if (toolbars['image'].params && !toolbars['image'].params.imageUpload) {
294+
toolbars['image'].params.imageUpload = (data: any) => {
295+
ctx.emit('imageUpload', data);
296+
}
297+
}
298+
}, { immediate: true });
293299

294300
watch(hidePreviewView, () => {
295301
refreshEditorCursor();

packages/devui-vue/devui/editor-md/src/editor-md.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import './editor-md.scss';
1111
export default defineComponent({
1212
name: 'DEditorMd',
1313
props: editorMdProps,
14-
emits: ['update:modelValue', 'mdCheckedEvent', 'selectHint', 'afterEditorInit', 'contentChange', 'previewContentChange'],
14+
emits: ['update:modelValue', 'mdCheckedEvent', 'selectHint', 'afterEditorInit', 'contentChange', 'previewContentChange', 'imageUpload'],
1515
setup(props: EditorMdProps, ctx: SetupContext) {
1616
const {
1717
mode,
@@ -64,7 +64,7 @@ export default defineComponent({
6464
class={[
6565
'dp-md-container',
6666
{ 'dp-md-readonly': mode.value === 'readonly', 'dp-md-editonly': mode.value === 'editonly', 'dp-md-dark': isDarkMode.value },
67-
]}>
67+
]} onPaste={onPaste}>
6868
<div class="dp-md-toolbar-container">
6969
<Toolbar />
7070
</div>

packages/devui-vue/devui/editor-md/src/toolbar-config.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,6 @@ class ToolBarHandler {
181181
const stopEventPropagation = (e: any): void => {
182182
e.stopPropagation();
183183
};
184-
185184
if (typeof document !== 'undefined' && params.imageUploadToServer) {
186185
let imageUploader = document.getElementById('markdown_image_upload_input');
187186
if (imageUploader) {
@@ -201,7 +200,7 @@ class ToolBarHandler {
201200
};
202201
imageUploader.onchange = (e: any) => {
203202
const file = e.target['files'][0];
204-
params.imageUpload.emit({ file, callback });
203+
params.imageUpload({ file, callback });
205204
};
206205
imageUploader.click();
207206
} else {
@@ -391,7 +390,8 @@ export const DEFAULT_TOOLBARS: Record<string, IToolbarItemConfig> = {
391390
type: 'button',
392391
icon: IMAGE_ICON,
393392
shortKey: 'Ctrl+G',
394-
handler: ToolBarHandler.link,
393+
params: { imageUploadToServer: false },
394+
handler: ToolBarHandler.image,
395395
},
396396
file: {
397397
id: 'file',

packages/devui-vue/devui/fullscreen/index.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ export { Fullscreen };
77

88
export default {
99
title: 'Fullscreen 全屏',
10-
category: '通用',
11-
status: '100%',
10+
category: '基础组件',
1211
install(app: App): void {
1312
app.component(Fullscreen.name, Fullscreen);
14-
}
13+
},
1514
};

packages/devui-vue/devui/fullscreen/src/composables/use-fullscreen.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export default function useFullscreen(props: FullscreenProps, slotElement: Ref<H
4545

4646
const handleFullscreenChange = () => {
4747
if (!document.fullscreenElement) {
48-
ctx.emit('update:modelValue');
48+
ctx.emit('update:modelValue', false);
4949

5050
exitByKeydown = true;
5151
} else {
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import type { PropType, ExtractPropTypes } from 'vue';
22

3-
type ModeType = PropType<'normal' | 'immersive'>;
3+
export type ModeType = 'immersive' | 'normal';
44
export const fullscreenProps = {
55
modelValue: {
66
type: Boolean,
77
default: false,
88
},
99
mode: {
10-
type: String as ModeType,
10+
type: String as PropType<ModeType>,
1111
default: 'normal'
1212
},
1313
zIndex: {
1414
type: Number,
1515
default: 10
16-
}
16+
},
1717
} as const;
1818

1919
export type FullscreenProps = ExtractPropTypes<typeof fullscreenProps>;

packages/devui-vue/devui/fullscreen/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { FullscreenProps } from './fullscreen-types';
2-
import { useNamespace } from '../../shared/hooks/use-namespace';
2+
import { useNamespace } from '@devui/shared/utils';
33

44
interface CompatibleHTMLElement extends HTMLElement {
55
mozRequestFullScreen?: () => void;

packages/devui-vue/docs/components/avatar/index.md

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
<d-avatar name="1Avatar"></d-avatar>
2222
</div>
2323
</template>
24-
2524
<style>
2625
.avatar-demo-1 .devui-avatar {
2726
margin-right: 10px;
@@ -33,7 +32,7 @@
3332

3433
### 头像的基础配置
3534

36-
头像组件可设置宽度,高度,是否为圆形头像,同时可自定义头像的显示字段,传入自定义图片等
35+
头像组件可设置宽度,高度,是否为圆形头像,同时可自定义头像的显示字段,传入自定义图片,图片加载失败控制内容显示等
3736

3837
:::demo
3938

@@ -43,9 +42,31 @@
4342
<d-avatar name="Avatar" :width="28" :height="28"></d-avatar>
4443
<d-avatar customText="DevUI" :width="80" :height="80" :isRound="false"></d-avatar>
4544
<d-avatar imgSrc="/../../assets/logo.svg" :width="100" :height="100" :isRound="false"></d-avatar>
45+
<d-avatar :name="name" :imgSrc="src" :width="28" :height="28" @load-error="onLoadError"></d-avatar>
4646
</div>
4747
</template>
4848
49+
<script>
50+
import { defineComponent, ref } from 'vue';
51+
52+
export default defineComponent({
53+
setup() {
54+
const src = ref('123.com/assets/logo.svg');
55+
const name = ref('Avatar');
56+
57+
const onLoadError = (e) => {
58+
console.log(e);
59+
src.value = '';
60+
}
61+
return {
62+
src,
63+
name,
64+
onLoadError
65+
};
66+
},
67+
});
68+
</script>
69+
4970
<style>
5071
.avatar-demo-2 {
5172
display: flex;
@@ -94,6 +115,11 @@
94115
| img-src | `string` | -- | 可选,传入自定义图片作为头像 | [头像的基础配置](#头像的基础配置) |
95116
| custom-text | `string` | -- | 可选,传入自定义显示文字 | [头像的基础配置](#头像的基础配置) |
96117

118+
### Avatar 事件
119+
| 事件 | 说明 | 跳转 Demo |
120+
| :----: | :--------------------------------------: | :-------------------: |
121+
| load-error | img加载失败后的事件抛出 | [头像的基础配置](#头像的基础配置) |
122+
97123
### 其他说明
98124

99125
#### 头像显示基本规则

packages/devui-vue/docs/components/editor-md/index.md

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,76 @@ export default defineComponent({
156156

157157
:::
158158

159+
### 配置图片文件上传
160+
161+
:::demo 设置imageUploadToServer后,编辑器对粘贴操作也将进行监听,若有图片也将触发imageUpload事件。
162+
163+
```vue
164+
<template>
165+
<d-editor-md
166+
v-model="content"
167+
:image-upload-to-server="true"
168+
@content-change="valueChange"
169+
@image-upload="imageUpload"
170+
></d-editor-md>
171+
</template>
172+
173+
<script>
174+
import { defineComponent, reactive, ref } from 'vue';
175+
176+
export default defineComponent({
177+
setup() {
178+
const content = ref('`Not use ngModel`');
179+
180+
const valueChange = (val) => {
181+
console.log(val);
182+
};
183+
184+
const imageUpload = ({file, callback}) => {
185+
let message;
186+
const rFilter = /^(image\/bmp|image\/gif|image\/jpge|image\/jpeg|image\/jpg|image\/png|image\/tiff)$/i;
187+
if (!rFilter.test(file.type)) {
188+
console.log(rFilter, file.type);
189+
message = 'Please choose bmp/jpg/jpge/png/gif/tiff type picture to upload';
190+
} else if (file.size / (1024 * 1024) > 1) {
191+
message = 'Please choose a picture smaller than 1M to upload';
192+
}
193+
194+
if (message) {
195+
// throw the error message by yourself
196+
return false;
197+
} else {
198+
new Promise((resolve) => {
199+
const xhr = new XMLHttpRequest();
200+
xhr.open('POST', 'https://xxx.xxx.com/v1/xxx');
201+
xhr.setRequestHeader('yourKey', 'yourValue');
202+
203+
xhr.addEventListener('load', (evt) => {
204+
const result = JSON.parse(xhr.responseText);
205+
resolve(result);
206+
}, false);
207+
208+
const fd = new FormData();
209+
fd.append('file', file);
210+
xhr.send(fd);
211+
}).then((res: any) => {
212+
if (res.status === 'success') {
213+
callback({ name: file.name, imgUrl: res['imgUrl'], title: res['imgTitle'] });
214+
} else {
215+
// throw your error message
216+
}
217+
});
218+
}
219+
}
220+
221+
return { content, valueChange, imageUpload };
222+
},
223+
});
224+
</script>
225+
```
226+
227+
:::
228+
159229
### EditorMd 参数
160230

161231
| 参数名 | 类型 | 默认值 | 说明 |
@@ -170,6 +240,7 @@ export default defineComponent({
170240
| custom-xss-rules | [ICustomXssRule[]](#icustomxssrule) | [] | 自定义 xss 对某种 tag 的过滤方式,每条规则需要指定 tag, 并给出需要加入白名单的属性数组 |
171241
| placeholder | `string` | '' | 编辑器无内容是的提示信息 |
172242
| fullscreen-z-index | `number` | 10 | 编辑器全屏状态的 z-index |
243+
| image-upload-to-server| `boolean` | false | 是否打开图片自定义上传开关(打开后将将监听图片的复制,toolbar图片功能上传,传出事件回调) |
173244

174245
### EditorMd 事件
175246

@@ -178,7 +249,7 @@ export default defineComponent({
178249
| after-editor-init | `Function(instance: object)` | 编辑器初始化事件,返回编辑器对象 | |
179250
| content-change | `Function(content: string)` | 编辑器内容改变事件,返回当前内容 | |
180251
| preview-content-change | `Function()` | 预览内容改变时触发 | |
181-
252+
| image-upload | `Function({file, callback})` | 打开图片上传开关后,图片上传事件回调,返回文件内容与callback函数 | |
182253
### MdRender 参数
183254

184255
| 参数名 | 类型 | 默认值 | 说明 | 跳转 Demo |

0 commit comments

Comments
 (0)