Skip to content

Commit

Permalink
feat: updateLink + unLink + viewLink
Browse files Browse the repository at this point in the history
  • Loading branch information
wangfupeng1988 committed Jun 1, 2021
1 parent b04242f commit 254d554
Show file tree
Hide file tree
Showing 9 changed files with 315 additions and 33 deletions.
9 changes: 7 additions & 2 deletions packages/basic/src/modules/link/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
import { IModuleConf } from '@wangeditor/core'
import withLink from './withLink'
import { renderLinkConf } from './formats'
import { insertLinkMenuConf } from './menu/index'
import {
insertLinkMenuConf,
updateLinkMenuConf,
unLinkMenuConf,
viewLinkMenuConf,
} from './menu/index'

const link: IModuleConf = {
renderElems: [renderLinkConf],
menus: [insertLinkMenuConf],
menus: [insertLinkMenuConf, updateLinkMenuConf, unLinkMenuConf, viewLinkMenuConf],
editorPlugin: withLink,
}

Expand Down
41 changes: 11 additions & 30 deletions packages/basic/src/modules/link/menu/InsertLink.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ import { Editor, Transforms, Range } from 'slate'
import { IMenuItem, IDomEditor, DomEditor, hideAllPanelsAndModals } from '@wangeditor/core'
import $, { Dom7Array } from '../../../utils/dom'
import { genRandomStr } from '../../../utils/util'

function genLabelContainer(): Dom7Array {
return $('<label class="babel-container"></label>')
}
import { getInputElems, getButtonElems } from './helpers'

/**
* 生成唯一的 DOM ID
Expand All @@ -31,16 +28,8 @@ class InsertLink implements IMenuItem {
private buttonId = genDomID()

getValue(editor: IDomEditor): string | boolean {
const [nodeEntry] = Editor.nodes(editor, {
match: n => {
// @ts-ignore
return n.type === 'link'
},
universal: true,
})

if (nodeEntry == null) return false
return true
// 任何时候,都不用激活 menu
return false
}

isDisabled(editor: IDomEditor): boolean {
Expand Down Expand Up @@ -74,22 +63,10 @@ class InsertLink implements IMenuItem {
const { selection } = editor
const { textInputId, urlInputId, buttonId } = this

// 文本 input elem
const $textContainer = genLabelContainer()
$textContainer.append('<span>链接文本</span>')
const $inputText = $(`<input type="text" id="${textInputId}">`)
$textContainer.append($inputText)

// 链接网址 input elem
const $urlContainer = genLabelContainer()
$urlContainer.append($('<span>链接网址</span>'))
const $inputUrl = $(`<input type="text" id="${urlInputId}">`)
$urlContainer.append($inputUrl)

// button
const $buttonContainer = $('<div class="button-container"></div>')
const $button = $(`<button id="${buttonId}">插入链接</button>`)
$buttonContainer.append($button)
// 获取 input button elem
const [$textContainer, $inputText] = getInputElems('链接文本', textInputId)
const [$urlContainer, $inputUrl] = getInputElems('链接网址', urlInputId)
const [$buttonContainer] = getButtonElems(buttonId, '确定')

if (this.$content == null) {
// 第一次渲染
Expand Down Expand Up @@ -149,6 +126,10 @@ class InsertLink implements IMenuItem {

// 还原选区
DomEditor.restoreSelection(editor)

if (this.isDisabled(editor)) return

// 判断选区是否折叠
const { selection } = editor
if (selection == null) return
const isCollapsed = Range.isCollapsed(selection)
Expand Down
51 changes: 51 additions & 0 deletions packages/basic/src/modules/link/menu/UnLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* @description unlink menu
* @author wangfupeng
*/

import { Transforms } from 'slate'
import { IMenuItem, IDomEditor } from '@wangeditor/core'
import { getLinkNode, checkLink } from './helpers'

