diff --git a/src/editor/index.js b/src/editor/index.js
index d94f863..1ef8c9e 100644
--- a/src/editor/index.js
+++ b/src/editor/index.js
@@ -6,14 +6,11 @@
import {
css,
- raw,
html,
Component,
bind,
- unbind,
+ range,
nextTick,
- styleMap,
- classMap,
outsideClick,
clearOutsideClick
} from 'wkit'
@@ -201,49 +198,24 @@ class Editor extends Component {
}
}
- .scroll-outerbox {
+ .wrapper {
overflow: hidden;
- position: relative;
- flex: 1;
- padding: 5px 8px;
- }
- .scroll-innerbox {
overflow-y: auto;
- width: 100%;
- height: 100%;
- scrollbar-width: 0;
+ flex: 1;
+ padding: 6px 12px;
&::-webkit-scrollbar {
- display: none;
- }
-
- .wrapper {
- min-height: 100%;
- }
- }
-
- .is-vertical {
- position: absolute;
- right: 0;
- top: 0;
- display: flex;
- justify-content: flex-end;
- width: 10px;
- height: 100%;
-
- .thumb {
- display: block;
width: 6px;
- height: 0;
- border-radius: 5px;
- background: rgba(44, 47, 53, 0.25);
- cursor: default;
- transition: width 0.1s linear;
+ }
- &:hover {
- width: 10px;
- background: rgba(44, 47, 53, 0.5);
- }
+ &::-webkit-scrollbar-thumb {
+ visibility: hidden;
+ border-radius: 3px;
+ }
+
+ &:hover::-webkit-scrollbar-thumb {
+ visibility: visible;
+ background: rgba(0, 0, 0, 0.3);
}
}
@@ -251,6 +223,7 @@ class Editor extends Component {
width: 100%;
height: 100%;
min-height: 54px;
+ line-height: 1.5;
outline: none;
text-wrap: wrap;
word-break: break-all;
@@ -397,7 +370,6 @@ class Editor extends Component {
]
#value = ''
- #cache = { bar: 0, y: 0 }
#gridx = 0
#gridy = 0
@@ -419,33 +391,12 @@ class Editor extends Component {
if (this.$refs.editor) {
this.#value = val
this.$refs.editor.innerHTML = val
+ this.$emit('input')
} else {
nextTick(_ => (this.value = val))
}
}
- __init__() {
- //
- let { outer, inner, thumb } = this.$refs
- let height = outer.offsetHeight
- let scrollHeight = inner.scrollHeight + 10
-
- let bar = 50 // 滚动条的高度
- bar = (height * (height / scrollHeight)) >> 0
-
- if (bar < 50) {
- bar = 50
- }
-
- // 100%或主体高度比滚动条还短时不显示
- if (bar >= height) {
- bar = 0
- }
-
- this.#cache.bar = bar
- thumb.style.height = bar + 'px'
- }
-
#updateStat() {
if (this.$refs.editor) {
if (this.readOnly || this.disabled) {
@@ -458,23 +409,6 @@ class Editor extends Component {
}
}
- #fetchScroll(moveY) {
- let { bar } = this.#cache
- let { outer, thumb, inner } = this.$refs
- let height = outer.offsetHeight
- let scrollHeight = inner.scrollHeight + 10
-
- if (moveY < 0) {
- moveY = 0
- } else if (moveY > height - bar) {
- moveY = height - bar
- }
-
- inner.scrollTop = (scrollHeight - height) * (moveY / (height - bar))
- thumb.style.transform = `translateY(${moveY}px)`
- return moveY
- }
-
#hideLayers() {
this.$refs.font.classList.remove('fadein')
this.$refs.color.classList.remove('fadein')
@@ -707,83 +641,11 @@ class Editor extends Component {
}
mounted() {
- let startY,
- moveY,
- mousemoveFn = ev => {
- let { y } = this.#cache
- if (startY !== undefined) {
- moveY = this.#fetchScroll(y + ev.pageY - startY)
- }
- },
- mouseupFn = ev => {
- startY = undefined
- this.#cache.y = moveY || 0
- delete this._active
- unbind(document, 'mousemove', mousemoveFn)
- unbind(document, 'mouseup', mouseupFn)
- }
-
this.exec('styleWithCSS', true)
-
- bind(this.$refs.thumb, 'mousedown', ev => {
- startY = ev.pageY
-
- this._active = true
- this.#hideLayers()
-
- bind(document, 'mousemove', mousemoveFn)
- bind(document, 'mouseup', mouseupFn)
- })
-
- // 鼠标滚动事件
- bind(this.$refs.inner, 'scroll', ev => {
- // 拖拽时忽略滚动事件
- if (this._active) {
- return
- }
-
- let { bar, y } = this.#cache
- let { outer, thumb, inner } = this.$refs
- let height = outer.offsetHeight
- let scrollHeight = inner.scrollHeight + 10
- let scrollTop = inner.scrollTop
-
- this.#hideLayers()
-
- // y轴 都为0时, 不作任何处理
- if (bar === 0) {
- return
- }
-
- // 修正滚动条的位置
- // 滚动比例 y 滚动条的可移动距离
- let fixedY = ~~((scrollTop / (scrollHeight - height)) * (height - bar))
-
- if (fixedY !== y) {
- this.#cache.y = fixedY
- thumb.style.transform = `translateY(${fixedY}px)`
- }
- })
-
this._clickoutsideFn = outsideClick(this, _ => this.#hideLayers())
-
- this._scrollFn = new ResizeObserver(this.__init__.bind(this))
- this._scrollFn.observe(this.$refs.cont)
-
- this._inputFn = new MutationObserver(_ => {
- this.$emit('input')
- })
-
- this._inputFn.observe(this.$refs.editor, {
- childList: true,
- subtree: true,
- characterData: true
- })
}
unmounted() {
- this._scrollFn?.disconnect()
- this._inputFn?.disconnect()
clearOutsideClick(this._clickoutsideFn)
}
@@ -809,22 +671,17 @@ class Editor extends Component {
`
)}
-
diff --git a/src/meditor/addon.js b/src/meditor/addon.js
index dd78c1d..57273b8 100644
--- a/src/meditor/addon.js
+++ b/src/meditor/addon.js
@@ -4,134 +4,94 @@
* @date 2020/10/14 17:52:44
*/
-import { offset } from 'wkit'
-
-var placeholder = '在此输入文本'
+const PLACEHOLDER = '在此输入文本'
function trim(str, sign) {
return str.replace(new RegExp('^' + sign + '|' + sign + '$', 'g'), '')
}
-function docScroll(k = 'X') {
- return window[`page${k.toUpperCase()}Offset`]
-}
-
-// 通用的弹层触发
-function showDialog(dialog, elem) {
- var { left, top } = offset(elem)
- left -= docScroll('X')
- top += 29 - docScroll('Y')
- left += 'px'
- top += 'px'
- dialog.moveTo({ top, left })
- dialog.show()
- return Promise.resolve(dialog)
-}
-
export default {
- header(elem) {
+ header() {
this.$refs.header.classList.add('fadein')
},
h(level) {
- var wrap = this.selection(true) || placeholder
+ var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^(#+ )?/, '#'.repeat(level) + ' ')
this.insert(wrap, true)
},
- quote(elem) {
- var wrap = this.selection(true) || placeholder
+ quote() {
+ var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^(>+ )?/, '> ')
this.insert(wrap, true)
},
- bold(elem) {
- var wrap = this.selection() || placeholder
+ bold() {
+ var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '\\*\\*')
wrap = wrap === unwrap ? `**${wrap}**` : unwrap
this.insert(wrap, true)
},
- italic(elem) {
- var wrap = this.selection() || placeholder
+ italic() {
+ var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '_')
wrap = wrap === unwrap ? `_${wrap}_` : unwrap
this.insert(wrap, true)
},
- through(elem) {
- var wrap = this.selection() || placeholder
+ through() {
+ var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '~~')
wrap = wrap === unwrap ? `~~${wrap}~~` : unwrap
this.insert(wrap, true)
},
- list(elem) {
- var wrap = this.selection(true) || placeholder
+ list() {
+ var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^([+\-*] )?/, '+ ')
this.insert(wrap, true)
},
- order(elem) {
- var wrap = this.selection(true) || placeholder
+ order() {
+ var wrap = this.selection(true) || PLACEHOLDER
wrap = wrap.replace(/^(\d+\. )?/, '1. ')
this.insert(wrap, true)
},
- line(elem) {
+ line() {
this.insert('\n\n---\n\n', false)
},
- code(elem) {
- var wrap = this.selection() || placeholder
+ code() {
+ var wrap = this.selection() || PLACEHOLDER
var unwrap = trim(wrap, '`')
wrap = wrap === unwrap ? `\`${wrap}\`` : unwrap
this.insert(wrap, true)
},
- codeblock(elem) {
+ codeblock() {
this.insert('\n```language\n\n```\n')
},
- table(elem) {
- // showDialog(this.__TABLE_ADDON__, elem)
+ table() {
this.$refs.table.classList.add('fadein')
},
- link(elem) {
- showDialog(this.__LINK_ADDON__, elem).then(dialog => {
- var wrap = this.selection() || placeholder
- dialog.__txt__.value = wrap
- })
+ link() {
+ this.$refs.link.classList.add('fadein')
},
- image(elem) {
- var $file = this.__ATTACH_ADDON__.querySelector('input')
-
- this._attach = 'image'
- $file.setAttribute('accept', 'image/*')
-
- showDialog(this.__ATTACH_ADDON__, elem)
- },
-
- attach(elem) {
- var $file = this.__ATTACH_ADDON__.querySelector('input')
- this._attach = 'file'
- $file.removeAttribute('accept')
- showDialog(this.__ATTACH_ADDON__, elem)
- },
-
- fullscreen(elem) {
+ fullscreen() {
this.classList.toggle('fullscreen')
- elem.classList.toggle('active')
},
- preview(elem) {
+ preview() {
this.previewEnabled = !this.previewEnabled
this.$refs.view.classList.toggle('active')
- elem.classList.toggle('active')
if (this.previewEnabled) {
this.$refs.view.code = this.value
}
diff --git a/src/meditor/helper.js b/src/meditor/helper.js
index d133522..b1b7b48 100644
--- a/src/meditor/helper.js
+++ b/src/meditor/helper.js
@@ -4,9 +4,6 @@
* @date 2020/10/12 18:23:23
*/
-import { html } from 'wkit'
-import ICONS from './svg.js'
-
const ELEMS = {
a: function (str, attr, inner) {
let href = attr.match(attrExp('href'))
@@ -83,31 +80,6 @@ export const DEFAULT_TOOLS = [
'preview'
]
-export const TOOL_TITLE = {
- header: '插入标题',
- h1: '一级标题',
- h2: '二级标题',
- h3: '三级标题',
- h4: '四级标题',
- h5: '五级标题',
- h6: '六级标题',
- quote: '引用文本',
- bold: '粗体',
- italic: '斜体',
- through: '横线',
- list: '无序列表',
- order: '有序列表',
- line: '分割线',
- code: '行内代码',
- codeblock: '插入代码块',
- table: '插入表格',
- link: '插入连接',
- image: '上传图片',
- attach: '上传附件',
- fullscreen: '全屏编辑',
- preview: '预览'
-}
-
const LI_EXP = /<(ul|ol)>(?:(?!/gi
// html标签的属性正则
@@ -126,21 +98,6 @@ function tagExp(tag, open) {
return new RegExp(exp, 'gi')
}
-/**
- * 渲染工具栏图标
- */
-export function renderToolbar(list = [], dict = {}, showText = false) {
- return list.map(it => {
- let title = showText ? '' : dict[it]
- let text = showText ? dict[it] || '' : ''
-
- return html`
-
- ${text}
- `
- })
-}
-
/**
* html转成md
*/
diff --git a/src/meditor/index.js b/src/meditor/index.js
index abc1491..1742770 100644
--- a/src/meditor/index.js
+++ b/src/meditor/index.js
@@ -9,6 +9,7 @@ import {
raw,
html,
Component,
+ range,
bind,
unbind,
nextTick,
@@ -18,7 +19,7 @@ import {
clearOutsideClick
} from 'wkit'
-import { renderToolbar, DEFAULT_TOOLS, html2md } from './helper.js'
+import { DEFAULT_TOOLS, html2md } from './helper.js'
import Addon from './addon.js'
import markd from '../markd/index.js'
@@ -26,6 +27,8 @@ import '../form/input.js'
import '../form/button.js'
import '../code/index.js'
+import ICONS from './svg.js'
+
const COLORS = [
'#f3f5fb',
'#dae1e9',
@@ -83,6 +86,7 @@ class MEditor extends Component {
display: flex;
min-width: 200px;
max-height: 720px;
+ min-height: 64px;
border-radius: 3px;
transition: box-shadow 0.15s linear;
background: var(--wc-meditor-background, #fff);
@@ -135,6 +139,12 @@ class MEditor extends Component {
fill: currentColor;
color: #62778d;
}
+ input {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ }
&:hover,
&.active {
@@ -155,7 +165,6 @@ class MEditor extends Component {
flex: 1;
display: flex;
width: 100%;
- min-height: 200px;
border-radius: 3px;
.editor,
@@ -197,16 +206,12 @@ class MEditor extends Component {
`,
css`
:host([readonly]) {
- .editor {
- cursor: default;
- opacity: 0.8;
- }
+ cursor: default;
+ opacity: 0.8;
}
:host([disabled]) {
- .editor {
- cursor: not-allowed;
- opacity: 0.6;
- }
+ cursor: not-allowed;
+ opacity: 0.6;
}
:host([readonly]),
:host([disabled]) {
@@ -235,6 +240,7 @@ class MEditor extends Component {
css`
.font-layer,
+ .link-layer,
.table-layer {
visibility: hidden;
position: absolute;
@@ -310,119 +316,16 @@ class MEditor extends Component {
}
}
- .addon-link {
- width: 320px;
- padding: 8px 5px;
- background: #fff;
- font-size: 13px;
+ .link-layer {
+ display: flex;
+ flex-direction: column;
+ left: 330px;
+ width: 230px;
+ padding: 8px;
- li {
- display: flex;
- align-items: center;
- padding: 0 12px;
- margin-top: 6px;
-
- label {
- width: 60px;
- margin-right: 8px;
- }
-
- wc-input {
- flex: 1;
- }
-
- wc-button {
- width: 80px;
- }
- }
- }
-
- .addon-attach {
- width: 320px;
- padding: 8px 5px;
- background: #fff;
- font-size: 13px;
-
- .tabs {
- display: flex;
- border-bottom: 1px solid var(--color-plain-2);
- user-select: none;
-
- span {
- height: 28px;
- padding: 0 8px;
- line-height: 28px;
- cursor: pointer;
-
- &.active {
- color: var(--color-teal-1);
- }
- }
- }
-
- .remote,
- .locale {
- display: none;
-
- &.active {
- display: block;
- }
- }
-
- .locale {
- height: 120px;
- padding: 24px 32px;
-
- .button {
- position: relative;
- width: 100%;
- height: 100%;
- padding: 12px 16px;
- line-height: 46px;
- border: 1px dashed var(--color-plain-3);
- border-radius: 4px;
- text-align: center;
- cursor: pointer;
- transition: background 0.1s ease-in-out;
-
- &::after {
- content: '点击选择文件,或拖拽文件到此处';
- }
- &:hover,
- &.active {
- background: rgba(255, 228, 196, 0.15);
- }
- }
-
- input {
- position: absolute;
- left: 0;
- top: 0;
- z-index: 0;
- width: 100%;
- height: 100%;
- opacity: 0;
- }
- }
-
- li {
- display: flex;
- align-items: center;
- padding: 0 12px;
- margin-top: 6px;
-
- label {
- width: 60px;
- margin-right: 8px;
- }
-
- wc-input {
- flex: 1;
- }
-
- wc-button {
- width: 80px;
- }
+ wc-button {
+ width: 40px;
+ margin-top: 8px;
}
}
`,
@@ -481,7 +384,7 @@ class MEditor extends Component {
#hideLayers() {
this.$refs.header.classList.remove('fadein')
// this.$refs.color.classList.remove('fadein')
- // this.$refs.link.classList.remove('fadein')
+ this.$refs.link.classList.remove('fadein')
this.$refs.table.classList.remove('fadein')
}
@@ -490,6 +393,7 @@ class MEditor extends Component {
if (ev && ev.type === 'change') {
file = ev.target.files[0]
ev.target.value = ''
+ t = ev.target.dataset.type === 'image' ? '!' : ''
}
this.$emit('upload', {
detail: {
@@ -564,6 +468,10 @@ class MEditor extends Component {
this.#hideLayers()
+ if (act === 'image' || act === 'attach') {
+ return
+ }
+
Addon[act].call(this, elem)
}
@@ -582,9 +490,7 @@ class MEditor extends Component {
if (value) {
this.$refs.link.classList.remove('fadein')
this.$refs.editor.focus()
- this.restoreSelection()
- this.exec(ACTTION.link, value)
- this.saveSelection()
+ this.insert(`[${value}](${value}) `)
this.$refs.linkinput.value = ''
}
}
@@ -889,14 +795,25 @@ class MEditor extends Component {
}
}
- mounted() {
- let pb = ~~(this.clientHeight * 0.6)
- pb = pb < 64 ? 64 : pb
- Addon.preview.call(this, this)
- this.$refs.editor.style.paddingBottom = pb + 'px'
+ #fixedPadding() {
+ if (this.clientHeight > 64) {
+ let pb = ~~(this.clientHeight * 0.6)
+ pb = pb < 64 ? 64 : pb
+ this.$refs.editor.style.paddingBottom = pb + 'px'
+ } else {
+ this.$refs.editor.style.cssText = 'padding-bottom:;'
+ }
}
- unmounted() {}
+ mounted() {
+ this.#fixedPadding()
+ this.__observer = new ResizeObserver(this.#fixedPadding.bind(this))
+ this.__observer.observe(this)
+ }
+
+ unmounted() {
+ this.__observer?.disconnect()
+ }
render() {
return html`
@@ -905,7 +822,22 @@ class MEditor extends Component {
class=${classMap({ toolbar: true, active: this.#toolbar.length })}
@click=${this.#toolbarClick}
>
- ${renderToolbar(this.#toolbar)}
+ ${this.#toolbar.map(it => {
+ return html`
+
+ ${it === 'image' || it === 'attach'
+ ? html``
+ : ''}
+ `
+ })}
+
@@ -942,9 +875,12 @@ class MEditor extends Component {
@mousemove=${this.#tableSelect}
@mouseleave=${this.#tableSelect}
>
- ${Array(81)
- .fill(0)
- .map((_, n) => html``)}
+ ${range(81).map((_, n) => html``)}
+
+
+
+
+ 插入
`