test: fix tests
This commit is contained in:
parent
9ff091bd39
commit
a51aad42ee
|
@ -6,13 +6,13 @@ describe('@schlechtenburg/core', () => {
|
|||
const a = 'a';
|
||||
const b = 'b';
|
||||
|
||||
it('Should activate', () => {
|
||||
it('Should activate', async () => {
|
||||
const {
|
||||
activeBlockId,
|
||||
isActive,
|
||||
activate,
|
||||
deactivate,
|
||||
} = withSetup(() => useActivation(a));
|
||||
} = await withSetup(() => useActivation(a));
|
||||
|
||||
activate(a);
|
||||
expect(activeBlockId.value).toBe(a);
|
||||
|
@ -22,9 +22,9 @@ describe('@schlechtenburg/core', () => {
|
|||
expect(activeBlockId.value).toBe(b);
|
||||
expect(isActive.value).toBeFalsy();
|
||||
|
||||
deactivate();
|
||||
deactivate(activeBlockId.value);
|
||||
expect(isActive.value).toBeFalsy();
|
||||
expect(activeBlockId.value).toBe(undefined);
|
||||
expect(activeBlockId.value).toBe(null);
|
||||
|
||||
activate();
|
||||
expect(activeBlockId.value).toBe(a);
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { useFormatTypes } from './use-format-types';
|
||||
import { FormatTypeStore } from './use-format-types';
|
||||
import { createElement } from './create-element';
|
||||
import { mergePair } from './concat';
|
||||
import { OBJECT_REPLACEMENT_CHARACTER, ZWNBSP } from './special-characters';
|
||||
|
@ -15,8 +12,14 @@ function createEmptyValue(): RichTextValue {
|
|||
};
|
||||
}
|
||||
|
||||
function toFormat( { tagName, attributes }: { tagName: string, attributes: Record<string,any> } ): RichTextFormat {
|
||||
const { getFormatTypeForClassName, getFormatTypeForBareElement } = useFormatTypes();
|
||||
function toFormat(
|
||||
{ tagName, attributes }: { tagName: string, attributes: Record<string,any> },
|
||||
store: FormatTypeStore,
|
||||
): RichTextFormat {
|
||||
if (!store) {
|
||||
console.dir((new Error()).stack);
|
||||
}
|
||||
const { getFormatTypeForClassName, getFormatTypeForBareElement } = store;
|
||||
let formatType: RichTextFormatType|undefined;
|
||||
|
||||
if ( attributes && attributes.class ) {
|
||||
|
@ -81,14 +84,14 @@ function toFormat( { tagName, attributes }: { tagName: string, attributes: Recor
|
|||
};
|
||||
}
|
||||
|
||||
export const fromPlainText = (text: string) => create({ text });
|
||||
export const fromHTMLString = (html: string) => create({ html });
|
||||
export const fromHTMLElement = (htmlElement: Element, options: { preserveWhiteSpace?: boolean } = {}) => {
|
||||
export const fromPlainText = (text: string, store: FormatTypeStore) => create({ text }, store);
|
||||
export const fromHTMLString = (html: string, store: FormatTypeStore) => create({ html }, store);
|
||||
export const fromHTMLElement = (htmlElement: Element, options: { preserveWhiteSpace?: boolean } = {}, store: FormatTypeStore) => {
|
||||
const { preserveWhiteSpace = false } = options;
|
||||
const element = preserveWhiteSpace
|
||||
? htmlElement
|
||||
: collapseWhiteSpace( htmlElement );
|
||||
const richTextValue = create({ element });
|
||||
const richTextValue = create({ element }, store);
|
||||
Object.defineProperty( richTextValue, 'originalHTML', {
|
||||
value: htmlElement.innerHTML,
|
||||
} );
|
||||
|
@ -120,27 +123,23 @@ export const fromHTMLElement = (htmlElement: Element, options: { preserveWhiteSp
|
|||
* holds information about the formatting at the relevant text indices. Finally
|
||||
* `start` and `end` state which text indices are selected. They are only
|
||||
* provided if a `Range` was given.
|
||||
*
|
||||
* @param {Object} [$1] Optional named arguments.
|
||||
* @param {Element} [$1.element] Element to create value from.
|
||||
* @param {string} [$1.text] Text to create value from.
|
||||
* @param {string} [$1.html] HTML to create value from.
|
||||
* @param {Range} [$1.range] Range to create value from.
|
||||
* @return {RichTextValue} A rich text value.
|
||||
*/
|
||||
export function create({
|
||||
element,
|
||||
text,
|
||||
html,
|
||||
range,
|
||||
isEditableTree = false,
|
||||
}: {
|
||||
element?: Element|Node,
|
||||
text?: string,
|
||||
html?: string,
|
||||
range?: SimpleRange,
|
||||
isEditableTree?: boolean,
|
||||
} = {} ): RichTextValue {
|
||||
export function create(
|
||||
{
|
||||
element,
|
||||
text,
|
||||
html,
|
||||
range,
|
||||
isEditableTree = false,
|
||||
}: {
|
||||
element?: Element|Node,
|
||||
text?: string,
|
||||
html?: string,
|
||||
range?: SimpleRange,
|
||||
isEditableTree?: boolean,
|
||||
} = {},
|
||||
store: FormatTypeStore,
|
||||
): RichTextValue {
|
||||
if ( typeof text === 'string' && text.length > 0 ) {
|
||||
return {
|
||||
formats: Array( text.length ),
|
||||
|
@ -163,17 +162,12 @@ export function create({
|
|||
element,
|
||||
range,
|
||||
isEditableTree,
|
||||
} );
|
||||
}, store );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to accumulate the value's selection start and end from the current
|
||||
* node and range.
|
||||
*
|
||||
* @param {Object} accumulator Object to accumulate into.
|
||||
* @param {Node} node Node to create value with.
|
||||
* @param {Range} range Range to create value with.
|
||||
* @param {Object} value Value that is being accumulated.
|
||||
*/
|
||||
function accumulateSelection(
|
||||
accumulator: RichTextValue,
|
||||
|
@ -238,12 +232,6 @@ function accumulateSelection(
|
|||
|
||||
/**
|
||||
* Adjusts the start and end offsets from a range based on a text filter.
|
||||
*
|
||||
* @param {Node} node Node of which the text should be filtered.
|
||||
* @param {Range} range The range to filter.
|
||||
* @param {Function} filter Function to use to filter the text.
|
||||
*
|
||||
* @return {Object|undefined} Object containing range properties.
|
||||
*/
|
||||
function filterRange(node: Node, range?: SimpleRange, filter?: Function): SimpleRange|undefined {
|
||||
if ( ! range ) {
|
||||
|
@ -280,11 +268,6 @@ function filterRange(node: Node, range?: SimpleRange, filter?: Function): Simple
|
|||
*
|
||||
* @see
|
||||
* https://developer.mozilla.org/en-US/docs/Web/CSS/white-space-collapse#collapsing_of_white_space
|
||||
*
|
||||
* @param {HTMLElement} element
|
||||
* @param {boolean} isRoot
|
||||
*
|
||||
* @return {HTMLElement} New element with collapsed whitespace.
|
||||
*/
|
||||
function collapseWhiteSpace(element: HTMLElement, isRoot: boolean = true): HTMLElement {
|
||||
const clone = element.cloneNode( true ) as HTMLElement;
|
||||
|
@ -346,25 +329,18 @@ export function removeReservedCharacters( string: string ): string {
|
|||
|
||||
/**
|
||||
* Creates a Rich Text value from a DOM element and range.
|
||||
*
|
||||
* @param {Object} $1 Named arguments.
|
||||
* @param {Element} [$1.element] Element to create value from.
|
||||
* @param {Range} [$1.range] Range to create value from.
|
||||
* @param {boolean} [$1.isEditableTree]
|
||||
*
|
||||
* @return {RichTextValue} A rich text value.
|
||||
*/
|
||||
function createFromElement(
|
||||
{
|
||||
element,
|
||||
range,
|
||||
isEditableTree,
|
||||
}:
|
||||
{
|
||||
}: {
|
||||
element?:Element|Node,
|
||||
range?:SimpleRange,
|
||||
isEditableTree?: boolean,
|
||||
}
|
||||
},
|
||||
store: FormatTypeStore,
|
||||
): RichTextValue {
|
||||
const accumulator = createEmptyValue();
|
||||
|
||||
|
@ -435,14 +411,14 @@ function createFromElement(
|
|||
|
||||
if ( tagName === 'br' ) {
|
||||
accumulateSelection( accumulator, node, newRange, createEmptyValue() );
|
||||
mergePair( accumulator, create( { text: '\n' } ) );
|
||||
mergePair( accumulator, create( { text: '\n' }, store ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
const format = toFormat( {
|
||||
tagName,
|
||||
attributes: getAttributes( { element: node as HTMLElement } ),
|
||||
} );
|
||||
}, store );
|
||||
|
||||
// When a format type is declared as not editable, replace it with an
|
||||
// object replacement character and preserve the inner HTML.
|
||||
|
@ -472,7 +448,7 @@ function createFromElement(
|
|||
element: node as HTMLElement,
|
||||
range: newRange,
|
||||
isEditableTree,
|
||||
} );
|
||||
}, store );
|
||||
|
||||
accumulateSelection( accumulator, node, newRange, value );
|
||||
|
||||
|
@ -524,12 +500,6 @@ function createFromElement(
|
|||
|
||||
/**
|
||||
* Gets the attributes of an element in object shape.
|
||||
*
|
||||
* @param {Object} $1 Named arguments.
|
||||
* @param {Element} $1.element Element to get attributes from.
|
||||
*
|
||||
* @return {Object} Attribute object or `undefined` if the element has no
|
||||
* attributes.
|
||||
*/
|
||||
function getAttributes({ element }: { element: Element }): Record<string, any>{
|
||||
let accumulator: Record<string, any> = {};
|
||||
|
|
|
@ -1,17 +1,27 @@
|
|||
import { describe, expect, it, beforeAll } from 'vitest'
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { defineComponent, Component } from 'vue'
|
||||
import { useFormatTypes, FormatTypeStore } from '../use-format-types';
|
||||
import { create, removeReservedCharacters } from '../create';
|
||||
import { OBJECT_REPLACEMENT_CHARACTER, ZWNBSP } from '../special-characters';
|
||||
import { createElement } from '../create-element';
|
||||
import { getSparseArrayLength, spec, specWithRegistration } from './helpers';
|
||||
|
||||
describe( 'create', () => {
|
||||
const em = { type: 'em' };
|
||||
const strong = { type: 'strong' };
|
||||
const em = { type: 'em', attributes: {} };
|
||||
const strong = { type: 'strong', attributes: {} };
|
||||
|
||||
beforeAll( () => {
|
||||
// Initialize the rich-text store.
|
||||
// require( '../store' );
|
||||
} );
|
||||
let TestComponent: Component;
|
||||
let store: FormatTypeStore;
|
||||
beforeAll(async () => {
|
||||
TestComponent = defineComponent({
|
||||
setup () {
|
||||
return useFormatTypes();
|
||||
}
|
||||
});
|
||||
|
||||
store = mount(TestComponent).vm;
|
||||
});
|
||||
|
||||
spec.forEach( ( { description, html, createRange, record } ) => {
|
||||
if ( html === undefined ) {
|
||||
|
@ -25,7 +35,7 @@ describe( 'create', () => {
|
|||
const createdRecord = create( {
|
||||
element,
|
||||
range,
|
||||
} );
|
||||
}, store );
|
||||
const formatsLength = getSparseArrayLength( record.formats );
|
||||
const createdFormatsLength = getSparseArrayLength(
|
||||
createdRecord.formats
|
||||
|
@ -47,13 +57,13 @@ describe( 'create', () => {
|
|||
// eslint-disable-next-line jest/valid-title
|
||||
it( description, () => {
|
||||
if ( formatName ) {
|
||||
registerFormatType( formatName, formatType );
|
||||
store.registerFormatTypes( formatName, formatType );
|
||||
}
|
||||
|
||||
const result = create( { html } );
|
||||
const result = create({ html }, store);
|
||||
|
||||
if ( formatName ) {
|
||||
unregisterFormatType( formatName );
|
||||
store.unregisterFormatTypes( formatName );
|
||||
}
|
||||
|
||||
expect( result ).toEqual( expectedValue );
|
||||
|
@ -62,7 +72,7 @@ describe( 'create', () => {
|
|||
);
|
||||
|
||||
it( 'should reference formats', () => {
|
||||
const value = create( { html: '<em>te<strong>st</strong></em>' } );
|
||||
const value = create( { html: '<em>te<strong>st</strong></em>' }, store );
|
||||
|
||||
expect( value ).toEqual( {
|
||||
formats: [ [ em ], [ em ], [ em, strong ], [ em, strong ] ],
|
||||
|
@ -81,7 +91,7 @@ describe( 'create', () => {
|
|||
} );
|
||||
|
||||
it( 'should use different reference for equal format', () => {
|
||||
const value = create( { html: '<a href="#">a</a><a href="#">a</a>' } );
|
||||
const value = create( { html: '<a href="#">a</a><a href="#">a</a>' }, store );
|
||||
|
||||
// Format objects.
|
||||
expect( value.formats[ 0 ][ 0 ] ).not.toBe( value.formats[ 1 ][ 0 ] );
|
||||
|
@ -91,7 +101,7 @@ describe( 'create', () => {
|
|||
} );
|
||||
|
||||
it( 'should use different reference for different format', () => {
|
||||
const value = create( { html: '<a href="#">a</a><a href="#a">a</a>' } );
|
||||
const value = create( { html: '<a href="#">a</a><a href="#a">a</a>' }, store );
|
||||
|
||||
// Format objects.
|
||||
expect( value.formats[ 0 ][ 0 ] ).not.toBe( value.formats[ 1 ][ 0 ] );
|
||||
|
|
|
@ -1,15 +1,27 @@
|
|||
import { describe, expect, it, beforeAll } from 'vitest'
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { defineComponent, ComponentInstance, Component } from 'vue'
|
||||
import { useFormatTypes } from '../use-format-types';
|
||||
import { toDom, applyValue } from '../to-dom';
|
||||
import { createElement } from '../create-element';
|
||||
import { spec } from './helpers';
|
||||
|
||||
describe( 'recordToDom', () => {
|
||||
let TestComponent: Component;
|
||||
let wrapper: ComponentInstance<typeof TestComponent>;
|
||||
beforeAll(async () => {
|
||||
TestComponent = defineComponent({
|
||||
setup () {
|
||||
return useFormatTypes();
|
||||
}
|
||||
});
|
||||
|
||||
wrapper = mount(TestComponent);
|
||||
});
|
||||
spec.forEach( ( { description, record, startPath, endPath } ) => {
|
||||
// eslint-disable-next-line jest/valid-title
|
||||
it( description, () => {
|
||||
const { body, selection } = toDom( {
|
||||
value: record,
|
||||
} );
|
||||
const { body, selection } = toDom({ value: record }, wrapper.componentVM);
|
||||
expect( body ).toMatchSnapshot();
|
||||
expect( selection ).toEqual( { startPath, endPath } );
|
||||
} );
|
||||
|
|
|
@ -2,10 +2,10 @@ import { describe, expect, it, beforeAll } from 'vitest'
|
|||
import { mount } from '@vue/test-utils';
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
import { useFormatTypes } from '../use-format-types';
|
||||
import { useFormatTypes, FormatTypeStore } from '../use-format-types';
|
||||
import { create } from '../create';
|
||||
import { toHTMLString } from '../to-html-string';
|
||||
import { withSetup, specWithRegistration } from './helpers';
|
||||
import { specWithRegistration } from './helpers';
|
||||
|
||||
function createNode( HTML ) {
|
||||
const doc = document.implementation.createHTMLDocument( '' );
|
||||
|
@ -14,7 +14,8 @@ function createNode( HTML ) {
|
|||
}
|
||||
|
||||
describe( 'toHTMLString', () => {
|
||||
let TestComponent, wrapper;
|
||||
let TestComponent;
|
||||
let store: FormatTypeStore;
|
||||
beforeAll(async () => {
|
||||
TestComponent = defineComponent({
|
||||
setup () {
|
||||
|
@ -22,7 +23,7 @@ describe( 'toHTMLString', () => {
|
|||
}
|
||||
});
|
||||
|
||||
wrapper = mount(TestComponent);
|
||||
store = mount(TestComponent).vm;
|
||||
});
|
||||
|
||||
specWithRegistration.forEach(
|
||||
|
@ -42,13 +43,13 @@ describe( 'toHTMLString', () => {
|
|||
it.skip( description, () => {
|
||||
console.log(description, formatName);
|
||||
if ( formatName ) {
|
||||
wrapper.vm.addFormatTypes( { name: formatName, ...formatType } );
|
||||
store.registerFormatTypes( { name: formatName, ...formatType } );
|
||||
}
|
||||
|
||||
const result = toHTMLString( { value } );
|
||||
|
||||
if ( formatName ) {
|
||||
wrapper.vm.removeFormatTypes( formatName );
|
||||
store.unregisterFormatTypes( formatName );
|
||||
}
|
||||
|
||||
expect( result ).toEqual( html );
|
||||
|
|
|
@ -1,23 +1,12 @@
|
|||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
|
||||
import { toTree } from './to-tree';
|
||||
import { FormatTypeStore } from './use-format-types';
|
||||
import { createElement } from './create-element';
|
||||
import { isRangeEqual } from './is-range-equal';
|
||||
import { RichTextValue } from './types';
|
||||
|
||||
/** @typedef {import('./types').RichTextValue} RichTextValue */
|
||||
|
||||
/**
|
||||
* Creates a path as an array of indices from the given root node to the given
|
||||
* node.
|
||||
*
|
||||
* @param {Node} node Node to find the path of.
|
||||
* @param {HTMLElement} rootNode Root node to find the path from.
|
||||
* @param {Array} path Initial path to build on.
|
||||
*
|
||||
* @return {Array} The path from the root node to the node.
|
||||
*/
|
||||
function createPathToNode( node: Node, rootNode: HTMLElement, path: number[] ) {
|
||||
let workingNode: Node|null = node;
|
||||
|
@ -39,11 +28,6 @@ function createPathToNode( node: Node, rootNode: HTMLElement, path: number[] ) {
|
|||
|
||||
/**
|
||||
* Gets a node given a path (array of indices) from the given node.
|
||||
*
|
||||
* @param {HTMLElement} node Root node to find the wanted node in.
|
||||
* @param {Array} path Path (indices) to the wanted node.
|
||||
*
|
||||
* @return {Object} Object with the found node and the remaining offset (if any).
|
||||
*/
|
||||
function getNodeByPath( node: HTMLElement, path: number[] ) {
|
||||
let workingNode: Node = node;
|
||||
|
@ -105,19 +89,22 @@ function remove( node ) {
|
|||
return node.parentNode.removeChild( node );
|
||||
}
|
||||
|
||||
export function toDom({
|
||||
value,
|
||||
prepareEditableTree,
|
||||
isEditableTree = true,
|
||||
placeholder,
|
||||
doc = document,
|
||||
}: {
|
||||
value: RichTextValue,
|
||||
prepareEditableTree: Function,
|
||||
isEditableTree?: boolean,
|
||||
placeholder?: string,
|
||||
doc?: Document,
|
||||
}) {
|
||||
export function toDom(
|
||||
{
|
||||
value,
|
||||
prepareEditableTree,
|
||||
isEditableTree = true,
|
||||
placeholder,
|
||||
doc = document,
|
||||
}: {
|
||||
value: RichTextValue,
|
||||
prepareEditableTree: Function,
|
||||
isEditableTree?: boolean,
|
||||
placeholder?: string,
|
||||
doc?: Document,
|
||||
},
|
||||
store: FormatTypeStore,
|
||||
) {
|
||||
let startPath: number[] = [];
|
||||
let endPath: number[] = [];
|
||||
|
||||
|
@ -135,8 +122,6 @@ export function toDom({
|
|||
* Note: The current implementation will return a shared reference, reset on
|
||||
* each call to `createEmpty`. Therefore, you should not hold a reference to
|
||||
* the value to operate upon asynchronously, as it may have unexpected results.
|
||||
*
|
||||
* @return {Object} RichText tree.
|
||||
*/
|
||||
const createEmpty = () => createElement( doc, '' );
|
||||
|
||||
|
@ -162,7 +147,8 @@ export function toDom({
|
|||
},
|
||||
isEditableTree,
|
||||
placeholder,
|
||||
} );
|
||||
},
|
||||
store );
|
||||
|
||||
return {
|
||||
body: tree,
|
||||
|
@ -173,32 +159,28 @@ export function toDom({
|
|||
/**
|
||||
* Create an `Element` tree from a Rich Text value and applies the difference to
|
||||
* the `Element` tree contained by `current`.
|
||||
*
|
||||
* @param {Object} $1 Named arguments.
|
||||
* @param {RichTextValue} $1.value Value to apply.
|
||||
* @param {HTMLElement} $1.current The live root node to apply the element tree to.
|
||||
* @param {Function} [$1.prepareEditableTree] Function to filter editorable formats.
|
||||
* @param {boolean} [$1.__unstableDomOnly] Only apply elements, no selection.
|
||||
* @param {string} [$1.placeholder] Placeholder text.
|
||||
*/
|
||||
export function apply( {
|
||||
value,
|
||||
current,
|
||||
prepareEditableTree,
|
||||
placeholder,
|
||||
}: {
|
||||
value: RichTextValue,
|
||||
current: HTMLElement,
|
||||
prepareEditableTree: Function,
|
||||
placeholder: string,
|
||||
}) {
|
||||
export function apply(
|
||||
{
|
||||
value,
|
||||
current,
|
||||
prepareEditableTree,
|
||||
placeholder,
|
||||
}: {
|
||||
value: RichTextValue,
|
||||
current: HTMLElement,
|
||||
prepareEditableTree: Function,
|
||||
placeholder: string,
|
||||
},
|
||||
store: FormatTypeStore,
|
||||
) {
|
||||
// Construct a new element tree in memory.
|
||||
const { body, selection } = toDom( {
|
||||
const { body, selection } = toDom({
|
||||
value,
|
||||
prepareEditableTree,
|
||||
placeholder,
|
||||
doc: current.ownerDocument,
|
||||
} );
|
||||
}, store );
|
||||
|
||||
applyValue( body, current );
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { useFormatTypes } from './use-format-types';
|
||||
import { getActiveFormats } from './get-active-formats';
|
||||
import { OBJECT_REPLACEMENT_CHARACTER, ZWNBSP } from './special-characters';
|
||||
import { RichTextValue } from './types';
|
||||
import { FormatTypeStore } from './use-format-types';
|
||||
|
||||
function restoreOnAttributes( attributes: Record<string, any>, isEditableTree: boolean ): Record<string, any> {
|
||||
if ( isEditableTree ) {
|
||||
|
@ -25,40 +25,28 @@ function restoreOnAttributes( attributes: Record<string, any>, isEditableTree: b
|
|||
/**
|
||||
* Converts a format object to information that can be used to create an element
|
||||
* from (type, attributes and object).
|
||||
*
|
||||
* @param {Object} $1 Named parameters.
|
||||
* @param {string} $1.type The format type.
|
||||
* @param {string} $1.tagName The tag name.
|
||||
* @param {Object} $1.attributes The format attributes.
|
||||
* @param {Object} $1.unregisteredAttributes The unregistered format
|
||||
* attributes.
|
||||
* @param {boolean} $1.object Whether or not it is an object
|
||||
* format.
|
||||
* @param {boolean} $1.boundaryClass Whether or not to apply a boundary
|
||||
* class.
|
||||
* @param {boolean} $1.isEditableTree
|
||||
*
|
||||
* @return {Object} Information to be used for element creation.
|
||||
*/
|
||||
function fromFormat( {
|
||||
type,
|
||||
tagName,
|
||||
attributes,
|
||||
unregisteredAttributes,
|
||||
object,
|
||||
boundaryClass,
|
||||
isEditableTree,
|
||||
}: {
|
||||
type: string,
|
||||
tagName: string,
|
||||
attributes: Record<string, any>,
|
||||
unregisteredAttributes: Record<string, any>
|
||||
object: boolean,
|
||||
boundaryClass: boolean,
|
||||
isEditableTree: boolean,
|
||||
}) {
|
||||
const { findFormatTypeByName } = useFormatTypes();
|
||||
const formatType = findFormatTypeByName(type);
|
||||
function fromFormat(
|
||||
{
|
||||
type,
|
||||
tagName,
|
||||
attributes,
|
||||
unregisteredAttributes,
|
||||
object,
|
||||
boundaryClass,
|
||||
isEditableTree,
|
||||
}: {
|
||||
type: string,
|
||||
tagName?: string,
|
||||
attributes: Record<string, any>,
|
||||
unregisteredAttributes: Record<string, any>
|
||||
object: boolean,
|
||||
boundaryClass: boolean,
|
||||
isEditableTree: boolean,
|
||||
},
|
||||
store: FormatTypeStore,
|
||||
) {
|
||||
const formatType = store.getFormatTypeByName(type);
|
||||
|
||||
let elementAttributes: Record<string, any> = {};
|
||||
|
||||
|
@ -118,10 +106,6 @@ function fromFormat( {
|
|||
|
||||
/**
|
||||
* Checks if both arrays of formats up until a certain index are equal.
|
||||
*
|
||||
* @param {Array} a Array of formats to compare.
|
||||
* @param {Array} b Array of formats to compare.
|
||||
* @param {number} index Index to check until.
|
||||
*/
|
||||
function isEqualUntil<T>( a: T[], b: T[], index: number ): boolean {
|
||||
do {
|
||||
|
@ -133,37 +117,40 @@ function isEqualUntil<T>( a: T[], b: T[], index: number ): boolean {
|
|||
return true;
|
||||
}
|
||||
|
||||
export function toTree( {
|
||||
value,
|
||||
preserveWhiteSpace,
|
||||
createEmpty,
|
||||
append,
|
||||
getLastChild,
|
||||
getParent,
|
||||
isText,
|
||||
getText,
|
||||
remove,
|
||||
appendText,
|
||||
onStartIndex,
|
||||
onEndIndex,
|
||||
isEditableTree,
|
||||
placeholder,
|
||||
}: {
|
||||
value: RichTextValue,
|
||||
preserveWhiteSpace?: boolean,
|
||||
createEmpty: Function,
|
||||
append: Function,
|
||||
getLastChild: Function,
|
||||
getParent: Function,
|
||||
isText: Function,
|
||||
getText: Function,
|
||||
remove: Function,
|
||||
appendText: Function,
|
||||
onStartIndex?: Function,
|
||||
onEndIndex?: Function,
|
||||
isEditableTree?: boolean,
|
||||
placeholder?: string,
|
||||
}) {
|
||||
export function toTree(
|
||||
{
|
||||
value,
|
||||
preserveWhiteSpace,
|
||||
createEmpty,
|
||||
append,
|
||||
getLastChild,
|
||||
getParent,
|
||||
isText,
|
||||
getText,
|
||||
remove,
|
||||
appendText,
|
||||
onStartIndex,
|
||||
onEndIndex,
|
||||
isEditableTree,
|
||||
placeholder,
|
||||
}: {
|
||||
value: RichTextValue,
|
||||
preserveWhiteSpace?: boolean,
|
||||
createEmpty: Function,
|
||||
append: Function,
|
||||
getLastChild: Function,
|
||||
getParent: Function,
|
||||
isText: Function,
|
||||
getText: Function,
|
||||
remove: Function,
|
||||
appendText: Function,
|
||||
onStartIndex?: Function,
|
||||
onEndIndex?: Function,
|
||||
isEditableTree?: boolean,
|
||||
placeholder?: string,
|
||||
},
|
||||
store: FormatTypeStore,
|
||||
) {
|
||||
const { formats, replacements, text, start, end } = value;
|
||||
const formatsLength = formats.length + 1;
|
||||
const tree = createEmpty();
|
||||
|
@ -220,7 +207,7 @@ export function toTree( {
|
|||
unregisteredAttributes,
|
||||
boundaryClass,
|
||||
isEditableTree,
|
||||
} )
|
||||
}, store )
|
||||
);
|
||||
|
||||
if ( isText( pointer ) && getText( pointer ).length === 0 ) {
|
||||
|
@ -248,7 +235,7 @@ export function toTree( {
|
|||
continue;
|
||||
}
|
||||
const { type, attributes, innerHTML } = replacement;
|
||||
const formatType = getFormatType( type );
|
||||
const formatType = store.getFormatTypeByName( type );
|
||||
|
||||
if ( ! isEditableTree && type === 'script' ) {
|
||||
pointer = append(
|
||||
|
@ -256,7 +243,7 @@ export function toTree( {
|
|||
fromFormat( {
|
||||
type: 'script',
|
||||
isEditableTree,
|
||||
} )
|
||||
}, store )
|
||||
);
|
||||
append( pointer, {
|
||||
html: decodeURIComponent(
|
||||
|
@ -271,7 +258,7 @@ export function toTree( {
|
|||
...replacement,
|
||||
isEditableTree,
|
||||
boundaryClass: start === i && end === i + 1,
|
||||
} )
|
||||
}, store )
|
||||
);
|
||||
|
||||
if ( innerHTML ) {
|
||||
|
@ -286,7 +273,7 @@ export function toTree( {
|
|||
...replacement,
|
||||
object: true,
|
||||
isEditableTree,
|
||||
} )
|
||||
}, store )
|
||||
);
|
||||
}
|
||||
// Ensure pointer is text node.
|
||||
|
|
|
@ -6,17 +6,27 @@ import {
|
|||
import { RichTextFormatType } from './types';
|
||||
|
||||
export const SymFormatTypes = Symbol('Schlechtenburg rich text formats');
|
||||
export function useFormatTypes() {
|
||||
export interface FormatTypeStore {
|
||||
formatTypes: Ref<RichTextFormatType[]>;
|
||||
registerFormatTypes: (types: RichTextFormatType|RichTextFormatType[]) => void;
|
||||
unregisterFormatTypes: (types: string|string[]) => void;
|
||||
findFormatType: (fn: (f:RichTextFormatType) => boolean) => RichTextFormatType|undefined;
|
||||
getFormatTypeByName: (name: string) => RichTextFormatType|undefined;
|
||||
getFormatTypeForClassName: (name: string) => RichTextFormatType|undefined;
|
||||
getFormatTypeForBareElement: (name: string) => RichTextFormatType|undefined;
|
||||
}
|
||||
|
||||
export function useFormatTypes(): FormatTypeStore {
|
||||
const formatTypes: Ref<RichTextFormatType[]> = inject(SymFormatTypes, ref([]));
|
||||
|
||||
const addFormatTypes = (typesToAdd: RichTextFormatType|RichTextFormatType[]) => {
|
||||
const registerFormatTypes = (typesToAdd: RichTextFormatType|RichTextFormatType[]) => {
|
||||
formatTypes.value = [
|
||||
...formatTypes.value,
|
||||
...(Array.isArray(typesToAdd) ? typesToAdd : [typesToAdd]),
|
||||
];
|
||||
};
|
||||
|
||||
const removeFormatTypes = (typesToRemove: string|string[]) => {
|
||||
const unregisterFormatTypes = (typesToRemove: string|string[]) => {
|
||||
const isArray = Array.isArray(typesToRemove);
|
||||
|
||||
formatTypes.value = formatTypes.value.filter(({ name }) => {
|
||||
|
@ -29,16 +39,16 @@ export function useFormatTypes() {
|
|||
};
|
||||
|
||||
const findFormatType = (fn: (f:RichTextFormatType) => boolean) => formatTypes.value.find(type => fn(type));
|
||||
const findFormatTypeByName = (name: string) => formatTypes.value.find(type => type.name === name);
|
||||
const getFormatTypeByName = (name: string) => formatTypes.value.find(type => type.name === name);
|
||||
const getFormatTypeForClassName = (name: string) => formatTypes.value.find(type => type.className === name);
|
||||
const getFormatTypeForBareElement = (name: string) => formatTypes.value.find(type => type.tagName === name);
|
||||
|
||||
return {
|
||||
formatTypes,
|
||||
addFormatTypes,
|
||||
removeFormatTypes,
|
||||
findFormatTypeByName,
|
||||
registerFormatTypes,
|
||||
unregisterFormatTypes,
|
||||
findFormatType,
|
||||
getFormatTypeByName,
|
||||
getFormatTypeForClassName,
|
||||
getFormatTypeForBareElement,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue