diff --git a/.eslintrc.js b/.eslintrc.js index 8e87abee..cb2a1bdf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -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', diff --git a/docs/src/demos/Examples/Formatting/index.vue b/docs/src/demos/Examples/Formatting/index.vue index 2d54b041..d573f20e 100644 --- a/docs/src/demos/Examples/Formatting/index.vue +++ b/docs/src/demos/Examples/Formatting/index.vue @@ -19,16 +19,16 @@ paragraph - + left - + center - + right - + justify diff --git a/docs/src/demos/Extensions/TextAlign/index.vue b/docs/src/demos/Extensions/TextAlign/index.vue index 0ecb20be..5c472b19 100644 --- a/docs/src/demos/Extensions/TextAlign/index.vue +++ b/docs/src/demos/Extensions/TextAlign/index.vue @@ -1,15 +1,15 @@ - + left - + center - + right - + justify diff --git a/packages/core/src/Editor.ts b/packages/core/src/Editor.ts index 59f30a38..6aa49edb 100644 --- a/packages/core/src/Editor.ts +++ b/packages/core/src/Editor.ts @@ -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) } /** diff --git a/packages/core/src/utils/isActive.ts b/packages/core/src/utils/isActive.ts new file mode 100644 index 00000000..8c0b63e5 --- /dev/null +++ b/packages/core/src/utils/isActive.ts @@ -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 +} diff --git a/packages/core/src/utils/markHasAttributes.ts b/packages/core/src/utils/markHasAttributes.ts index a76b1b53..6db66894 100644 --- a/packages/core/src/utils/markHasAttributes.ts +++ b/packages/core/src/utils/markHasAttributes.ts @@ -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) } diff --git a/packages/core/src/utils/objectIncludes.ts b/packages/core/src/utils/objectIncludes.ts new file mode 100644 index 00000000..a2853919 --- /dev/null +++ b/packages/core/src/utils/objectIncludes.ts @@ -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 +}