class UnLink implements IMenuItem {
title = '取消链接'
iconSvg =
'<svg viewBox="0 0 1024 1024"><path d="M608.16328 811.815036c9.371954 9.371954 9.371954 24.56788 0 33.941834l-89.347563 89.347564c-118.525421 118.523421-311.38448 118.531421-429.919901 0-118.527421-118.529421-118.527421-311.39048 0-429.917901l89.349564-89.349563c9.371954-9.371954 24.56788-9.371954 33.941834 0l79.195613 79.195613c9.371954 9.371954 9.371954 24.56788 0 33.941834l-89.349563 89.347564c-56.143726 56.145726-56.143726 147.49928 0 203.645005 56.143726 56.143726 147.49928 56.145726 203.647005 0l89.347564-89.347563c9.371954-9.371954 24.56788-9.371954 33.941834 0l79.193613 79.195613z m-113.135447-520.429459c9.371954 9.371954 24.56788 9.371954 33.941834 0l89.347564-89.347564c56.143726-56.149726 147.49928-56.145726 203.647006 0 56.143726 56.145726 56.143726 147.49928 0 203.645006l-89.349564 89.347564c-9.371954 9.371954-9.371954 24.56788 0 33.941834l79.195613 79.195613c9.371954 9.371954 24.56788 9.371954 33.941834 0l89.349564-89.349563c118.529421-118.529421 118.529421-311.38848 0-429.917901-118.531421-118.527421-311.38848-118.527421-429.919901 0l-89.347563 89.347564c-9.371954 9.371954-9.371954 24.56788 0 33.941834l79.193613 79.195613z m469.653707 718.556492l45.253779-45.253779c18.745908-18.745908 18.745908-49.13776 0-67.881669L127.195629 14.062931c-18.745908-18.745908-49.13776-18.745908-67.881669 0L14.058181 59.31871c-18.745908 18.745908-18.745908 49.13776 0 67.881669l882.74169 882.74169c18.745908 18.743908 49.13776 18.743908 67.881669 0z"></path></svg>'
tag = 'button'

getValue(editor: IDomEditor): string | boolean {
const linkNode = getLinkNode(editor)
if (linkNode) {
// 选区处于 link node
return true
}
return false
}

isDisabled(editor: IDomEditor): boolean {
if (editor.selection == null) return true

const linkNode = getLinkNode(editor)
if (linkNode == null) {
// 选区未处于 link node ,则禁用
return true
}
return false
}

exec(editor: IDomEditor, value: string | boolean) {
if (this.isDisabled(editor)) return

// 取消链接
Transforms.unwrapNodes(editor, {
match: checkLink,
})
}
}

export default {
key: 'unLink',
factory() {
return new UnLink()
},
}
129 changes: 129 additions & 0 deletions packages/basic/src/modules/link/menu/UpdateLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/**
* @description update link menu
* @author wangfupeng
*/

import { Editor, Transforms, Node } from 'slate'
import { IMenuItem, IDomEditor, DomEditor, hideAllPanelsAndModals } from '@wangeditor/core'
import $, { Dom7Array } from '../../../utils/dom'
import { genRandomStr } from '../../../utils/util'
import { getInputElems, getButtonElems, getLinkNode, checkLink } from './helpers'

/**
* 生成唯一的 DOM ID
*/
function genDomID(): string {
return genRandomStr('w-e-update-link')
}

class UpdateLink implements IMenuItem {
title = '修改链接'
iconSvg =
'<svg viewBox="0 0 1024 1024"><path d="M850.622159 29.124904c-31.331849-33.126756-82.334296-33.126756-113.660501 0L672.525631 97.602293l151.494653 160.582075 64.441672-68.454812c31.676155-33.143689 31.676155-87.019116 0-120.168449l-37.839797-40.436203z m-208.683321 100.514783l-421.684577 447.919568V587.01356h36.411774v36.417418h36.417418v36.417418h36.417418v36.411774h36.411774V748.318113l427.882085-458.090707-151.855892-160.587719zM183.836843 616.516635l-15.663103 16.379936-57.166089 219.238276 223.21755-69.555462 12.378084-13.484379h-17.102414v-36.411774h-36.417418v-36.417418h-36.417418v-36.411774h-36.411774v-36.417418H183.836843v-6.919987z m-43.704289 338.672958v68.810407h758.528762v-68.810407H140.132554z"></path></svg>'
tag = 'button'
showModal = true // 点击 button 时显示 modal
private $content: Dom7Array | null = null
private urlInputId = genDomID()
private buttonId = genDomID()

/**
* 获取 node.url
* @param editor editor
*/
getValue(editor: IDomEditor): string | boolean {
const linkNode = getLinkNode(editor)
if (linkNode) {
// @ts-ignore
return linkNode.url || ''
}
return ''
}

isDisabled(editor: IDomEditor): boolean {
if (editor.selection == null) return true

const linkNode = getLinkNode(editor)

// 未匹配到 link node 则禁用
if (linkNode == null) return true
return false
}

getModalContentElem(editor: IDomEditor): Dom7Array {
const { urlInputId, buttonId } = this

// 获取 input button elem
const [$urlContainer, $inputUrl] = getInputElems('链接网址', urlInputId)
const [$buttonContainer] = getButtonElems(buttonId, '确定')

if (this.$content == null) {
// 第一次渲染
const $content = $('<div style="width: 300px;"></div>')

// 绑定事件(第一次渲染时绑定,不要重复绑定)
$content.on('click', 'button', e => {
e.preventDefault()
const url = $(`#${urlInputId}`).val()
this.updateLink(editor, url)
})

// 记录属性,重要
this.$content = $content
}

const $content = this.$content
$content.html('') // 先清空内容

// append input and button
$content.append($urlContainer)
$content.append($buttonContainer)

// 设置 input val
const url = this.getValue(editor)
$inputUrl.val(url)

// focus 一个 input(异步,此时 DOM 尚未渲染)
setTimeout(() => {
$(`#${urlInputId}`).focus()
})

return $content
}

/**
* 修改 link
* @param editor editor
* @param url url
*/
private updateLink(editor: IDomEditor, url: string) {
if (!url) {
hideAllPanelsAndModals() // 隐藏 modal
return
}

// 还原选区
DomEditor.restoreSelection(editor)

if (this.isDisabled(editor)) return

// 修改链接
Transforms.setNodes(
editor,
// @ts-ignore
{ url },
{
match: checkLink,
}
)

// 隐藏 modal
hideAllPanelsAndModals()
}
}

