add support for only checking attributes in isActive

This commit is contained in:
Philipp Kühn 2020-11-30 00:04:30 +01:00
parent 9a18cce546
commit ec56158739
7 changed files with 76 additions and 25 deletions

View File

@ -66,6 +66,8 @@ module.exports = {
'@typescript-eslint/no-use-before-define': ['error'],
'no-dupe-class-members': 'off',
'@typescript-eslint/no-dupe-class-members': ['error'],
'lines-between-class-members': 'off',
'@typescript-eslint/lines-between-class-members': ['error'],
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-empty-interface': 'off',
'@typescript-eslint/explicit-module-boundary-type': 'off',

View File

@ -19,16 +19,16 @@
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
paragraph
</button>
<button @click="editor.chain().focus().setTextAlign('left').run()">
<button @click="editor.chain().focus().setTextAlign('left').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'left' }) }">
left
</button>
<button @click="editor.chain().focus().setTextAlign('center').run()">
<button @click="editor.chain().focus().setTextAlign('center').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'center' }) }">
center
</button>
<button @click="editor.chain().focus().setTextAlign('right').run()">
<button @click="editor.chain().focus().setTextAlign('right').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'right' }) }">
right
</button>
<button @click="editor.chain().focus().setTextAlign('justify').run()">
<button @click="editor.chain().focus().setTextAlign('justify').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'justify' }) }">
justify
</button>
</div>

View File

@ -1,15 +1,15 @@
<template>
<div v-if="editor">
<button @click="editor.chain().focus().setTextAlign('left').run()">
<button @click="editor.chain().focus().setTextAlign('left').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'left' }) }">
left
</button>
<button @click="editor.chain().focus().setTextAlign('center').run()">
<button @click="editor.chain().focus().setTextAlign('center').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'center' }) }">
center
</button>
<button @click="editor.chain().focus().setTextAlign('right').run()">
<button @click="editor.chain().focus().setTextAlign('right').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'right' }) }">
right
</button>
<button @click="editor.chain().focus().setTextAlign('justify').run()">
<button @click="editor.chain().focus().setTextAlign('justify').run()" :class="{ 'is-active': editor.isActive({ textAlign: 'justify' }) }">
justify
</button>
<button @click="editor.chain().focus().unsetTextAlign().run()">

View File

@ -3,12 +3,10 @@ import { EditorView } from 'prosemirror-view'
import { Schema, DOMParser, Node } from 'prosemirror-model'
import magicMethods from './utils/magicMethods'
import elementFromString from './utils/elementFromString'
import nodeIsActive from './utils/nodeIsActive'
import markIsActive from './utils/markIsActive'
import getNodeAttributes from './utils/getNodeAttributes'
import getMarkAttributes from './utils/getMarkAttributes'
import isActive from './utils/isActive'
import removeElement from './utils/removeElement'
import getSchemaTypeNameByName from './utils/getSchemaTypeNameByName'
import getHTMLFromFragment from './utils/getHTMLFromFragment'
import createStyleTag from './utils/createStyleTag'
import CommandManager from './CommandManager'
@ -350,18 +348,20 @@ export class Editor extends EventEmitter {
* Returns if the currently selected node or mark is active.
*
* @param name Name of the node or mark
* @param attrs Attributes of the node or mark
* @param attributes Attributes of the node or mark
*/
public isActive(name: string, attrs = {}) {
const schemaType = getSchemaTypeNameByName(name, this.schema)
public isActive(name: string, attributes?: {}): boolean;
public isActive(attributes: {}): boolean;
public isActive(nameOrAttributes: string, attributesOrUndefined?: {}): boolean {
const name = typeof nameOrAttributes === 'string'
? nameOrAttributes
: null
if (schemaType === 'node') {
return nodeIsActive(this.state, this.schema.nodes[name], attrs)
} if (schemaType === 'mark') {
return markIsActive(this.state, this.schema.marks[name], attrs)
}
const attributes = typeof nameOrAttributes === 'string'
? attributesOrUndefined
: nameOrAttributes
return false
return isActive(this.state, name, attributes)
}
/**

View File

@ -0,0 +1,45 @@
import { EditorState } from 'prosemirror-state'
import { Node, Mark } from 'prosemirror-model'
import nodeIsActive from './nodeIsActive'
import markIsActive from './markIsActive'
import objectIncludes from './objectIncludes'
import getSchemaTypeNameByName from './getSchemaTypeNameByName'
export default function isActive(state: EditorState, name: string | null, attributes: { [key: string ]: any } = {}): boolean {
if (name) {
const schemaType = getSchemaTypeNameByName(name, state.schema)
if (schemaType === 'node') {
return nodeIsActive(state, state.schema.nodes[name], attributes)
} if (schemaType === 'mark') {
return markIsActive(state, state.schema.marks[name], attributes)
}
}
if (!name) {
const { from, to, empty } = state.selection
let nodes: Node[] = []
let marks: Mark[] = []
if (empty) {
marks = state.selection.$head.marks()
}
state.doc.nodesBetween(from, to, node => {
nodes = [...nodes, node]
if (!empty) {
marks = [...marks, ...node.marks]
}
})
const anyNodeWithAttributes = nodes.find(node => objectIncludes(node.attrs, attributes))
const anyMarkWithAttributes = marks.find(mark => objectIncludes(mark.attrs, attributes))
if (anyNodeWithAttributes || anyMarkWithAttributes) {
return true
}
}
return false
}

View File

@ -3,16 +3,14 @@ import { MarkType } from 'prosemirror-model'
import getMarkAttributes from './getMarkAttributes'
import { AnyObject } from '../types'
import isEmptyObject from './isEmptyObject'
import objectIncludes from './objectIncludes'
export default function markHasAttributes(state: EditorState, type: MarkType, attributes: AnyObject) {
if (isEmptyObject(attributes)) {
return true
}
const originalAttrs = getMarkAttributes(state, type)
const originalAttributes = getMarkAttributes(state, type)
return !!Object
.keys(attributes)
.filter(key => attributes[key] === originalAttrs[key])
.length
return objectIncludes(originalAttributes, attributes)
}

View File

@ -0,0 +1,6 @@
export default function objectIncludes(object1: { [key: string ]: any }, object2: { [key: string ]: any }): boolean {
return !!Object
.keys(object2)
.filter(key => object2[key] === object1[key])
.length
}