mirror of
https://github.com/pipipi-pikachu/PPTist.git
synced 2025-04-15 02:20:00 +08:00
feat: 支持文本缩进
This commit is contained in:
parent
7b07629a58
commit
533b76ffee
@ -54,6 +54,28 @@
|
||||
font-style: italic;
|
||||
border-left: 5px solid #ccc;
|
||||
}
|
||||
|
||||
[data-indent='1'] {
|
||||
padding-left: 48px;
|
||||
}
|
||||
[data-indent='2'] {
|
||||
padding-left: 96px;
|
||||
}
|
||||
[data-indent='3'] {
|
||||
padding-left: 144px;
|
||||
}
|
||||
[data-indent='4'] {
|
||||
padding-left: 192px;
|
||||
}
|
||||
[data-indent='5'] {
|
||||
padding-left: 240px;
|
||||
}
|
||||
[data-indent='6'] {
|
||||
padding-left: 288px;
|
||||
}
|
||||
[data-indent='7'] {
|
||||
padding-left: 336px;
|
||||
}
|
||||
}
|
||||
|
||||
.ProseMirror-selectednode {
|
||||
|
@ -74,6 +74,7 @@ export default () => {
|
||||
const formatHTML = (html: string) => {
|
||||
const ast = toAST(html)
|
||||
let bulletFlag = false
|
||||
let indent = 0
|
||||
|
||||
const slices: pptxgen.TextProps[] = []
|
||||
const parse = (obj: AST[], baseStyleObj = {}) => {
|
||||
@ -124,6 +125,12 @@ export default () => {
|
||||
if (item.tagName === 'li') {
|
||||
bulletFlag = true
|
||||
}
|
||||
if (item.tagName === 'p') {
|
||||
if ('attributes' in item) {
|
||||
const dataIndentAttr = item.attributes.find(attr => attr.key === 'data-indent')
|
||||
if (dataIndentAttr && dataIndentAttr.value) indent = +dataIndentAttr.value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ('tagName' in item && item.tagName === 'br') {
|
||||
@ -184,6 +191,10 @@ export default () => {
|
||||
options.paraSpaceBefore = 0.1
|
||||
bulletFlag = false
|
||||
}
|
||||
if (indent) {
|
||||
options.indentLevel = indent
|
||||
indent = 0
|
||||
}
|
||||
|
||||
slices.push({ text, options })
|
||||
}
|
||||
|
@ -98,6 +98,8 @@ import {
|
||||
Magic,
|
||||
HighLight,
|
||||
Share,
|
||||
IndentLeft,
|
||||
IndentRight,
|
||||
} from '@icon-park/vue-next'
|
||||
|
||||
const icons = {
|
||||
@ -197,6 +199,8 @@ const icons = {
|
||||
Magic,
|
||||
HighLight,
|
||||
Share,
|
||||
IndentLeft,
|
||||
IndentRight,
|
||||
}
|
||||
|
||||
export default {
|
||||
|
66
src/utils/prosemirror/commands/setTextIndent.ts
Normal file
66
src/utils/prosemirror/commands/setTextIndent.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { Schema } from 'prosemirror-model'
|
||||
import { TextSelection, AllSelection, Transaction } from 'prosemirror-state'
|
||||
import { EditorView } from 'prosemirror-view'
|
||||
import { isList } from './toggleList'
|
||||
|
||||
function setNodeIndentMarkup(tr: Transaction, pos: number, delta: number): Transaction {
|
||||
if (!tr.doc) return tr
|
||||
|
||||
const node = tr.doc.nodeAt(pos)
|
||||
if (!node) return tr
|
||||
|
||||
const minIndent = 0
|
||||
const maxIndent = 7
|
||||
|
||||
let indent = (node.attrs.indent || 0) + delta
|
||||
if (indent < minIndent) indent = minIndent
|
||||
if (indent > maxIndent) indent = maxIndent
|
||||
|
||||
if (indent === node.attrs.indent) return tr
|
||||
|
||||
const nodeAttrs = {
|
||||
...node.attrs,
|
||||
indent,
|
||||
}
|
||||
|
||||
return tr.setNodeMarkup(pos, node.type, nodeAttrs, node.marks)
|
||||
}
|
||||
|
||||
const setTextIndent = (tr: Transaction, schema: Schema, delta: number): Transaction => {
|
||||
const { selection, doc } = tr
|
||||
if (!selection || !doc) return tr
|
||||
|
||||
if (!(selection instanceof TextSelection || selection instanceof AllSelection)) return tr
|
||||
|
||||
const { from, to } = selection
|
||||
|
||||
doc.nodesBetween(from, to, (node, pos) => {
|
||||
const nodeType = node.type
|
||||
|
||||
if (nodeType.name === 'paragraph' || nodeType.name === 'blockquote') {
|
||||
tr = setNodeIndentMarkup(tr, pos, delta)
|
||||
return false
|
||||
}
|
||||
else if (isList(node, schema)) return false
|
||||
return true
|
||||
})
|
||||
|
||||
return tr
|
||||
}
|
||||
|
||||
export const indentCommand = (view: EditorView, delta: number) => {
|
||||
const { state } = view
|
||||
const { schema, selection } = state
|
||||
|
||||
const tr = setTextIndent(
|
||||
state.tr.setSelection(selection),
|
||||
schema,
|
||||
delta,
|
||||
)
|
||||
if (tr.docChanged) {
|
||||
view.dispatch(tr)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
@ -3,7 +3,7 @@ import { Schema, Node, NodeType } from 'prosemirror-model'
|
||||
import { Transaction, EditorState } from 'prosemirror-state'
|
||||
import { findParentNode } from '../utils'
|
||||
|
||||
const isList = (node: Node, schema: Schema) => {
|
||||
export const isList = (node: Node, schema: Schema) => {
|
||||
return (
|
||||
node.type === schema.nodes.bullet_list ||
|
||||
node.type === schema.nodes.ordered_list
|
||||
|
@ -25,6 +25,9 @@ const paragraph: NodeSpec = {
|
||||
align: {
|
||||
default: '',
|
||||
},
|
||||
indent: {
|
||||
default: 0,
|
||||
},
|
||||
},
|
||||
content: 'inline*',
|
||||
group: 'block',
|
||||
@ -33,19 +36,25 @@ const paragraph: NodeSpec = {
|
||||
tag: 'p',
|
||||
getAttrs: dom => {
|
||||
const { textAlign } = (dom as HTMLElement).style
|
||||
|
||||
let align = (dom as HTMLElement).getAttribute('align') || textAlign || ''
|
||||
align = /(left|right|center|justify)/.test(align) ? align : ''
|
||||
|
||||
return { align }
|
||||
const indent = +((dom as HTMLElement).getAttribute('data-indent') || 0)
|
||||
|
||||
return { align, indent }
|
||||
}
|
||||
}
|
||||
],
|
||||
toDOM: (node: Node) => {
|
||||
const { align } = node.attrs
|
||||
const { align, indent } = node.attrs
|
||||
let style = ''
|
||||
if (align && align !== 'left') style += `text-align: ${align};`
|
||||
|
||||
return ['p', { style }, 0]
|
||||
const attr = { style }
|
||||
if (indent) attr['data-indent'] = indent
|
||||
|
||||
return ['p', attr, 0]
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -209,6 +209,15 @@
|
||||
</Tooltip>
|
||||
</CheckboxButtonGroup>
|
||||
|
||||
<ButtonGroup class="row">
|
||||
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="减小缩进">
|
||||
<Button style="flex: 1;" @click="emitRichTextCommand('indent', '-1')"><IconIndentLeft /></Button>
|
||||
</Tooltip>
|
||||
<Tooltip :mouseLeaveDelay="0" :mouseEnterDelay="0.5" title="增大缩进">
|
||||
<Button style="flex: 1;" @click="emitRichTextCommand('indent', '+1')"><IconIndentRight /></Button>
|
||||
</Tooltip>
|
||||
</ButtonGroup>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div class="row">
|
||||
|
@ -16,6 +16,7 @@ import { initProsemirrorEditor, createDocument } from '@/utils/prosemirror'
|
||||
import { findNodesWithSameMark, getTextAttrs, autoSelectAll, addMark, markActive, getFontsize } from '@/utils/prosemirror/utils'
|
||||
import emitter, { EmitterEvents, RichTextCommand } from '@/utils/emitter'
|
||||
import { alignmentCommand } from '@/utils/prosemirror/commands/setTextAlign'
|
||||
import { indentCommand } from '@/utils/prosemirror/commands/setTextIndent'
|
||||
import { toggleList } from '@/utils/prosemirror/commands/toggleList'
|
||||
|
||||
export default defineComponent({
|
||||
@ -192,6 +193,9 @@ export default defineComponent({
|
||||
else if (item.command === 'align' && item.value) {
|
||||
alignmentCommand(editorView, item.value)
|
||||
}
|
||||
else if (item.command === 'indent' && item.value) {
|
||||
indentCommand(editorView, +item.value)
|
||||
}
|
||||
else if (item.command === 'bulletList') {
|
||||
const { bullet_list: bulletList, list_item: listItem } = editorView.state.schema.nodes
|
||||
toggleList(bulletList, listItem)(editorView.state, editorView.dispatch)
|
||||
|
Loading…
x
Reference in New Issue
Block a user