精简markd编辑器

master
yutent 2023-10-16 15:14:39 +08:00
parent b52c95f210
commit c6a0cfbcef
3 changed files with 100 additions and 126 deletions

View File

@ -1,99 +0,0 @@
/**
* 基础拓展
* @author yutent<yutent.io@gmail.com>
* @date 2020/10/14 17:52:44
*/
const PLACEHOLDER = '在此输入文本'
function trim(str, sign) {
return str.replace(new RegExp('^' + sign + '|' + sign + '$', 'g'), '')
}
export default {
header() {
this.$refs.header.classList.add('fadein')
},
h(level) {
var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^(#+ )?/, '#'.repeat(level) + ' ')
this.insert(wrap, true)
},
quote() {
var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^(>+ )?/, '> ')
this.insert(wrap, true)
},
bold() {
var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '\\*\\*')
wrap = wrap === unwrap ? `**${wrap}**` : unwrap
this.insert(wrap, true)
},
italic() {
var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '_')
wrap = wrap === unwrap ? `_${wrap}_` : unwrap
this.insert(wrap, true)
},
through() {
var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '~~')
wrap = wrap === unwrap ? `~~${wrap}~~` : unwrap
this.insert(wrap, true)
},
list() {
var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^([+\-*] )?/, '+ ')
this.insert(wrap, true)
},
order() {
var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^(\d+\. )?/, '1. ')
this.insert(wrap, true)
},
line() {
this.insert('\n\n---\n\n', false)
},
code() {
var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '`')
wrap = wrap === unwrap ? `\`${wrap}\`` : unwrap
this.insert(wrap, true)
},
codeblock() {
this.insert('\n```language\n\n```\n')
},
table() {
this.$refs.table.classList.add('fadein')
},
link() {
this.$refs.link.classList.add('fadein')
},
fullscreen() {
this.classList.toggle('fullscreen')
},
preview() {
this.previewEnabled = !this.previewEnabled
this.$refs.view.classList.toggle('active')
if (this.previewEnabled) {
this.$refs.view.code = this.value
}
}
}

View File

@ -4,6 +4,8 @@
* @date 2020/10/12 18:23:23
*/
const PLACEHOLDER = '在此输入文本'
const ELEMS = {
a: function (str, attr, inner) {
let href = attr.match(attrExp('href'))
@ -82,6 +84,10 @@ export const DEFAULT_TOOLS = [
const LI_EXP = /<(ul|ol)>(?:(?!<ul|<ol)[\s\S])*?<\/\1>/gi
function trim(str, sign) {
return str.replace(new RegExp('^' + sign + '|' + sign + '$', 'g'), '')
}
// html标签的属性正则
function attrExp(field, flag = 'i') {
return new RegExp(field + '\\s?=\\s?["\']?([^"\']*)["\']?', flag)
@ -187,3 +193,91 @@ export function html2md(str) {
})
return str
}
export const Addon = {
header() {
this.$refs.header.classList.add('fadein')
},
h(level) {
var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^(#+ )?/, '#'.repeat(level) + ' ')
this.insert(wrap, true)
},
quote() {
var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^(>+ )?/, '> ')
this.insert(wrap, true)
},
bold() {
var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '\\*\\*')
wrap = wrap === unwrap ? `**${wrap}**` : unwrap
this.insert(wrap, true)
},
italic() {
var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '_')
wrap = wrap === unwrap ? `_${wrap}_` : unwrap
this.insert(wrap, true)
},
through() {
var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '~~')
wrap = wrap === unwrap ? `~~${wrap}~~` : unwrap
this.insert(wrap, true)
},
list() {
var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^([+\-*] )?/, '+ ')
this.insert(wrap, true)
},
order() {
var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^(\d+\. )?/, '1. ')
this.insert(wrap, true)
},
line() {
this.insert('\n\n---\n\n', false)
},
code() {
var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '`')
wrap = wrap === unwrap ? `\`${wrap}\`` : unwrap
this.insert(wrap, true)
},
codeblock() {
this.insert('\n```language\n\n```\n')
},
table() {
this.$refs.table.classList.add('fadein')
},
link() {
this.$refs.link.classList.add('fadein')
},
fullscreen() {
this.classList.toggle('fullscreen')
},
preview() {
this.previewEnabled = !this.previewEnabled
this.$refs.view.classList.toggle('active')
if (this.previewEnabled) {
this.$refs.view.code = this.value
}
}
}

View File

@ -6,44 +6,22 @@
import {
css,
raw,
html,
Component,
range,
bind,
unbind,
nextTick,
styleMap,
classMap,
outsideClick,
clearOutsideClick
} from 'wkit'
import { DEFAULT_TOOLS, html2md } from './helper.js'
import Addon from './addon.js'
import markd from '../markd/index.js'
import '../markd/index.js'
import '../form/input.js'
import '../form/button.js'
import '../code/index.js'
import { DEFAULT_TOOLS, html2md, Addon } from './helper.js'
import ICONS from './svg.js'
const COLORS = [
'#f3f5fb',
'#dae1e9',
'#62778d',
'#58d68d',
'#3fc2a7',
'#52a3de',
'#ac61ce',
'#ffb618',
'#e67e22',
'#ff5061',
'#ff0000',
'#000000'
]
// 获取一维数组转二维的行
function getY(i) {
return (i / 9) >> 0
@ -377,13 +355,10 @@ class MEditor extends Component {
#gridx = 0
#gridy = 0
#select = null
previewEnabled = false
#hideLayers() {
this.$refs.header.classList.remove('fadein')
// this.$refs.color.classList.remove('fadein')
this.$refs.link.classList.remove('fadein')
this.$refs.table.classList.remove('fadein')
}
@ -807,12 +782,15 @@ class MEditor extends Component {
mounted() {
this.#fixedPadding()
this._clickoutsideFn = outsideClick(this, _ => this.#hideLayers())
this.__observer = new ResizeObserver(this.#fixedPadding.bind(this))
this.__observer.observe(this)
}
unmounted() {
this.__observer?.disconnect()
clearOutsideClick(this._clickoutsideFn)
}
render() {
@ -846,6 +824,7 @@ class MEditor extends Component {
spellcheck="false"
:readOnly=${this.readOnly}
:disabled=${this.disabled}
@click=${this.#hideLayers}
@keydown=${this.#handleKeydown}
@paste.prevent=${this.#handlePaste}
@input=${this.#updatePreview}