export default {
key: 'updateLink',
factory() {
return new UpdateLink()
},
}
53 changes: 53 additions & 0 deletions packages/basic/src/modules/link/menu/ViewLink.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @description view link menu
* @author wangfupeng
*/

import { IMenuItem, IDomEditor } from '@wangeditor/core'
import { getLinkNode } from './helpers'

class ViewLink implements IMenuItem {
title = '查看链接'
iconSvg =
'<svg viewBox="0 0 1024 1024"><path d="M924.402464 1023.068211H0.679665V99.345412h461.861399v98.909208H99.596867v725.896389h725.896389V561.206811h98.909208z" p-id="10909"></path><path d="M930.805104 22.977336l69.965436 69.965436-453.492405 453.492404-69.965435-69.901489z" p-id="10910"></path><path d="M1022.464381 304.030081h-98.917201V99.345412H709.230573V0.428211h313.233808z"></path></svg>'
tag = 'button'

getValue(editor: IDomEditor): string | boolean {
const linkNode = getLinkNode(editor)
if (linkNode) {
// @ts-ignore 选区处于 link node
return linkNode.url || ''
}
return ''
}

isDisabled(editor: IDomEditor): boolean {
if (editor.selection == null) return true

const linkNode = getLinkNode(editor)
if (linkNode == null) {
// 选区未处于 link node ,则禁用
return true
}
return false
}

exec(editor: IDomEditor, value: string | boolean) {
if (this.isDisabled(editor)) return

if (!value || typeof value !== 'string') {
throw new Error(`View link failed, link url is '${value}'`)
return
}

// 查看链接
window.open(value, '_blank')
}
}

export default {
key: 'viewLink',
factory() {
return new ViewLink()
},
}
56 changes: 56 additions & 0 deletions packages/basic/src/modules/link/menu/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/**
* @description link menu helpers
* @author wangfupeng
*/

import { Editor, Node, Element } from 'slate'
import { IDomEditor } from '@wangeditor/core'
import $, { Dom7Array } from '../../../utils/dom'

export function checkLink(n: Node): boolean {
if (Editor.isEditor(n)) return false
if (Element.isElement(n)) {
// @ts-ignore
return n.type === 'link'
}
return false
}

export function getLinkNode(editor: IDomEditor): Node | null {
const [nodeEntry] = Editor.nodes(editor, {
match: checkLink,
universal: true,
})

if (nodeEntry == null) return null
return nodeEntry[0]
}

/**
* 获取 input elems
* @param labelText label text
* @param inputId input dom id
* @returns [$container, $input]
*/
export function getInputElems(labelText: string, inputId: string): Dom7Array[] {
const $container = $('<label class="babel-container"></label>')
$container.append(`<span>${labelText}</span>`)
const $input = $(`<input type="text" id="${inputId}">`)
$container.append($input)

return [$container, $input]
}

/**
* 获取 button elems
* @param buttonId button dom id
* @param buttonText button text
* @returns [ $container, $button ]
*/
export function getButtonElems(buttonId: string, buttonText: string): Dom7Array[] {
const $buttonContainer = $('<div class="button-container"></div>')
const $button = $(`<button id="${buttonId}">${buttonText}</button>`)
$buttonContainer.append($button)

return [$buttonContainer, $button]
}
5 changes: 4 additions & 1 deletion packages/basic/src/modules/link/menu/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@
*/

import insertLinkMenuConf from './InsertLink'
import updateLinkMenuConf from './UpdateLink'
import unLinkMenuConf from './UnLink'
import viewLinkMenuConf from './ViewLink'

export { insertLinkMenuConf }
export { insertLinkMenuConf, updateLinkMenuConf, unLinkMenuConf, viewLinkMenuConf }
1 change: 1 addition & 0 deletions packages/core/src/assets/select-list.less
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.w-e-select-list {
z-index: 1;
position: absolute;
left: 0;
top: 0;
Expand Down
Loading

0 comments on commit 254d554

Please sign in to comment.