update
parent
5b454bad12
commit
12630d66c0
|
@ -511,6 +511,10 @@ class Editor extends Component {
|
||||||
let txt = ev.clipboardData.getData('text/plain')
|
let txt = ev.clipboardData.getData('text/plain')
|
||||||
let items = ev.clipboardData.items
|
let items = ev.clipboardData.items
|
||||||
|
|
||||||
|
if (this.readOnly || this.disabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 先文件判断, 避免右键单击复制图片时, 当成html处理
|
// 先文件判断, 避免右键单击复制图片时, 当成html处理
|
||||||
if (items && items.length) {
|
if (items && items.length) {
|
||||||
let blob = null
|
let blob = null
|
||||||
|
|
|
@ -594,7 +594,7 @@ class Tool {
|
||||||
|
|
||||||
// 引用结束
|
// 引用结束
|
||||||
if (isBlockquote) {
|
if (isBlockquote) {
|
||||||
if (emptyLineLength > 1) {
|
if (emptyLineLength > 0) {
|
||||||
isBlockquote = false
|
isBlockquote = false
|
||||||
emptyLineLength = 0
|
emptyLineLength = 0
|
||||||
while (blockquoteLevel > 0) {
|
while (blockquoteLevel > 0) {
|
||||||
|
|
|
@ -10,6 +10,8 @@ import md2html from './core.js'
|
||||||
import '../code/index.js'
|
import '../code/index.js'
|
||||||
import '../form/checkbox.js'
|
import '../form/checkbox.js'
|
||||||
|
|
||||||
|
export default md2html
|
||||||
|
|
||||||
class Markd extends Component {
|
class Markd extends Component {
|
||||||
static props = {
|
static props = {
|
||||||
code: { type: String, default: '', attribute: false }
|
code: { type: String, default: '', attribute: false }
|
||||||
|
|
|
@ -124,18 +124,15 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
fullscreen(elem) {
|
fullscreen(elem) {
|
||||||
//
|
this.classList.toggle('fullscreen')
|
||||||
this.props.fullscreen = !this.props.fullscreen
|
elem.classList.toggle('active')
|
||||||
if (this.props.fullscreen) {
|
|
||||||
this.setAttribute('fullscreen', '')
|
|
||||||
} else {
|
|
||||||
this.removeAttribute('fullscreen')
|
|
||||||
}
|
|
||||||
elem.classList.toggle('active', this.props.fullscreen)
|
|
||||||
},
|
},
|
||||||
preview(elem) {
|
preview(elem) {
|
||||||
this.state.preview = !this.state.preview
|
this.previewEnabled = !this.previewEnabled
|
||||||
this.__VIEW__.classList.toggle('active', this.state.preview)
|
this.$refs.view.classList.toggle('active')
|
||||||
elem.classList.toggle('active', this.state.preview)
|
elem.classList.toggle('active')
|
||||||
|
if (this.previewEnabled) {
|
||||||
|
this.$refs.view.code = this.value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,17 +16,17 @@ const ELEMS = {
|
||||||
|
|
||||||
href = (href && href[1]) || null
|
href = (href && href[1]) || null
|
||||||
title = (title && title[1]) || null
|
title = (title && title[1]) || null
|
||||||
tar = (tar && tar[1]) || '_self'
|
tar = tar && tar[1]
|
||||||
|
|
||||||
if (!href) {
|
if (!href) {
|
||||||
return inner || href
|
return inner || href
|
||||||
}
|
}
|
||||||
|
|
||||||
href = href.replace('viod(0)', '')
|
href = href.replace('viod(0)', '').replaceAll('&', '&')
|
||||||
attrs = `target=${tar}`
|
attrs = tar ? `target=${tar}` : ''
|
||||||
attrs += title ? `;title=${title}` : ''
|
attrs += title ? `;title=${title}` : ''
|
||||||
|
|
||||||
return `[${inner || href}](${href} "${attrs}")`
|
return `[${inner || href}](${href}${attrs ? ` "${attrs}"` : ''})`
|
||||||
},
|
},
|
||||||
em: function (str, attr, inner) {
|
em: function (str, attr, inner) {
|
||||||
return (inner && '_' + inner + '_') || ''
|
return (inner && '_' + inner + '_') || ''
|
||||||
|
@ -134,10 +134,10 @@ export function renderToolbar(list = [], dict = {}, showText = false) {
|
||||||
let title = showText ? '' : dict[it]
|
let title = showText ? '' : dict[it]
|
||||||
let text = showText ? dict[it] || '' : ''
|
let text = showText ? dict[it] || '' : ''
|
||||||
|
|
||||||
return html`<section data-act=${it} title=${title}>
|
return html`<span data-act=${it} title=${title}>
|
||||||
<svg class="icon" viewBox="0 0 1024 1024"><path d=${ICONS[it]} /></svg>
|
<svg class="icon" viewBox="0 0 1024 1024"><path d=${ICONS[it]} /></svg>
|
||||||
${text}
|
${text}
|
||||||
</section>`
|
</span>`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,11 +151,19 @@ export function html2md(str) {
|
||||||
|
|
||||||
str = str
|
str = str
|
||||||
.replace(/\t/g, ' ')
|
.replace(/\t/g, ' ')
|
||||||
.replace(/<meta [^>]*>/, '')
|
.replace(/<\/?(meta|link|script)[^>]*?>/g, '')
|
||||||
|
.replace(/<!--[\w\W]*?-->/g, '')
|
||||||
|
.replace(/<xml[^>]*?>[\w\W]*?<\/xml>/g, '')
|
||||||
|
.replace(/<style>[\w\W]*?<\/style>/g, '')
|
||||||
.replace(attrExp('class', 'g'), '')
|
.replace(attrExp('class', 'g'), '')
|
||||||
.replace(attrExp('style', 'g'), '')
|
.replace(attrExp('style', 'g'), '')
|
||||||
|
.replace(/<a[^>]*? href\s?=\s?["']?([^"']*)["']?[^>]*?>/g, '<a href="$1">')
|
||||||
|
.replace(
|
||||||
|
/<img[^>]*? src\s?=\s?["']?([^"']*)["']?[^>]*?>/g,
|
||||||
|
'<img src="$1">'
|
||||||
|
)
|
||||||
.replace(/<(?!a |img )(\w+) [^>]*>/g, '<$1>')
|
.replace(/<(?!a |img )(\w+) [^>]*>/g, '<$1>')
|
||||||
.replace(/<svg[^>]*>.*?<\/svg>/g, '{invalid image}')
|
.replace(/<svg[^>]*>.*?<\/svg>/g, '{svg not support}')
|
||||||
|
|
||||||
// log(str)
|
// log(str)
|
||||||
for (let i in ELEMS) {
|
for (let i in ELEMS) {
|
||||||
|
|
|
@ -18,10 +18,13 @@ import {
|
||||||
clearOutsideClick
|
clearOutsideClick
|
||||||
} from 'wkit'
|
} from 'wkit'
|
||||||
|
|
||||||
import { renderToolbar, DEFAULT_TOOLS } from './helper.js'
|
import { renderToolbar, DEFAULT_TOOLS, html2md } from './helper.js'
|
||||||
|
import Addon from './addon.js'
|
||||||
|
import markd from '../markd/index.js'
|
||||||
|
|
||||||
import '../form/input.js'
|
import '../form/input.js'
|
||||||
import '../form/button.js'
|
import '../form/button.js'
|
||||||
|
import '../code/index.js'
|
||||||
|
|
||||||
const COLORS = [
|
const COLORS = [
|
||||||
'#f3f5fb',
|
'#f3f5fb',
|
||||||
|
@ -113,7 +116,7 @@ class MEditor extends Component {
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
border-bottom: 1px solid var(--color-grey-1);
|
border-bottom: 1px solid var(--color-grey-1);
|
||||||
|
|
||||||
section {
|
span {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -415,7 +418,12 @@ class MEditor extends Component {
|
||||||
|
|
||||||
set value(val) {
|
set value(val) {
|
||||||
if (this.$refs.editor) {
|
if (this.$refs.editor) {
|
||||||
|
if (this.$refs.editor.value === val) {
|
||||||
|
return
|
||||||
|
}
|
||||||
this.$refs.editor.value = val
|
this.$refs.editor.value = val
|
||||||
|
this.#updatePreview()
|
||||||
|
this.$emit('input')
|
||||||
} else {
|
} else {
|
||||||
nextTick(_ => (this.value = val))
|
nextTick(_ => (this.value = val))
|
||||||
}
|
}
|
||||||
|
@ -429,6 +437,8 @@ class MEditor extends Component {
|
||||||
|
|
||||||
#select = null
|
#select = null
|
||||||
|
|
||||||
|
previewEnabled = false
|
||||||
|
|
||||||
__init__() {
|
__init__() {
|
||||||
//
|
//
|
||||||
let { outer, inner, thumb } = this.$refs
|
let { outer, inner, thumb } = this.$refs
|
||||||
|
@ -476,7 +486,7 @@ class MEditor extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理图片
|
// 处理图片
|
||||||
#handleImage(ev, file) {
|
#handleFile(ev, file, t = '!') {
|
||||||
if (ev && ev.type === 'change') {
|
if (ev && ev.type === 'change') {
|
||||||
file = ev.target.files[0]
|
file = ev.target.files[0]
|
||||||
ev.target.value = ''
|
ev.target.value = ''
|
||||||
|
@ -486,14 +496,7 @@ class MEditor extends Component {
|
||||||
file,
|
file,
|
||||||
send: link => {
|
send: link => {
|
||||||
this.$refs.editor.focus()
|
this.$refs.editor.focus()
|
||||||
this.restoreSelection()
|
this.insert(`${t}[${file.name}](${link})`)
|
||||||
this.exec(ACTTION.image, link)
|
|
||||||
this.saveSelection()
|
|
||||||
|
|
||||||
// 修正插入的图片,宽度不得超出容器
|
|
||||||
this.$refs.editor.querySelectorAll('img').forEach(_ => {
|
|
||||||
_.style.maxWidth = '100%'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -504,52 +507,50 @@ class MEditor extends Component {
|
||||||
let txt = ev.clipboardData.getData('text/plain')
|
let txt = ev.clipboardData.getData('text/plain')
|
||||||
let items = ev.clipboardData.items
|
let items = ev.clipboardData.items
|
||||||
|
|
||||||
|
if (this.readOnly || this.disabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 先文件判断, 避免右键单击复制图片时, 当成html处理
|
// 先文件判断, 避免右键单击复制图片时, 当成html处理
|
||||||
if (items && items.length) {
|
if (items && items.length) {
|
||||||
let blob = null
|
let file = null
|
||||||
|
|
||||||
for (let it of items) {
|
for (let it of items) {
|
||||||
if (it.type.indexOf('image') > -1) {
|
file = it.getAsFile()
|
||||||
blob = it.getAsFile()
|
if (file) {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blob) {
|
if (file) {
|
||||||
return this.#handleImage(null, blob)
|
return this.#handleFile(
|
||||||
|
null,
|
||||||
|
file,
|
||||||
|
file.type.includes('image') ? '!' : ''
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (html) {
|
if (html) {
|
||||||
html = html
|
this.insert(html2md(html))
|
||||||
.replace(/\t/g, ' ')
|
} else if (txt) {
|
||||||
.replace(/<\/?(meta|link|script)[^>]*?>/g, '')
|
this.insert(txt)
|
||||||
.replace(/<!--[\w\W]*?-->/g, '')
|
}
|
||||||
.replace(
|
|
||||||
/<a[^>]*? href\s?=\s?["']?([^"']*)["']?[^>]*?>/g,
|
|
||||||
'<a href="$1">'
|
|
||||||
)
|
|
||||||
.replace(
|
|
||||||
/<img[^>]*? src\s?=\s?["']?([^"']*)["']?[^>]*?>/g,
|
|
||||||
'<img src="$1">'
|
|
||||||
)
|
|
||||||
.replace(/<(?!a|img)([\w\-]+)[^>]*>/g, '<$1>')
|
|
||||||
.replace(/<xml[^>]*?>[\w\W]*?<\/xml>/g, '')
|
|
||||||
.replace(/<style>[\w\W]*?<\/style>/g, '')
|
|
||||||
|
|
||||||
return this.exec('insertHtml', html)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (txt) {
|
#updatePreview() {
|
||||||
return this.exec('insertText', txt)
|
if (this.previewEnabled) {
|
||||||
|
this.$refs.view.code = this.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#toolbarClick(ev) {
|
#toolbarClick(ev) {
|
||||||
var target = ev.target
|
var elem = ev.target
|
||||||
var act
|
var act
|
||||||
|
|
||||||
this.restoreSelection()
|
this.restoreSelection()
|
||||||
|
|
||||||
if (ev.target === ev.currentTarget) {
|
if (elem === ev.currentTarget) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,41 +558,15 @@ class MEditor extends Component {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
while (target.tagName !== 'SPAN') {
|
while (elem.tagName !== 'SPAN') {
|
||||||
target = target.parentNode
|
elem = elem.parentNode
|
||||||
}
|
}
|
||||||
|
|
||||||
act = target.dataset.act
|
act = elem.dataset.act
|
||||||
|
|
||||||
this.#hideLayers()
|
// this.#hideLayers()
|
||||||
|
|
||||||
switch (act) {
|
Addon[act].call(this, elem)
|
||||||
case 'font':
|
|
||||||
case 'color':
|
|
||||||
case 'link':
|
|
||||||
case 'table':
|
|
||||||
this.$refs[act].classList.add('fadein')
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'image':
|
|
||||||
// 这里不作任何处理
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'copy':
|
|
||||||
navigator.clipboard.writeText(this.value)
|
|
||||||
break
|
|
||||||
|
|
||||||
case 'fullscreen':
|
|
||||||
this.classList.toggle('fullscreen')
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
this.$refs.editor.focus()
|
|
||||||
this.restoreSelection()
|
|
||||||
this.exec(ACTTION[act])
|
|
||||||
this.saveSelection()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#chnageFontSize(ev) {
|
#chnageFontSize(ev) {
|
||||||
|
@ -688,9 +663,248 @@ class MEditor extends Component {
|
||||||
gs.addRange(this.#select)
|
gs.addRange(this.#select)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 执行命令
|
|
||||||
exec(cmd, val = '') {
|
/**
|
||||||
document.execCommand(cmd, false, val)
|
* 往文本框中插入内容
|
||||||
|
* @param {String} val [要插入的文本]
|
||||||
|
* @param {Boolean} isSelect [插入之后是否要选中文本]
|
||||||
|
* @param {Boolean} offset [选中文本时的偏移量]
|
||||||
|
*/
|
||||||
|
insert(val = '', isSelect = false, offset = 0) {
|
||||||
|
let $el = this.$refs.editor
|
||||||
|
let start = $el.selectionStart
|
||||||
|
let end = $el.selectionEnd
|
||||||
|
let scrollTop = $el.scrollTop
|
||||||
|
|
||||||
|
if (start || start === 0) {
|
||||||
|
$el.value = $el.value.slice(0, start) + val + $el.value.slice(end)
|
||||||
|
|
||||||
|
this.select(
|
||||||
|
(isSelect ? start : start + val.length) + offset,
|
||||||
|
start + val.length - offset
|
||||||
|
)
|
||||||
|
$el.scrollTop = scrollTop
|
||||||
|
$el.focus()
|
||||||
|
} else {
|
||||||
|
$el.value += val
|
||||||
|
$el.focus()
|
||||||
|
}
|
||||||
|
this.#updatePreview()
|
||||||
|
this.$emit('input')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [selection 获取选中的文本]
|
||||||
|
* @param {[type]} forceHoleLine [是否强制光标所在的整行文本]
|
||||||
|
*/
|
||||||
|
selection(forceHoleLine = false) {
|
||||||
|
let $el = this.$refs.editor
|
||||||
|
let start = $el.selectionStart
|
||||||
|
let end = $el.selectionEnd
|
||||||
|
|
||||||
|
if (end) {
|
||||||
|
//强制选择整行
|
||||||
|
if (forceHoleLine) {
|
||||||
|
start = $el.value.slice(0, start).lastIndexOf('\n')
|
||||||
|
|
||||||
|
let tmpEnd = $el.value.slice(end).indexOf('\n')
|
||||||
|
tmpEnd = tmpEnd < 0 ? $el.value.slice(end).length : tmpEnd
|
||||||
|
|
||||||
|
start += 1 // 把\n加上
|
||||||
|
end += tmpEnd
|
||||||
|
|
||||||
|
$el.selectionStart = start
|
||||||
|
$el.selectionEnd = end
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//强制选择整行
|
||||||
|
if (forceHoleLine) {
|
||||||
|
end = $el.value.indexOf('\n')
|
||||||
|
end = end < 0 ? $el.value.length : end
|
||||||
|
$el.selectionEnd = end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$el.focus()
|
||||||
|
return $el.value.slice(start, end)
|
||||||
|
}
|
||||||
|
|
||||||
|
select(start = 0, end = 0) {
|
||||||
|
let $el = this.$refs.editor
|
||||||
|
$el.selectionStart = start
|
||||||
|
$el.selectionEnd = end
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置光标
|
||||||
|
cursor(pos) {
|
||||||
|
this.select(pos, pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
#cursorMove(step) {
|
||||||
|
let $el = this.$refs.editor
|
||||||
|
let pos = (step < 0 ? $el.selectionStart : $el.selectionEnd) || 0
|
||||||
|
pos += step
|
||||||
|
|
||||||
|
if (step === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos < 0) {
|
||||||
|
pos = 0
|
||||||
|
}
|
||||||
|
this.cursor(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取光标处的字符
|
||||||
|
#getCursorText(n) {
|
||||||
|
let $el = this.$refs.editor
|
||||||
|
let start = $el.selectionStart
|
||||||
|
let pos = $el.selectionEnd
|
||||||
|
|
||||||
|
if (n < 0) {
|
||||||
|
pos = start - 1
|
||||||
|
}
|
||||||
|
return this.value[pos] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
#handleKeydown(ev) {
|
||||||
|
let $el = this.$refs.editor
|
||||||
|
let wrapTxt = this.selection() || ''
|
||||||
|
let selected = wrapTxt.length > 0
|
||||||
|
let newTxt = ''
|
||||||
|
|
||||||
|
if (this.readOnly || this.disabled) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ev.keyCode) {
|
||||||
|
//tab键改为插入2个空格,阻止默认事件,防止焦点失去
|
||||||
|
case 9:
|
||||||
|
ev.preventDefault()
|
||||||
|
if (ev.shiftKey && !selected) {
|
||||||
|
let pos = $el.selectionStart
|
||||||
|
let line = this.selection(true)
|
||||||
|
newTxt = line.replace(/^\s{2}/, '')
|
||||||
|
// 防止无法往左取消缩进时, 选中整行
|
||||||
|
if (line === newTxt) {
|
||||||
|
this.cursor(pos)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
pos -= 2
|
||||||
|
this.insert(newTxt, selected)
|
||||||
|
this.cursor(pos)
|
||||||
|
} else {
|
||||||
|
newTxt = wrapTxt
|
||||||
|
.split('\n')
|
||||||
|
.map(function (it) {
|
||||||
|
return ev.shiftKey ? it.replace(/^\s{2}/, '') : ' ' + it
|
||||||
|
})
|
||||||
|
.join('\n')
|
||||||
|
|
||||||
|
if (newTxt === wrapTxt) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
this.insert(newTxt, selected)
|
||||||
|
}
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
// 退格键, 遇到成对的符号时,同时删除
|
||||||
|
case 8:
|
||||||
|
if (!selected) {
|
||||||
|
let pos = $el.selectionStart
|
||||||
|
let prev = this.#getCursorText(-1)
|
||||||
|
let next = this.#getCursorText(1)
|
||||||
|
|
||||||
|
if (
|
||||||
|
(prev === next && (prev === '"' || prev === "'")) ||
|
||||||
|
(prev === next && prev === '`') ||
|
||||||
|
(prev === '[' && next === ']') ||
|
||||||
|
(prev === '{' && next === '}') ||
|
||||||
|
(prev === '(' && next === ')')
|
||||||
|
) {
|
||||||
|
this.select(pos - 1, pos + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
// (
|
||||||
|
case 57:
|
||||||
|
if (ev.shiftKey) {
|
||||||
|
ev.preventDefault()
|
||||||
|
|
||||||
|
this.insert('(' + wrapTxt + ')', selected, (selected && 1) || 0)
|
||||||
|
this.#cursorMove(selected ? 0 : -1)
|
||||||
|
}
|
||||||
|
break
|
||||||
|
// )
|
||||||
|
case 48:
|
||||||
|
if (ev.shiftKey) {
|
||||||
|
let prev = this.#getCursorText(-1)
|
||||||
|
let next = this.#getCursorText(1)
|
||||||
|
if (prev === '(' && next === ')') {
|
||||||
|
ev.preventDefault()
|
||||||
|
this.#cursorMove(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case 219: // [ & {
|
||||||
|
ev.preventDefault()
|
||||||
|
this.insert(
|
||||||
|
ev.shiftKey ? `{${wrapTxt}}` : `[${wrapTxt}]`,
|
||||||
|
selected,
|
||||||
|
selected ^ 0
|
||||||
|
)
|
||||||
|
this.#cursorMove(selected ? 0 : -1)
|
||||||
|
break
|
||||||
|
// } & ]
|
||||||
|
case 221: {
|
||||||
|
let prev = this.#getCursorText(-1)
|
||||||
|
let next = this.#getCursorText(1)
|
||||||
|
if (ev.shiftKey) {
|
||||||
|
if (prev === '{' && next === '}') {
|
||||||
|
ev.preventDefault()
|
||||||
|
this.#cursorMove(1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (prev === '[' && next === ']') {
|
||||||
|
ev.preventDefault()
|
||||||
|
this.#cursorMove(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// `
|
||||||
|
case 192:
|
||||||
|
// ' & "
|
||||||
|
case 222:
|
||||||
|
if (ev.shiftKey && ev.keyCode === 192) {
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
let val = ev.keyCode === 192 ? '`' : ev.shiftKey ? '"' : "'"
|
||||||
|
let prev = this.#getCursorText(-1)
|
||||||
|
let next = this.#getCursorText(1)
|
||||||
|
|
||||||
|
if (prev === '' && next === val) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ev.preventDefault()
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
this.insert(val + wrapTxt + val, true, 1)
|
||||||
|
} else {
|
||||||
|
if (prev === next && prev === val) {
|
||||||
|
this.#cursorMove(1)
|
||||||
|
} else {
|
||||||
|
this.insert(val + wrapTxt + val)
|
||||||
|
this.#cursorMove(-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mounted() {}
|
mounted() {}
|
||||||
|
@ -704,6 +918,7 @@ class MEditor extends Component {
|
||||||
<div class="meditor">
|
<div class="meditor">
|
||||||
<header
|
<header
|
||||||
class=${classMap({ toolbar: true, active: this.#toolbar.length })}
|
class=${classMap({ toolbar: true, active: this.#toolbar.length })}
|
||||||
|
@click=${this.#toolbarClick}
|
||||||
>
|
>
|
||||||
${renderToolbar(this.#toolbar)}
|
${renderToolbar(this.#toolbar)}
|
||||||
</header>
|
</header>
|
||||||
|
@ -714,11 +929,11 @@ class MEditor extends Component {
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
:readOnly=${this.readOnly}
|
:readOnly=${this.readOnly}
|
||||||
:disabled=${this.disabled}
|
:disabled=${this.disabled}
|
||||||
@input=${function (ev) {
|
@keydown=${this.#handleKeydown}
|
||||||
// this.value = ev.target.value
|
@paste.prevent=${this.#handlePaste}
|
||||||
}}
|
@input=${this.#updatePreview}
|
||||||
></textarea>
|
></textarea>
|
||||||
<wc-markd class="preview"></wc-markd>
|
<wc-markd ref="view" class="preview"></wc-markd>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
|
Loading…
Reference in New Issue