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;
|
font-style: italic;
|
||||||
border-left: 5px solid #ccc;
|
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 {
|
.ProseMirror-selectednode {
|
||||||
|
@ -74,6 +74,7 @@ export default () => {
|
|||||||
const formatHTML = (html: string) => {
|
const formatHTML = (html: string) => {
|
||||||
const ast = toAST(html)
|
const ast = toAST(html)
|
||||||
let bulletFlag = false
|
let bulletFlag = false
|
||||||
|
let indent = 0
|
||||||
|
|
||||||
const slices: pptxgen.TextProps[] = []
|
const slices: pptxgen.TextProps[] = []
|
||||||
const parse = (obj: AST[], baseStyleObj = {}) => {
|
const parse = (obj: AST[], baseStyleObj = {}) => {
|
||||||
@ -124,6 +125,12 @@ export default () => {
|
|||||||
if (item.tagName === 'li') {
|
if (item.tagName === 'li') {
|
||||||
bulletFlag = true
|
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') {
|
if ('tagName' in item && item.tagName === 'br') {
|
||||||
@ -184,6 +191,10 @@ export default () => {
|
|||||||
options.paraSpaceBefore = 0.1
|
options.paraSpaceBefore = 0.1
|
||||||
bulletFlag = false
|
bulletFlag = false
|
||||||
}
|
}
|
||||||
|
if (indent) {
|
||||||
|
options.indentLevel = indent
|
||||||
|
indent = 0
|
||||||
|
}
|
||||||
|
|
||||||
slices.push({ text, options })
|
slices.push({ text, options })
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,8 @@ import {
|
|||||||
Magic,
|
Magic,
|
||||||
HighLight,
|
HighLight,
|
||||||
Share,
|
Share,
|
||||||
|
IndentLeft,
|
||||||
|
IndentRight,
|
||||||
} from '@icon-park/vue-next'
|
} from '@icon-park/vue-next'
|
||||||
|
|
||||||
const icons = {
|
const icons = {
|
||||||
@ -197,6 +199,8 @@ const icons = {
|
|||||||
Magic,
|
Magic,
|
||||||
HighLight,
|
HighLight,
|
||||||
Share,
|
Share,
|
||||||
|
IndentLeft,
|
||||||
|
IndentRight,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
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 { Transaction, EditorState } from 'prosemirror-state'
|
||||||
import { findParentNode } from '../utils'
|
import { findParentNode } from '../utils'
|
||||||
|
|
||||||
const isList = (node: Node, schema: Schema) => {
|
export const isList = (node: Node, schema: Schema) => {
|
||||||
return (
|
return (
|
||||||
node.type === schema.nodes.bullet_list ||
|
node.type === schema.nodes.bullet_list ||
|
||||||
node.type === schema.nodes.ordered_list
|
node.type === schema.nodes.ordered_list
|
||||||
|
@ -25,6 +25,9 @@ const paragraph: NodeSpec = {
|
|||||||
align: {
|
align: {
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
|
indent: {
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
content: 'inline*',
|
content: 'inline*',
|
||||||
group: 'block',
|
group: 'block',
|
||||||
@ -33,19 +36,25 @@ const paragraph: NodeSpec = {
|
|||||||
tag: 'p',
|
tag: 'p',
|
||||||
getAttrs: dom => {
|
getAttrs: dom => {
|
||||||
const { textAlign } = (dom as HTMLElement).style
|
const { textAlign } = (dom as HTMLElement).style
|
||||||
|
|
||||||
let align = (dom as HTMLElement).getAttribute('align') || textAlign || ''
|
let align = (dom as HTMLElement).getAttribute('align') || textAlign || ''
|
||||||
align = /(left|right|center|justify)/.test(align) ? align : ''
|
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) => {
|
toDOM: (node: Node) => {
|
||||||
const { align } = node.attrs
|
const { align, indent } = node.attrs
|
||||||
let style = ''
|
let style = ''
|
||||||
if (align && align !== 'left') style += `text-align: ${align};`
|
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>
|
</Tooltip>
|
||||||
</CheckboxButtonGroup>
|
</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 />
|
<Divider />
|
||||||
|
|
||||||
<div class="row">
|
<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 { findNodesWithSameMark, getTextAttrs, autoSelectAll, addMark, markActive, getFontsize } from '@/utils/prosemirror/utils'
|
||||||
import emitter, { EmitterEvents, RichTextCommand } from '@/utils/emitter'
|
import emitter, { EmitterEvents, RichTextCommand } from '@/utils/emitter'
|
||||||
import { alignmentCommand } from '@/utils/prosemirror/commands/setTextAlign'
|
import { alignmentCommand } from '@/utils/prosemirror/commands/setTextAlign'
|
||||||
|
import { indentCommand } from '@/utils/prosemirror/commands/setTextIndent'
|
||||||
import { toggleList } from '@/utils/prosemirror/commands/toggleList'
|
import { toggleList } from '@/utils/prosemirror/commands/toggleList'
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -192,6 +193,9 @@ export default defineComponent({
|
|||||||
else if (item.command === 'align' && item.value) {
|
else if (item.command === 'align' && item.value) {
|
||||||
alignmentCommand(editorView, item.value)
|
alignmentCommand(editorView, item.value)
|
||||||
}
|
}
|
||||||
|
else if (item.command === 'indent' && item.value) {
|
||||||
|
indentCommand(editorView, +item.value)
|
||||||
|
}
|
||||||
else if (item.command === 'bulletList') {
|
else if (item.command === 'bulletList') {
|
||||||
const { bullet_list: bulletList, list_item: listItem } = editorView.state.schema.nodes
|
const { bullet_list: bulletList, list_item: listItem } = editorView.state.schema.nodes
|
||||||
toggleList(bulletList, listItem)(editorView.state, editorView.dispatch)
|
toggleList(bulletList, listItem)(editorView.state, editorView.dispatch)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user