vue-editify 0.1.26 → 0.1.29

Sign up to get free protection for your applications and to get access to all the features.
package/src/core/tool.ts CHANGED
@@ -198,8 +198,15 @@ export type MenuConfigType = {
198
198
  extends?: MenuExtendType
199
199
  }
200
200
 
201
+ export type PluginMenuConfigType = {
202
+ extraDisabled?: ((name: string) => boolean) | null
203
+ sequence: number
204
+ extend: MenuCustomButtonType
205
+ }
206
+
201
207
  export type PluginResultType = {
202
- menu?: MenuConfigType
208
+ name: string
209
+ menu?: PluginMenuConfigType
203
210
  updateView?: () => void
204
211
  customParseNode?: (element: AlexElement) => AlexElement
205
212
  renderRule?: (el: AlexElement) => void
@@ -209,7 +216,9 @@ export type PluginResultType = {
209
216
 
210
217
  export type PluginType = (editifyInstance: ComponentInternalInstance, color: string | null, editTrans: (key: string) => any) => PluginResultType
211
218
 
212
- //粘贴html时保留的数据
219
+ /**
220
+ * 粘贴html时保留的数据
221
+ */
213
222
  export const pasteKeepData: ObjectType = {
214
223
  //粘贴html时元素保留的样式(全部元素)
215
224
  marks: {
@@ -237,7 +246,12 @@ export const pasteKeepData: ObjectType = {
237
246
  }
238
247
  }
239
248
 
240
- //对象平替值方法
249
+ /**
250
+ * 对象平替值方法
251
+ * @param o1
252
+ * @param o2
253
+ * @returns
254
+ */
241
255
  export const mergeObject = function (o1: ObjectType, o2: ObjectType) {
242
256
  if (!DapCommon.isObject(o1) && DapCommon.isObject(o2)) {
243
257
  return null
@@ -255,7 +269,13 @@ export const mergeObject = function (o1: ObjectType, o2: ObjectType) {
255
269
  return o1
256
270
  }
257
271
 
258
- //判断对象是否含有某个属性或者属性值是否一致
272
+ /**
273
+ * 判断对象是否含有某个属性或者属性值是否一致
274
+ * @param obj
275
+ * @param name
276
+ * @param value
277
+ * @returns
278
+ */
259
279
  export const queryHasValue = function (obj: ObjectType, name: string, value?: string | number) {
260
280
  //如果value不存在则判断是否拥有属性name
261
281
  if (value == null || value == undefined) {
@@ -296,7 +316,11 @@ export const queryHasValue = function (obj: ObjectType, name: string, value?: st
296
316
  return ownValue == value
297
317
  }
298
318
 
299
- //深拷贝函数
319
+ /**
320
+ * 深拷贝函数
321
+ * @param data
322
+ * @returns
323
+ */
300
324
  export const cloneData = function (data: any) {
301
325
  if (DapCommon.isObject(data) || Array.isArray(data)) {
302
326
  return JSON.parse(JSON.stringify(data))
@@ -304,7 +328,11 @@ export const cloneData = function (data: any) {
304
328
  return data
305
329
  }
306
330
 
307
- //根据行元素获取colgroup的col数量
331
+ /**
332
+ * 根据行元素获取colgroup的col数量
333
+ * @param row
334
+ * @returns
335
+ */
308
336
  export const getColNumbers = function (row: AlexElement) {
309
337
  const children = row.children || []
310
338
  let num = 0
@@ -321,7 +349,11 @@ export const getColNumbers = function (row: AlexElement) {
321
349
  return num
322
350
  }
323
351
 
324
- //获取菜单按钮列表数据配置
352
+ /**
353
+ * 获取菜单按钮列表数据配置
354
+ * @param editTrans
355
+ * @returns
356
+ */
325
357
  export const getButtonOptionsConfig = function (editTrans: (key: string) => any): ButtonOptionsConfigType {
326
358
  return {
327
359
  //标题配置
@@ -517,7 +549,12 @@ export const getButtonOptionsConfig = function (editTrans: (key: string) => any)
517
549
  }
518
550
  }
519
551
 
520
- //工具条全量配置
552
+ /**
553
+ * 工具条全量配置
554
+ * @param editTrans
555
+ * @param editLocale
556
+ * @returns
557
+ */
521
558
  export const getToolbarConfig = function (editTrans: (key: string) => any, editLocale: LocaleType): ToolbarConfigType {
522
559
  return {
523
560
  //是否使用工具条
@@ -762,7 +799,12 @@ export const getToolbarConfig = function (editTrans: (key: string) => any, editL
762
799
  }
763
800
  }
764
801
 
765
- //菜单栏全量配置
802
+ /**
803
+ * 菜单栏全量配置
804
+ * @param editTrans
805
+ * @param editLocale
806
+ * @returns
807
+ */
766
808
  export const getMenuConfig = function (editTrans: (key: string) => any, editLocale: LocaleType): MenuConfigType {
767
809
  return {
768
810
  //是否使用菜单栏
@@ -348,7 +348,7 @@
348
348
  color: @font-color-link;
349
349
  transition: all 200ms;
350
350
  position: relative;
351
- padding: 0 2px;
351
+ padding: 0 10px;
352
352
  font-size: 14px;
353
353
  vertical-align: baseline;
354
354
 
@@ -378,6 +378,7 @@
378
378
  &.editify-placeholder::before {
379
379
  cursor: auto;
380
380
  }
381
+
381
382
  :deep(a) {
382
383
  cursor: pointer;
383
384
  }
@@ -5,7 +5,7 @@
5
5
  <!-- 编辑层,与编辑区域宽高相同必须适配 -->
6
6
  <div ref="bodyRef" class="editify-body" :class="{ 'editify-border': showBorder, 'editify-menu_inner': menuConfig.use && menuConfig.mode == 'inner' }" :data-editify-uid="instance.uid">
7
7
  <!-- 编辑器 -->
8
- <div ref="contentRef" class="editify-content" :class="{ 'editify-placeholder': showPlaceholder, 'editify-disabled': disabled }" @keydown="handleEditorKeydown" @click="handleEditorClick" @compositionstart="isInputChinese = true" @compositionend="isInputChinese = false" :data-editify-placeholder="placeholder"></div>
8
+ <div ref="contentRef" class="editify-content" :class="{ 'editify-placeholder': showPlaceholder, 'editify-disabled': disabled }" @click="handleEditorClick" @compositionstart="isInputChinese = true" @compositionend="isInputChinese = false" :data-editify-placeholder="placeholder"></div>
9
9
  <!-- 代码视图 -->
10
10
  <textarea v-if="isSourceView" :value="value" readonly class="editify-sourceview" />
11
11
  <!-- 工具条 -->
@@ -41,12 +41,10 @@ const instance = getCurrentInstance()!
41
41
  //属性
42
42
  const props = defineProps(EditifyProps)
43
43
  //事件
44
- const emits = defineEmits(['update:modelValue', 'focus', 'blur', 'change', 'keydown', 'insertparagraph', 'rangeupdate', 'updateview'])
44
+ const emits = defineEmits(['update:modelValue', 'focus', 'blur', 'change', 'keydown', 'keyup', 'insertparagraph', 'rangeupdate', 'updateview'])
45
45
 
46
46
  //设置国际化方法
47
47
  const $editTrans = trans(props.locale || 'zh_CN')
48
- //对子孙后代组件提供国际化方法
49
- provide('$editTrans', $editTrans)
50
48
 
51
49
  //是否编辑器内部修改值
52
50
  const isModelChange = ref<boolean>(false)
@@ -135,15 +133,7 @@ const pluginResultList = computed<PluginResultType[]>(() => {
135
133
  })
136
134
  //最终生效的菜单栏配置
137
135
  const menuConfig = computed<MenuConfigType>(() => {
138
- let menu: MenuConfigType = {}
139
- //注册插件:自定义菜单栏
140
- pluginResultList.value.forEach(pluginResult => {
141
- menu = <MenuConfigType>mergeObject(menu, pluginResult.menu || {})
142
- })
143
- //加入自定义menu配置
144
- menu = <MenuConfigType>mergeObject(menu, props.menu || {})
145
- //返回最终配置
146
- return <MenuConfigType>mergeObject(getMenuConfig($editTrans, props.locale), menu)
136
+ return <MenuConfigType>mergeObject(getMenuConfig($editTrans, props.locale), props.menu || {})
147
137
  })
148
138
 
149
139
  //编辑器内部修改值的方法
@@ -303,6 +293,8 @@ const createEditor = () => {
303
293
  editor.value.on('change', handleEditorChange)
304
294
  editor.value.on('focus', handleEditorFocus)
305
295
  editor.value.on('blur', handleEditorBlur)
296
+ editor.value.on('keydown', handleEditorKeydown)
297
+ editor.value.on('keyup', handleEditorKeyup)
306
298
  editor.value.on('insertParagraph', handleInsertParagraph)
307
299
  editor.value.on('rangeUpdate', handleRangeUpdate)
308
300
  editor.value.on('deleteInStart', handleDeleteInStart)
@@ -522,7 +514,7 @@ const handleCustomParseNode = (ele: AlexElement) => {
522
514
  return ele
523
515
  }
524
516
  //编辑区域键盘按下:设置缩进快捷键
525
- const handleEditorKeydown = (e: Event) => {
517
+ const handleEditorKeydown = (val: string, e: Event) => {
526
518
  if (props.disabled) {
527
519
  return
528
520
  }
@@ -535,7 +527,15 @@ const handleEditorKeydown = (e: Event) => {
535
527
  editor.value!.rangeRender()
536
528
  }
537
529
  //自定义键盘按下操作
538
- emits('keydown', e)
530
+ emits('keydown', val, e)
531
+ }
532
+ //编辑区域键盘松开
533
+ const handleEditorKeyup = (val: string, e: Event) => {
534
+ if (props.disabled) {
535
+ return
536
+ }
537
+ //自定义键盘松开操作
538
+ emits('keyup', val, e)
539
539
  }
540
540
  //点击编辑器:处理图片和视频的光标聚集
541
541
  const handleEditorClick = (e: Event) => {
@@ -625,8 +625,8 @@ const handleEditorFocus = (val: string) => {
625
625
  const handleInsertParagraph = (element: AlexElement, previousElement: AlexElement) => {
626
626
  //两个元素不一致,则表示不在代码块样式内
627
627
  if (!element.isEqual(previousElement)) {
628
- //前一个块元素如果是只包含换行符的元素,并且当前块元素也是包含换行符的元素,则当前块元素转为段落
629
- if (previousElement.isOnlyHasBreak() && element.isOnlyHasBreak()) {
628
+ //前一个根级块元素如果是只包含换行符的元素,并且当前根级块元素也是包含换行符的元素,则当前根级块元素转为段落
629
+ if (previousElement.isBlock() && element.isBlock() && previousElement.isOnlyHasBreak() && element.isOnlyHasBreak()) {
630
630
  if (previousElement.parsedom != AlexElement.BLOCK_NODE) {
631
631
  elementToParagraph(previousElement)
632
632
  editor.value!.range!.anchor.moveToStart(previousElement)
@@ -674,6 +674,7 @@ const handleRangeUpdate = () => {
674
674
  }
675
675
  }
676
676
  }, 200)
677
+ //触发rangeupdate事件
677
678
  emits('rangeupdate')
678
679
  }
679
680
  //编辑器部分删除情景(在编辑器起始处)
@@ -830,6 +831,7 @@ onBeforeUnmount(() => {
830
831
  editor.value!.destroy()
831
832
  })
832
833
 
834
+ provide('$editTrans', $editTrans)
833
835
  provide('editify', instance)
834
836
  provide('isSourceView', isSourceView)
835
837
  provide('isFullScreen', isFullScreen)
@@ -837,6 +839,7 @@ provide('canUseMenu', canUseMenu)
837
839
  provide('editor', editor)
838
840
  provide('dataRangeCaches', dataRangeCaches)
839
841
  provide('showBorder', showBorder)
842
+ provide('pluginResultList', pluginResultList)
840
843
 
841
844
  defineExpose({
842
845
  editor,
package/src/hljs/index.ts CHANGED
@@ -74,7 +74,12 @@ export type LanguagesItemType = {
74
74
  value?: string
75
75
  }
76
76
 
77
- //获取经过hljs处理的html元素
77
+ /**
78
+ * 获取经过hljs处理的html元素
79
+ * @param code
80
+ * @param language
81
+ * @returns
82
+ */
78
83
  export const getHljsHtml = function (code: string, language: string) {
79
84
  if (language) {
80
85
  return hljs.highlight(code, {
@@ -84,7 +89,9 @@ export const getHljsHtml = function (code: string, language: string) {
84
89
  }
85
90
  return hljs.highlightAuto(code).value
86
91
  }
87
- //可选择语言列表
92
+ /**
93
+ * 可选择语言列表
94
+ */
88
95
  export const languages: LanguagesItemType[] = [
89
96
  {
90
97
  label: 'Plain Text',
package/src/index.ts CHANGED
@@ -9,7 +9,7 @@ export type { ButtonTypeType, ButtonOptionsItemType, ButtonSelectConfigType, But
9
9
  export type { InsertImageUploadErrorType } from './components/insertImage/props'
10
10
  export type { InsertVideoUploadErrorType } from './components/insertVideo/props'
11
11
  export type { MenuButtonType, MenuSelectButtonType, MenuDisplayButtonType, MenuImageButtonType, MenuVideoButtonType, MenuTableButtonType, MenuCustomButtonType, CodeBlockToolbarType, TextToolbarType, ToolbarConfigType, MenuSequenceType, MenuModeType, MenuExtendType, MenuConfigType, PluginType, PluginResultType } from './core/tool'
12
- //插件相关类型
12
+ //导出插件相关类型
13
13
  export type { AttachmentOptionsType } from './plugins/attachment'
14
14
  export type { InsertAttachmentUploadErrorType } from './plugins/attachment/insertAttachment/props'
15
15
 
@@ -21,13 +21,15 @@ const install: FunctionPlugin = (app: App) => {
21
21
  app.component(Editify.name!, Editify)
22
22
  }
23
23
  //版本号
24
- const version = '0.1.26'
24
+ const version = '0.1.29'
25
25
 
26
26
  //导出AlexElement元素
27
27
  export { AlexElement } from 'alex-editor'
28
28
 
29
+ //导出插件
30
+ export { attachment } from './plugins/attachment'
31
+
29
32
  //导出组件和安装函数
30
33
  export { install as default, install, Editify, version }
31
34
 
32
- //导出插件
33
- export { attachment } from './plugins/attachment'
35
+ console.log(`%c vue-editify %c v${version} `, 'padding: 2px 1px; border-radius: 3px 0 0 3px; color: #fff; background: #606060; font-weight: bold;', 'padding: 2px 1px; border-radius: 0 3px 3px 0; color: #fff; background: #42c02e; font-weight: bold;')
@@ -90,7 +90,8 @@ export const en_US: ObjectType = {
90
90
  insertAttachment: 'Insert attachment',
91
91
  uploadAttachment: 'Upload',
92
92
  remoteAttachment: 'Remote',
93
+ attachmentNamePlaceholder: 'Please enter the attachment name',
93
94
  attachmentUrlPlaceholder: 'Please enter the attachment address',
94
- downloadAttachment: 'Click to download attachment',
95
- attachmentDownloadName: 'attachment'
95
+ attachmentDownloadTitle: 'Click to download attachment',
96
+ attachmentDefaultName: 'attachment'
96
97
  }
@@ -1,10 +1,13 @@
1
1
  import { en_US } from './en_US'
2
2
  import { zh_CN } from './zh_CN'
3
3
 
4
- //语言类型
5
4
  export type LocaleType = 'zh_CN' | 'en_US'
6
5
 
7
- //翻译方法
6
+ /**
7
+ * 翻译方法
8
+ * @param locale
9
+ * @returns
10
+ */
8
11
  export const trans = (locale: LocaleType) => {
9
12
  return (key: string) => {
10
13
  return { zh_CN, en_US }[locale][key]
@@ -90,7 +90,8 @@ export const zh_CN: ObjectType = {
90
90
  insertAttachment: '插入附件',
91
91
  uploadAttachment: '上传附件',
92
92
  remoteAttachment: '远程地址',
93
- attachmentUrlPlaceholder: '请输入远程地址',
94
- downloadAttachment: '点击下载附件',
95
- attachmentDownloadName: '附件'
93
+ attachmentNamePlaceholder: '请输入附件名称',
94
+ attachmentUrlPlaceholder: '请输入附件地址',
95
+ attachmentDownloadTitle: '点击下载附件',
96
+ attachmentDefaultName: '附件'
96
97
  }
@@ -1,5 +1,5 @@
1
1
  import { ComponentInternalInstance, h } from 'vue'
2
- import { AlexEditor, AlexElement } from 'alex-editor'
2
+ import { AlexEditor, AlexElement, AlexElementsRangeType } from 'alex-editor'
3
3
  import { ObjectType, PluginType } from '../../core/tool'
4
4
  import Layer from '../../components/layer/layer.vue'
5
5
  import Button from '../../components/button/button.vue'
@@ -7,7 +7,7 @@ import Icon from '../../components/icon/icon.vue'
7
7
  import InsertAttachment from './insertAttachment/insertAttachment.vue'
8
8
  import { InsertAttachmentUploadErrorType } from './insertAttachment/props'
9
9
  import { event as DapEvent, common as DapCommon } from 'dap-util'
10
- import { hasPreInRange } from '../../core/function'
10
+ import { hasLinkInRange, hasPreInRange, hasQuoteInRange } from '../../core/function'
11
11
 
12
12
  export type AttachmentOptionsType = {
13
13
  //排序
@@ -19,7 +19,7 @@ export type AttachmentOptionsType = {
19
19
  //按钮是否显示右侧边框
20
20
  rightBorder?: boolean
21
21
  //定义可选择的文件类型,默认不限制类型,设定此参数后选择文件时会自动过滤非符合的文件类型
22
- accept?: 'rar' | 'zip' | 'txt' | 'image' | 'video' | 'audio' | 'html' | 'doc' | 'xml' | 'js' | 'json' | 'ppt' | 'pdf' | null
22
+ accept?: string
23
23
  //支持的类型数组
24
24
  allowedFileType?: string[]
25
25
  //是否多选
@@ -34,42 +34,90 @@ export type AttachmentOptionsType = {
34
34
  handleError?: (error: InsertAttachmentUploadErrorType, file: File) => void
35
35
  }
36
36
 
37
+ /**
38
+ * 元素是否附件
39
+ * @param element
40
+ * @returns
41
+ */
42
+ export const isAttachment = (element: AlexElement) => {
43
+ if (element.isEmpty()) {
44
+ return false
45
+ }
46
+ return element.parsedom == 'span' && element.type == 'closed' && element.hasMarks() && element.marks!['data-attachment']
47
+ }
48
+
49
+ /**
50
+ * 选区是否含有附件
51
+ * @param editor
52
+ * @param dataRangeCaches
53
+ * @returns
54
+ */
55
+ export const hasAttachmentInRange = (editor: AlexEditor, dataRangeCaches: AlexElementsRangeType) => {
56
+ if (!editor.range) {
57
+ return false
58
+ }
59
+ if (editor.range.anchor.isEqual(editor.range.focus)) {
60
+ return isAttachment(editor.range.anchor.element)
61
+ }
62
+ return dataRangeCaches.flatList.some(item => {
63
+ return isAttachment(item.element)
64
+ })
65
+ }
66
+
67
+ /**
68
+ * 附件插件
69
+ * @param options
70
+ * @returns
71
+ */
37
72
  export const attachment = (options?: AttachmentOptionsType) => {
38
73
  if (!DapCommon.isObject(options)) {
39
74
  options = {}
40
75
  }
41
76
  const plugin: PluginType = (editifyInstance: ComponentInternalInstance, color: string | null, editTrans: (key: string) => any) => {
77
+ let isDisabled = false
78
+ //如果光标范围内有链接、代码块和引用则禁用
79
+ if (editifyInstance.exposed!.editor.value) {
80
+ isDisabled = hasPreInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value) || hasLinkInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value) || hasQuoteInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value)
81
+ }
42
82
  return {
83
+ name: 'attachment',
43
84
  //附件菜单项配置
44
85
  menu: {
45
- sequence: {
46
- attachment: options!.sequence || 100
86
+ sequence: options!.sequence || 100,
87
+ extraDisabled: (name: string) => {
88
+ //如果光标选区内有附件则禁用链接菜单和引用菜单
89
+ if (name == 'link' || name == 'quote') {
90
+ return hasAttachmentInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value)
91
+ }
92
+ return false
47
93
  },
48
- extends: {
49
- attachment: {
50
- type: 'select',
51
- title: options!.title || editTrans('insertAttachment'),
52
- leftBorder: options!.leftBorder,
53
- rightBorder: options!.rightBorder,
54
- disabled: editifyInstance.exposed!.editor.value ? hasPreInRange(editifyInstance.exposed!.editor.value, editifyInstance.exposed!.dataRangeCaches.value) : false,
55
- default: () => h(Icon, { value: 'attachment' }),
56
- layer: (_name: string, btnInstance: InstanceType<typeof Button>) =>
57
- h(InsertAttachment, {
58
- color: color,
59
- accept: options!.accept,
60
- allowedFileType: options!.allowedFileType || [],
61
- multiple: !!options!.multiple,
62
- maxSize: options!.maxSize,
63
- minSize: options!.minSize,
64
- customUpload: options!.customUpload,
65
- handleError: options!.handleError,
66
- onChange: () => {
67
- ;(<InstanceType<typeof Layer>>btnInstance.$refs.layerRef).setPosition()
68
- },
69
- onInsert: (url: string) => {
94
+ extend: {
95
+ type: 'select',
96
+ title: options!.title || editTrans('insertAttachment'),
97
+ leftBorder: options!.leftBorder,
98
+ rightBorder: options!.rightBorder,
99
+ hideScroll: true,
100
+ disabled: isDisabled,
101
+ default: () => h(Icon, { value: 'attachment' }),
102
+ layer: (_name: string, btnInstance: InstanceType<typeof Button>) =>
103
+ h(InsertAttachment, {
104
+ color: color,
105
+ accept: options!.accept,
106
+ allowedFileType: options!.allowedFileType || [],
107
+ multiple: !!options!.multiple,
108
+ maxSize: options!.maxSize,
109
+ minSize: options!.minSize,
110
+ customUpload: options!.customUpload,
111
+ handleError: options!.handleError,
112
+ onChange: () => {
113
+ ;(<InstanceType<typeof Layer>>btnInstance.$refs.layerRef).setPosition()
114
+ },
115
+ onInsert: (name: string, url: string) => {
116
+ //如果地址存在
117
+ if (url) {
70
118
  const marks: ObjectType = {
71
119
  'data-attachment': url,
72
- 'data-attachment-name': editTrans('attachmentDownloadName'),
120
+ 'data-attachment-name': name || editTrans('attachmentDefaultName'),
73
121
  contenteditable: 'false'
74
122
  }
75
123
  //创建元素
@@ -91,11 +139,11 @@ export const attachment = (options?: AttachmentOptionsType) => {
91
139
  editor.formatElementStack()
92
140
  editor.domRender()
93
141
  editor.rangeRender()
94
- //关闭浮层
95
- btnInstance.show = false
96
142
  }
97
- })
98
- }
143
+ //关闭浮层
144
+ btnInstance.show = false
145
+ }
146
+ })
99
147
  }
100
148
  },
101
149
  //找到附件元素点击下载
@@ -104,11 +152,21 @@ export const attachment = (options?: AttachmentOptionsType) => {
104
152
  AlexElement.flatElements(editor.stack).forEach(el => {
105
153
  if (el.parsedom == 'span' && el.hasMarks() && el.marks!['data-attachment']) {
106
154
  DapEvent.off(<HTMLElement>el.elm, 'click')
107
- DapEvent.on(<HTMLElement>el.elm, 'click', () => {
155
+ //单击下载
156
+ DapEvent.on(<HTMLElement>el.elm, 'click', async () => {
157
+ //获取文件地址
108
158
  const url = el.marks!['data-attachment']
159
+ //使用fetch读取文件地址
160
+ const res = await fetch(url, {
161
+ method: 'GET'
162
+ })
163
+ //获取blob数据
164
+ const blob = await res.blob()
165
+ //创建a标签进行下载
109
166
  const a = document.createElement('a')
110
- a.setAttribute('href', url)
111
- a.setAttribute('download', editTrans('attachmentDownloadName'))
167
+ a.setAttribute('target', '_blank')
168
+ a.setAttribute('href', URL.createObjectURL(blob))
169
+ a.setAttribute('download', el.marks!['data-attachment-name'])
112
170
  a.click()
113
171
  })
114
172
  }
@@ -130,7 +188,7 @@ export const attachment = (options?: AttachmentOptionsType) => {
130
188
  renderRule: (el: AlexElement) => {
131
189
  if (el.type == 'closed' && el.hasMarks() && el.marks!['data-attachment']) {
132
190
  //设置title
133
- el.marks!['title'] = editTrans('downloadAttachment')
191
+ el.marks!['title'] = editTrans('attachmentDownloadTitle')
134
192
  //获取editor对象
135
193
  const editor = <AlexEditor>editifyInstance.exposed!.editor.value
136
194
  //前一个元素
@@ -8,9 +8,10 @@
8
8
  justify-content: flex-start;
9
9
  align-items: center;
10
10
  width: 100%;
11
- margin-bottom: 20px;
11
+ margin-bottom: 10px;
12
12
  position: relative;
13
13
  padding-bottom: 6px;
14
+ user-select: none;
14
15
 
15
16
  .editify-attachment-header-slider {
16
17
  position: absolute;
@@ -107,29 +108,57 @@
107
108
 
108
109
  .editify-attachment-upload {
109
110
  display: flex;
110
- justify-content: center;
111
- align-items: center;
111
+ justify-content: space-between;
112
+ align-items: flex-end;
112
113
  width: 100%;
113
114
  padding: 15px 0;
114
- font-size: 36px;
115
- opacity: 0.8;
116
- transition: all 200ms;
117
- position: relative;
118
115
 
119
- &:hover {
120
- cursor: pointer;
121
- opacity: 1;
116
+ input[type='text'] {
117
+ appearance: none;
118
+ -webkit-appearance: none;
119
+ -moz-appearance: none;
120
+ display: block;
121
+ width: 100%;
122
+ margin: 0;
123
+ padding: 4px 2px;
124
+ border: none;
125
+ font-size: @font-size;
126
+ color: @font-color;
127
+ border-bottom: 1px solid @border-color;
128
+ line-height: 1.5;
129
+ transition: border-color 500ms;
130
+ background-color: transparent;
131
+ outline: none;
132
+ box-sizing: border-box;
133
+
134
+ &::-webkit-input-placeholder,
135
+ &::placeholder {
136
+ color: @font-color-disabled;
137
+ font-family: inherit;
138
+ font-size: inherit;
139
+ vertical-align: middle;
140
+ }
122
141
  }
123
142
 
124
- input {
125
- opacity: 0;
126
- position: absolute;
127
- left: 0;
128
- top: 0;
129
- width: 100%;
130
- height: 100%;
131
- z-index: 1;
132
- cursor: pointer;
143
+ .editify-attachment-btn {
144
+ position: relative;
145
+ font-size: 20px;
146
+ line-height: 1;
147
+ opacity: 0.8;
148
+ transition: all 200ms;
149
+ color: @font-color;
150
+ border-radius: 2px;
151
+ padding: 2px;
152
+ margin-left: 15px;
153
+
154
+ &:hover {
155
+ cursor: pointer;
156
+ opacity: 1;
157
+ }
158
+
159
+ input[type='file'] {
160
+ display: none;
161
+ }
133
162
  }
134
163
  }
135
164
  }