From 083d76cef79bea9607113cf5c9c92a241d827371 Mon Sep 17 00:00:00 2001 From: Federico Date: Thu, 14 Mar 2024 21:33:24 -0300 Subject: [PATCH 01/17] Migrate to Typescript --- .eslintrc.js => .eslintrc.cjs | 51 +++-- .prettierrc | 10 +- package.json | 15 +- src/augmentation.ts | 22 ++ src/autoformatmath.ts | 59 ++++++ src/automath.ts | 137 ++++++++++++ src/index.ts | 6 + src/katex.d.ts | 153 ++++++++++++++ src/math.ts | 16 ++ src/mathcommand.ts | 64 ++++++ src/mathediting.ts | 309 +++++++++++++++++++++++++++ src/mathui.ts | 285 +++++++++++++++++++++++++ src/svg.d.ts | 4 + src/ui/mainformview.ts | 284 +++++++++++++++++++++++++ src/ui/mathview.ts | 80 +++++++ src/utils.ts | 346 ++++++++++++++++++++++++++++++ tsconfig.json | 109 ++++++++++ yarn.lock | 385 +++++++++++++++++++++++----------- 18 files changed, 2188 insertions(+), 147 deletions(-) rename .eslintrc.js => .eslintrc.cjs (50%) create mode 100644 src/augmentation.ts create mode 100644 src/autoformatmath.ts create mode 100644 src/automath.ts create mode 100644 src/index.ts create mode 100644 src/katex.d.ts create mode 100644 src/math.ts create mode 100644 src/mathcommand.ts create mode 100644 src/mathediting.ts create mode 100644 src/mathui.ts create mode 100644 src/svg.d.ts create mode 100644 src/ui/mainformview.ts create mode 100644 src/ui/mathview.ts create mode 100644 src/utils.ts create mode 100644 tsconfig.json diff --git a/.eslintrc.js b/.eslintrc.cjs similarity index 50% rename from .eslintrc.js rename to .eslintrc.cjs index 137d49c..33b7fac 100644 --- a/.eslintrc.js +++ b/.eslintrc.cjs @@ -1,37 +1,56 @@ -/* eslint-env node */ - -'use strict'; - module.exports = { - extends: 'ckeditor5', + extends: [ + "ckeditor5", + "plugin:@typescript-eslint/strict", + "plugin:@typescript-eslint/stylistic-type-checked", + ], root: true, + plugins: ["@typescript-eslint"], + parser: "@typescript-eslint/parser", + parserOptions: { + project: true, + __tsconfigRootDir: __dirname, + ecmaVersion: "latest", + sourceType: "module", + }, globals: { - 'MathJax': true, - 'katex': true, - 'console': true + MathJax: true, + katex: true, + console: true, }, ignorePatterns: [ // Ignore the entire `build/` (the DLL build). - 'build/**' + "build/**", ], rules: { // This rule disallows importing core DLL packages directly. Imports should be done using the `ckeditor5` package. // Also, importing non-DLL packages is not allowed. If the package requires other features to work, they should be // specified as soft-requirements. // Read more: https://ckeditor.com/docs/ckeditor5/latest/builds/guides/migration/migration-to-26.html#soft-requirements. - 'ckeditor5-rules/ckeditor-imports': 'error', + "ckeditor5-rules/ckeditor-imports": "error", // This rule could not be found ??? - 'ckeditor5-rules/use-require-for-debug-mode-imports': 'off' + "ckeditor5-rules/use-require-for-debug-mode-imports": "off", + + "no-void": ["error", { allowAsStatement: true }], }, overrides: [ { - files: [ 'tests/**/*.js', 'sample/**/*.js' ], + files: ["tests/**/*.js", "sample/**/*.js"], rules: { // To write complex tests, you may need to import files that are not exported in DLL files by default. // Hence, imports CKEditor 5 packages in test files are not checked. - 'ckeditor5-rules/ckeditor-imports': 'off' - } - } - ] + "ckeditor5-rules/ckeditor-imports": "off", + }, + }, + { + env: { + node: true, + }, + files: [".eslintrc.{js,cjs}"], + parserOptions: { + sourceType: "script", + }, + }, + ], }; diff --git a/.prettierrc b/.prettierrc index d59927f..d688f6b 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,11 @@ { - "embeddedLanguageFormatting": "off" + "embeddedLanguageFormatting": "off", + "overrides": [ + { + "files": "*.json", + "options": { + "tabWidth": 2 + } + } + ] } diff --git a/package.json b/package.json index bf819f1..7599e53 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "ckeditor5-feature", "ckeditor5-plugin", "ckeditor5-math", - "katex" + "katex" ], "main": "src/index.js", "dependencies": { @@ -35,13 +35,16 @@ "@ckeditor/ckeditor5-table": "41.2.0", "@ckeditor/ckeditor5-theme-lark": "41.2.0", "@ckeditor/ckeditor5-upload": "41.2.0", - "eslint": "^7.32.0", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "eslint": "^8.57.0", "eslint-config-ckeditor5": "^5.3.0", "http-server": "^14.1.0", "husky": "^4.2.5", "lint-staged": "^10.2.6", "stylelint": "^13.13.1", - "stylelint-config-ckeditor5": ">=5.3.0" + "stylelint-config-ckeditor5": ">=5.3.0", + "typescript": "^5.4.2" }, "engines": { "node": ">=18.0.0", @@ -65,15 +68,15 @@ "scripts": { "dll:build": "ckeditor5-package-tools dll:build", "dll:serve": "http-server ./ -o sample/dll.html", - "lint": "eslint --quiet src/**/*.js", - "lint:fix": "eslint --quiet src/**/*.js --fix", + "lint": "eslint --quiet --ext .ts src/", + "lint:fix": "eslint --quiet --fix --ext .ts src/", "stylelint": "stylelint --quiet --allow-empty-input 'theme/**/*.css'", "test": "ckeditor5-package-tools test", "prepare": "yarn run dll:build", "start": "ckeditor5-package-tools start" }, "lint-staged": { - "**/*.js": [ + "**/*.ts": [ "eslint --quiet" ], "**/*.css": [ diff --git a/src/augmentation.ts b/src/augmentation.ts new file mode 100644 index 0000000..3f95f24 --- /dev/null +++ b/src/augmentation.ts @@ -0,0 +1,22 @@ +import type { KatexOptions } from './katex'; + +declare module '@ckeditor/ckeditor5-core' { + interface EditorConfig { + math?: { + engine?: + | 'mathjax' + | 'katex' + | ( ( equation: string, element: HTMLElement, display: boolean ) => void ) + | undefined; + lazyLoad?: undefined | ( () => Promise ); + outputType?: 'script' | 'span' | undefined; + className?: string | undefined; + forceOutputType?: boolean | undefined; + enablePreview?: boolean | undefined; + previewClassName?: Array | undefined; + popupClassName?: Array | undefined; + katexRenderOptions?: Partial | undefined; + }; + } +} + diff --git a/src/autoformatmath.ts b/src/autoformatmath.ts new file mode 100644 index 0000000..7962472 --- /dev/null +++ b/src/autoformatmath.ts @@ -0,0 +1,59 @@ +import { Plugin } from 'ckeditor5/src/core'; +import { global, logWarning } from 'ckeditor5/src/utils'; +// eslint-disable-next-line ckeditor5-rules/allow-imports-only-from-main-package-entry-point +import blockAutoformatEditing from '@ckeditor/ckeditor5-autoformat/src/blockautoformatediting'; +import Math from './math'; +import MathCommand from './mathcommand'; +import MathUI from './mathui'; + +export default class AutoformatMath extends Plugin { + public static get requires() { + return [ Math, 'Autoformat' ] as const; + } + + /** + * @inheritDoc + */ + public init(): void { + const editor = this.editor; + + if ( !editor.plugins.has( 'Math' ) ) { + logWarning( 'autoformat-math-feature-missing', editor ); + } + } + + public afterInit(): void { + const editor = this.editor; + const command = editor.commands.get( 'math' ); + + if ( command instanceof MathCommand ) { + const callback = () => { + if ( !command.isEnabled ) { + return false; + } + + command.display = true; + + // Wait until selection is removed. + global.window.setTimeout( + () => { + const mathUIInstance = editor.plugins.get( 'MathUI' ); + if ( mathUIInstance instanceof MathUI ) { + mathUIInstance._showUI(); + } + }, + 50 + ); + }; + + // @ts-expect-error: blockAutoformatEditing expects an Autoformat instance even though it works with any Plugin instance + blockAutoformatEditing( editor, this, /^\$\$$/, callback ); + // @ts-expect-error: blockAutoformatEditing expects an Autoformat instance even though it works with any Plugin instance + blockAutoformatEditing( editor, this, /^\\\[$/, callback ); + } + } + + public static get pluginName() { + return 'AutoformatMath' as const; + } +} diff --git a/src/automath.ts b/src/automath.ts new file mode 100644 index 0000000..1183ab1 --- /dev/null +++ b/src/automath.ts @@ -0,0 +1,137 @@ +import { Clipboard } from 'ckeditor5/src/clipboard'; +import { Plugin, type Editor } from 'ckeditor5/src/core'; +import { LivePosition, LiveRange } from 'ckeditor5/src/engine'; +import { Undo } from 'ckeditor5/src/undo'; +import { global } from 'ckeditor5/src/utils'; +import { extractDelimiters, hasDelimiters, delimitersCounts } from './utils'; + +export default class AutoMath extends Plugin { + public static get requires() { + return [ Clipboard, Undo ] as const; + } + + public static get pluginName() { + return 'AutoMath' as const; + } + + private _timeoutId: null | number; + private _positionToInsert: null | LivePosition; + + constructor( editor: Editor ) { + super( editor ); + + this._timeoutId = null; + + this._positionToInsert = null; + } + + public init(): void { + const editor = this.editor; + const modelDocument = editor.model.document; + + this.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', () => { + const firstRange = modelDocument.selection.getFirstRange(); + if ( !firstRange ) { + return; + } + + const leftLivePosition = LivePosition.fromPosition( firstRange.start ); + leftLivePosition.stickiness = 'toPrevious'; + + const rightLivePosition = LivePosition.fromPosition( firstRange.end ); + rightLivePosition.stickiness = 'toNext'; + + modelDocument.once( 'change:data', () => { + this._mathBetweenPositions( + leftLivePosition, + rightLivePosition + ); + + leftLivePosition.detach(); + rightLivePosition.detach(); + }, + { priority: 'high' } + ); + } + ); + + editor.commands.get( 'undo' )?.on( 'execute', () => { + if ( this._timeoutId ) { + global.window.clearTimeout( this._timeoutId ); + this._positionToInsert?.detach(); + + this._timeoutId = null; + this._positionToInsert = null; + } + }, { priority: 'high' } ); + } + + private _mathBetweenPositions( + leftPosition: LivePosition, + rightPosition: LivePosition + ) { + const editor = this.editor; + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const mathConfig = this.editor.config.get( 'math' )!; + + const equationRange = new LiveRange( leftPosition, rightPosition ); + const walker = equationRange.getWalker( { ignoreElementEnd: true } ); + + let text = ''; + + // Get equation text + for ( const node of walker ) { + if ( node.item.is( '$textProxy' ) ) { + text += node.item.data; + } + } + + text = text.trim(); + + // Skip if don't have delimiters + if ( !hasDelimiters( text ) || delimitersCounts( text ) !== 2 ) { + return; + } + + const mathCommand = editor.commands.get( 'math' ); + + // Do not anything if math element cannot be inserted at the current position + if ( !mathCommand?.isEnabled ) { + return; + } + + this._positionToInsert = LivePosition.fromPosition( leftPosition ); + + // With timeout user can undo conversation if want use plain text + this._timeoutId = global.window.setTimeout( () => { + editor.model.change( writer => { + this._timeoutId = null; + + writer.remove( equationRange ); + + let insertPosition: LivePosition | null; + + // Check if position where the math element should be inserted is still valid. + if ( this._positionToInsert?.root.rootName !== '$graveyard' ) { + insertPosition = this._positionToInsert; + } + + editor.model.change( innerWriter => { + const params = Object.assign( extractDelimiters( text ), { + type: mathConfig.outputType + } ); + const mathElement = innerWriter.createElement( params.display ? 'mathtex-display' : 'mathtex-inline', params + ); + + editor.model.insertContent( mathElement, insertPosition ); + + innerWriter.setSelection( mathElement, 'on' ); + } ); + + this._positionToInsert?.detach(); + this._positionToInsert = null; + } ); + }, 100 ); + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..433ed38 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,6 @@ +/** + * @module math + */ + +export { default as Math } from './math'; +export { default as AutoformatMath } from './autoformatmath'; diff --git a/src/katex.d.ts b/src/katex.d.ts new file mode 100644 index 0000000..da254b6 --- /dev/null +++ b/src/katex.d.ts @@ -0,0 +1,153 @@ +interface MathJax3 { + version: string; + tex2chtmlPromise?: ( input: string, options: { display: boolean } ) => Promise; + tex2svgPromise?: ( input: string, options: { display: boolean } ) => Promise; +} + +interface MathJax2 { + Hub: { Queue: ( callback: [string, MathJax2['Hub'], string | HTMLElement] | ( () => void ) ) => void }; +} + +interface Katex { + render( equation: string, el: HTMLElement, options: KatexOptions ): void; +} + +declare global { + // eslint-disable-next-line no-var + var CKEDITOR_MATH_LAZY_LOAD: undefined | Promise; + // eslint-disable-next-line no-var + var MathJax: undefined | MathJax2 | MathJax3; + // eslint-disable-next-line no-var + var katex: undefined | Katex; +} + +export interface KatexOptions { + + /** + * If `true`, math will be rendered in display mode + * (math in display style and center math on page) + * + * If `false`, math will be rendered in inline mode + * @default false + */ + displayMode?: boolean | undefined; + + /** + * Determines the markup language of the output. The valid choices are: + * - `html`: Outputs KaTeX in HTML only. + * - `mathml`: Outputs KaTeX in MathML only. + * - `htmlAndMathml`: Outputs HTML for visual rendering + * and includes MathML for accessibility. + * + * @default 'htmlAndMathml' + */ + output?: 'html' | 'mathml' | 'htmlAndMathml' | undefined; + + /** + * If `true`, display math has \tags rendered on the left + * instead of the right, like \usepackage[leqno]{amsmath} in LaTeX. + * + * @default false + */ + leqno?: boolean | undefined; + + /** + * If `true`, display math renders flush left with a 2em left margin, + * like \documentclass[fleqn] in LaTeX with the amsmath package. + * + * @default false + */ + fleqn?: boolean | undefined; + + /** + * If `true`, KaTeX will throw a `ParseError` when + * it encounters an unsupported command or invalid LaTex + * + * If `false`, KaTeX will render unsupported commands as + * text, and render invalid LaTeX as its source code with + * hover text giving the error, in color given by errorColor + * @default true + */ + throwOnError?: boolean | undefined; + + /** + * A Color string given in format `#XXX` or `#XXXXXX` + */ + errorColor?: string | undefined; + + /** + * A collection of custom macros. + * + * See `src/macros.js` for its usage + */ + macros?: unknown; + + /** + * Specifies a minimum thickness, in ems, for fraction lines, + * \sqrt top lines, {array} vertical lines, \hline, \hdashline, + * \underline, \overline, and the borders of \fbox, \boxed, and + * \fcolorbox. + */ + minRuleThickness?: number | undefined; + + /** + * If `true`, `\color` will work like LaTeX's `\textcolor` + * and takes 2 arguments + * + * If `false`, `\color` will work like LaTeX's `\color` + * and takes 1 argument + * + * In both cases, `\textcolor` works as in LaTeX + * + * @default false + */ + colorIsTextColor?: boolean | undefined; + + /** + * All user-specified sizes will be caped to `maxSize` ems + * + * If set to Infinity, users can make elements and space + * arbitrarily large + * + * @default Infinity + */ + maxSize?: number | undefined; + + /** + * Limit the number of macro expansions to specified number + * + * If set to `Infinity`, marco expander will try to fully expand + * as in LaTex + * + * @default 1000 + */ + maxExpand?: number | undefined; + + /** + * If `false` or `"ignore"`, allow features that make + * writing in LaTex convenient but not supported by LaTex + * + * If `true` or `"error"`, throw an error for such transgressions + * + * If `"warn"`, warn about behavior via `console.warn` + * + * @default "warn" + */ + strict?: boolean | string | Function | undefined; + + /** + * If `false` (do not trust input), prevent any commands that could enable adverse behavior, rendering them instead in errorColor. + * + * If `true` (trust input), allow all such commands. + * + * @default false + */ + trust?: boolean | ( ( context: TrustContext ) => boolean ) | undefined; + + /** + * Place KaTeX code in the global group. + * + * @default false + */ + globalGroup?: boolean | undefined; +} diff --git a/src/math.ts b/src/math.ts new file mode 100644 index 0000000..cfd390f --- /dev/null +++ b/src/math.ts @@ -0,0 +1,16 @@ +import { Plugin } from 'ckeditor5/src/core'; +import { Widget } from 'ckeditor5/src/widget'; + +import MathUI from './mathui'; +import MathEditing from './mathediting'; +import AutoMath from './automath'; + +export default class Math extends Plugin { + public static get requires() { + return [ MathEditing, MathUI, AutoMath, Widget ] as const; + } + + public static get pluginName() { + return 'Math' as const; + } +} diff --git a/src/mathcommand.ts b/src/mathcommand.ts new file mode 100644 index 0000000..644da0b --- /dev/null +++ b/src/mathcommand.ts @@ -0,0 +1,64 @@ +import { Command } from 'ckeditor5/src/core'; +import { getSelectedMathModelWidget } from './utils'; + +export default class MathCommand extends Command { + public value: string | null = null; + public execute( + equation: string, + display?: boolean, + outputType: 'script' | 'span' = 'script', + forceOutputType?: boolean + ): void { + const model = this.editor.model; + const selection = model.document.selection; + const selectedElement = selection.getSelectedElement(); + + model.change( writer => { + let mathtex; + if ( + selectedElement && + ( selectedElement.is( 'element', 'mathtex-inline' ) || + selectedElement.is( 'element', 'mathtex-display' ) ) + ) { + // Update selected element + const typeAttr = selectedElement.getAttribute( 'type' ); + + // Use already set type if found and is not forced + const type = forceOutputType ? + outputType : + typeAttr || outputType; + + mathtex = writer.createElement( + display ? 'mathtex-display' : 'mathtex-inline', + { equation, type, display } + ); + } else { + // Create new model element + mathtex = writer.createElement( + display ? 'mathtex-display' : 'mathtex-inline', + { equation, type: outputType, display } + ); + } + model.insertContent( mathtex ); + } ); + } + + public display = false; + + public refresh(): void { + const model = this.editor.model; + const selection = model.document.selection; + const selectedElement = selection.getSelectedElement(); + + this.isEnabled = + selectedElement === null || + selectedElement.is( 'element', 'mathtex-inline' ) || + selectedElement.is( 'element', 'mathtex-display' ); + + const selectedEquation = getSelectedMathModelWidget( selection ); + const value = selectedEquation?.getAttribute( 'equation' ); + this.value = typeof value === 'string' ? value : null; + const display = selectedEquation?.getAttribute( 'display' ); + this.display = typeof display === 'boolean' ? display : false; + } +} diff --git a/src/mathediting.ts b/src/mathediting.ts new file mode 100644 index 0000000..2958ad7 --- /dev/null +++ b/src/mathediting.ts @@ -0,0 +1,309 @@ +import MathCommand from './mathcommand'; +import { type Editor, Plugin } from 'ckeditor5/src/core'; +import { + toWidget, + Widget, + viewToModelPositionOutsideModelElement +} from 'ckeditor5/src/widget'; +import { renderEquation, extractDelimiters } from './utils'; +import type { DowncastWriter, Element } from 'ckeditor5/src/engine'; +import { CKEditorError, uid } from 'ckeditor5/src/utils'; + +export default class MathEditing extends Plugin { + public static get requires() { + return [ Widget ] as const; + } + + public static get pluginName() { + return 'MathEditing' as const; + } + + constructor( editor: Editor ) { + super( editor ); + editor.config.define( 'math', { + engine: 'mathjax', + outputType: 'script', + className: 'math-tex', + forceOutputType: false, + enablePreview: true, + previewClassName: [], + popupClassName: [], + katexRenderOptions: {} + } ); + } + + public init(): void { + const editor = this.editor; + editor.commands.add( 'math', new MathCommand( editor ) ); + + this._defineSchema(); + this._defineConverters(); + + editor.editing.mapper.on( + 'viewToModelPosition', + viewToModelPositionOutsideModelElement( + editor.model, + viewElement => viewElement.hasClass( 'math' ) + ) + ); + } + + private _defineSchema() { + const schema = this.editor.model.schema; + schema.register( 'mathtex-inline', { + allowWhere: '$text', + isInline: true, + isObject: true, + allowAttributes: [ 'equation', 'type', 'display' ] + } ); + + schema.register( 'mathtex-display', { + allowWhere: '$block', + isInline: false, + isObject: true, + allowAttributes: [ 'equation', 'type', 'display' ] + } ); + } + + private _defineConverters() { + const conversion = this.editor.conversion; + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const mathConfig = this.editor.config.get( 'math' )!; + + // View -> Model + conversion + .for( 'upcast' ) + // MathJax inline way (e.g. ) + .elementToElement( { + view: { + name: 'script', + attributes: { + type: 'math/tex' + } + }, + model: ( viewElement, { writer } ) => { + const child = viewElement.getChild( 0 ); + if ( child?.is( '$text' ) ) { + const equation = child.data.trim(); + return writer.createElement( 'mathtex-inline', { + equation, + type: mathConfig.forceOutputType ? + mathConfig.outputType : + 'script', + display: false + } ); + } + return null; + } + } ) + // MathJax display way (e.g. ) + .elementToElement( { + view: { + name: 'script', + attributes: { + type: 'math/tex; mode=display' + } + }, + model: ( viewElement, { writer } ) => { + const child = viewElement.getChild( 0 ); + if ( child?.is( '$text' ) ) { + const equation = child.data.trim(); + return writer.createElement( 'mathtex-display', { + equation, + type: mathConfig.forceOutputType ? + mathConfig.outputType : + 'script', + display: true + } ); + } + return null; + } + } ) + // CKEditor 4 way (e.g. \( \sqrt{\frac{a}{b}} \)) + .elementToElement( { + view: { + name: 'span', + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + classes: [ mathConfig.className! ] + }, + model: ( viewElement, { writer } ) => { + const child = viewElement.getChild( 0 ); + if ( child?.is( '$text' ) ) { + const equation = child.data.trim(); + + const params = Object.assign( extractDelimiters( equation ), { + type: mathConfig.forceOutputType ? + mathConfig.outputType : + 'span' + } ); + + return writer.createElement( + params.display ? 'mathtex-display' : 'mathtex-inline', + params + ); + } + + return null; + } + } ) + // KaTeX from Quill: https://github.com/quilljs/quill/blob/develop/formats/formula.js + .elementToElement( { + view: { + name: 'span', + classes: [ 'ql-formula' ] + }, + model: ( viewElement, { writer } ) => { + const equation = viewElement.getAttribute( 'data-value' ); + if ( equation == null ) { + /** + * Couldn't find equation on current element + * @error missing-equation + */ + throw new CKEditorError( 'missing-equation', { pluginName: 'math' } ); + } + return writer.createElement( 'mathtex-inline', { + equation: equation.trim(), + type: mathConfig.forceOutputType ? + mathConfig.outputType : + 'script', + display: false + } ); + } + } ); + + // Model -> View (element) + conversion + .for( 'editingDowncast' ) + .elementToElement( { + model: 'mathtex-inline', + view: ( modelItem, { writer } ) => { + const widgetElement = createMathtexEditingView( + modelItem, + writer + ); + return toWidget( widgetElement, writer ); + } + } ) + .elementToElement( { + model: 'mathtex-display', + view: ( modelItem, { writer } ) => { + const widgetElement = createMathtexEditingView( + modelItem, + writer + ); + return toWidget( widgetElement, writer ); + } + } ); + + // Model -> Data + conversion + .for( 'dataDowncast' ) + .elementToElement( { + model: 'mathtex-inline', + view: createMathtexView + } ) + .elementToElement( { + model: 'mathtex-display', + view: createMathtexView + } ); + + // Create view for editor + function createMathtexEditingView( + modelItem: Element, + writer: DowncastWriter + ) { + const equation = String( modelItem.getAttribute( 'equation' ) ); + const display = !!modelItem.getAttribute( 'display' ); + + const styles = + 'user-select: none; ' + + ( display ? '' : 'display: inline-block;' ); + const classes = + 'ck-math-tex ' + + ( display ? 'ck-math-tex-display' : 'ck-math-tex-inline' ); + + const mathtexView = writer.createContainerElement( + display ? 'div' : 'span', + { + style: styles, + class: classes + } + ); + + const uiElement = writer.createUIElement( + 'div', + null, + function( domDocument ) { + const domElement = this.toDomElement( domDocument ); + + void renderEquation( + equation, + domElement, + mathConfig.engine, + mathConfig.lazyLoad, + display, + false, + `math-editing-${ uid() }`, + mathConfig.previewClassName, + mathConfig.katexRenderOptions + ); + + return domElement; + } + ); + + writer.insert( writer.createPositionAt( mathtexView, 0 ), uiElement ); + + return mathtexView; + } + + // Create view for data + function createMathtexView( + modelItem: Element, + { writer }: { writer: DowncastWriter } + ) { + const equation = modelItem.getAttribute( 'equation' ); + if ( typeof equation != 'string' ) { + /** + * Couldn't find equation on current element + * @error missing-equation + */ + throw new CKEditorError( 'missing-equation', { pluginName: 'math' } ); + } + + const type = modelItem.getAttribute( 'type' ); + const display = modelItem.getAttribute( 'display' ); + + if ( type === 'span' ) { + const mathtexView = writer.createContainerElement( 'span', { + class: mathConfig.className + } ); + + if ( display ) { + writer.insert( + writer.createPositionAt( mathtexView, 0 ), + writer.createText( '\\[' + equation + '\\]' ) + ); + } else { + writer.insert( + writer.createPositionAt( mathtexView, 0 ), + writer.createText( '\\(' + equation + '\\)' ) + ); + } + + return mathtexView; + } else { + const mathtexView = writer.createContainerElement( 'script', { + type: display ? 'math/tex; mode=display' : 'math/tex' + } ); + + writer.insert( + writer.createPositionAt( mathtexView, 0 ), + writer.createText( equation ) + ); + + return mathtexView; + } + } + } +} diff --git a/src/mathui.ts b/src/mathui.ts new file mode 100644 index 0000000..92bc290 --- /dev/null +++ b/src/mathui.ts @@ -0,0 +1,285 @@ +import MathEditing from './mathediting'; +import MainFormView from './ui/mainformview'; +import mathIcon from '../theme/icons/math.svg'; +import { Plugin } from 'ckeditor5/src/core'; +import { ClickObserver } from 'ckeditor5/src/engine'; +import { + ButtonView, + ContextualBalloon, + clickOutsideHandler +} from 'ckeditor5/src/ui'; +import { CKEditorError, global, uid } from 'ckeditor5/src/utils'; +import { getBalloonPositionData } from './utils'; +import MathCommand from './mathcommand'; + +const mathKeystroke = 'Ctrl+M'; + +export default class MathUI extends Plugin { + public static get requires() { + return [ ContextualBalloon, MathEditing ] as const; + } + + public static get pluginName() { + return 'MathUI' as const; + } + + private _previewUid = `math-preview-${ uid() }`; + private _balloon: ContextualBalloon = this.editor.plugins.get( ContextualBalloon ); + public formView: MainFormView | null = null; + + public init(): void { + const editor = this.editor; + editor.editing.view.addObserver( ClickObserver ); + + this._createToolbarMathButton(); + + this.formView = this._createFormView(); + + this._enableUserBalloonInteractions(); + } + + public destroy(): void { + super.destroy(); + + this.formView?.destroy(); + + // Destroy preview element + const previewEl = global.document.getElementById( this._previewUid ); + if ( previewEl ) { + previewEl.parentNode?.removeChild( previewEl ); + } + } + + public _showUI(): void { + const editor = this.editor; + const mathCommand = editor.commands.get( 'math' ); + + if ( !mathCommand?.isEnabled ) { + return; + } + + this._addFormView(); + + this._balloon.showStack( 'main' ); + } + + private _createFormView() { + const editor = this.editor; + const mathCommand = editor.commands.get( 'math' ); + if ( !( mathCommand instanceof MathCommand ) ) { + /** + * Missing Math command + * @error math-command + */ + throw new CKEditorError( 'math-command' ); + } + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const mathConfig = editor.config.get( 'math' )!; + + const formView = new MainFormView( + editor.locale, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + mathConfig.engine!, + mathConfig.lazyLoad, + mathConfig.enablePreview, + this._previewUid, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + mathConfig.previewClassName!, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + mathConfig.popupClassName!, + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + mathConfig.katexRenderOptions! + ); + + formView.mathInputView.bind( 'value' ).to( mathCommand, 'value' ); + formView.displayButtonView.bind( 'isOn' ).to( mathCommand, 'display' ); + + // Form elements should be read-only when corresponding commands are disabled. + formView.mathInputView.bind( 'isReadOnly' ).to( mathCommand, 'isEnabled', value => !value ); + formView.saveButtonView.bind( 'isEnabled' ).to( mathCommand ); + formView.displayButtonView.bind( 'isEnabled' ).to( mathCommand ); + + // Listen to submit button click + this.listenTo( formView, 'submit', () => { + editor.execute( 'math', formView.equation, formView.displayButtonView.isOn, mathConfig.outputType, mathConfig.forceOutputType ); + this._closeFormView(); + } ); + + // Listen to cancel button click + this.listenTo( formView, 'cancel', () => { + this._closeFormView(); + } ); + + // Close plugin ui, if esc is pressed (while ui is focused) + formView.keystrokes.set( 'esc', ( _data, cancel ) => { + this._closeFormView(); + cancel(); + } ); + + return formView; + } + + private _addFormView() { + if ( this._isFormInPanel ) { + return; + } + + const editor = this.editor; + const mathCommand = editor.commands.get( 'math' ); + if ( !( mathCommand instanceof MathCommand ) ) { + /** + * Math command not found + * @error plugin-load + */ + throw new CKEditorError( 'plugin-load', { pluginName: 'math' } ); + } + + if ( this.formView == null ) { + return; + } + + this._balloon.add( { + view: this.formView, + position: getBalloonPositionData( editor ) + } ); + + if ( this._balloon.visibleView === this.formView ) { + this.formView.mathInputView.fieldView.element?.select(); + } + + // Show preview element + const previewEl = global.document.getElementById( this._previewUid ); + if ( previewEl && this.formView.previewEnabled ) { + // Force refresh preview + this.formView.mathView?.updateMath(); + } + + this.formView.equation = mathCommand.value ?? ''; + this.formView.displayButtonView.isOn = mathCommand.display || false; + } + + private _hideUI() { + if ( !this._isFormInPanel ) { + return; + } + + const editor = this.editor; + + this.stopListening( editor.ui, 'update' ); + this.stopListening( this._balloon, 'change:visibleView' ); + + editor.editing.view.focus(); + + // Remove form first because it's on top of the stack. + this._removeFormView(); + } + + private _closeFormView() { + const mathCommand = this.editor.commands.get( 'math' ); + if ( mathCommand?.value != null ) { + this._removeFormView(); + } else { + this._hideUI(); + } + } + + private _removeFormView() { + if ( this._isFormInPanel && this.formView ) { + this.formView.saveButtonView.focus(); + + this._balloon.remove( this.formView ); + + // Hide preview element + const previewEl = global.document.getElementById( this._previewUid ); + if ( previewEl ) { + previewEl.style.visibility = 'hidden'; + } + + this.editor.editing.view.focus(); + } + } + + private _createToolbarMathButton() { + const editor = this.editor; + const mathCommand = editor.commands.get( 'math' ); + if ( !mathCommand ) { + /** + * Math command not found + * @error plugin-load + */ + throw new CKEditorError( 'plugin-load', { pluginName: 'math' } ); + } + const t = editor.t; + + // Handle the `Ctrl+M` keystroke and show the panel. + editor.keystrokes.set( mathKeystroke, ( _keyEvtData, cancel ) => { + // Prevent focusing the search bar in FF and opening new tab in Edge. #153, #154. + cancel(); + + if ( mathCommand.isEnabled ) { + this._showUI(); + } + } ); + + this.editor.ui.componentFactory.add( 'math', locale => { + const button = new ButtonView( locale ); + + button.isEnabled = true; + button.label = t( 'Insert math' ); + button.icon = mathIcon; + button.keystroke = mathKeystroke; + button.tooltip = true; + button.isToggleable = true; + + button.bind( 'isEnabled' ).to( mathCommand, 'isEnabled' ); + + this.listenTo( button, 'execute', () => { + this._showUI(); + } ); + + return button; + } ); + } + + private _enableUserBalloonInteractions() { + const editor = this.editor; + const viewDocument = this.editor.editing.view.document; + this.listenTo( viewDocument, 'click', () => { + const mathCommand = editor.commands.get( 'math' ); + if ( mathCommand?.isEnabled && mathCommand.value ) { + this._showUI(); + } + } ); + + // Close the panel on the Esc key press when the editable has focus and the balloon is visible. + editor.keystrokes.set( 'Esc', ( _data, cancel ) => { + if ( this._isUIVisible ) { + this._hideUI(); + cancel(); + } + } ); + + // Close on click outside of balloon panel element. + if ( this.formView ) { + clickOutsideHandler( { + emitter: this.formView, + activator: () => !!this._isFormInPanel, + contextElements: this._balloon.view.element ? [ this._balloon.view.element ] : [], + callback: () => { this._hideUI(); } + } ); + } else { + throw new Error( 'missing form view' ); + } + } + + private get _isUIVisible() { + const visibleView = this._balloon.visibleView; + + return visibleView == this.formView; + } + + private get _isFormInPanel() { + return this.formView && this._balloon.hasView( this.formView ); + } +} diff --git a/src/svg.d.ts b/src/svg.d.ts new file mode 100644 index 0000000..4657938 --- /dev/null +++ b/src/svg.d.ts @@ -0,0 +1,4 @@ +declare module '*.svg' { + const src: string; + export default src; +} diff --git a/src/ui/mainformview.ts b/src/ui/mainformview.ts new file mode 100644 index 0000000..0af0e8a --- /dev/null +++ b/src/ui/mainformview.ts @@ -0,0 +1,284 @@ +import { icons } from 'ckeditor5/src/core'; +import { + ButtonView, + createLabeledInputText, + FocusCycler, + LabelView, + LabeledFieldView, + submitHandler, + SwitchButtonView, + View, + ViewCollection, + type InputTextView, + type FocusableView +} from 'ckeditor5/src/ui'; +import { Locale, FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils'; +import { extractDelimiters, hasDelimiters } from '../utils'; +import MathView from './mathview'; +import '../../theme/mathform.css'; +import type { KatexOptions } from '../katex'; + +const { check: checkIcon, cancel: cancelIcon } = icons; + +class MathInputView extends LabeledFieldView { + public value: null | string = null; + public isReadOnly = false; + + constructor( locale: Locale ) { + super( locale, createLabeledInputText ); + } +} + +export default class MainFormView extends View { + public saveButtonView: ButtonView; + public mathInputView: MathInputView; + public displayButtonView: SwitchButtonView; + public cancelButtonView: ButtonView; + public previewEnabled: boolean; + public previewLabel?: LabelView; + public mathView?: MathView; + public locale: Locale = new Locale(); + public lazyLoad: undefined | ( () => Promise ); + + constructor( + locale: Locale, + engine: + | 'mathjax' + | 'katex' + | ( ( + equation: string, + element: HTMLElement, + display: boolean, + ) => void ), + lazyLoad: undefined | ( () => Promise ), + previewEnabled = false, + previewUid: string, + previewClassName: Array, + popupClassName: Array, + katexRenderOptions: KatexOptions + ) { + super( locale ); + + const t = locale.t; + + // Submit button + this.saveButtonView = this._createButton( t( 'Save' ), checkIcon, 'ck-button-save', null ); + this.saveButtonView.type = 'submit'; + + // Equation input + this.mathInputView = this._createMathInput(); + + // Display button + this.displayButtonView = this._createDisplayButton(); + + // Cancel button + this.cancelButtonView = this._createButton( t( 'Cancel' ), cancelIcon, 'ck-button-cancel', 'cancel' ); + + this.previewEnabled = previewEnabled; + + let children = []; + if ( this.previewEnabled ) { + // Preview label + this.previewLabel = new LabelView( locale ); + this.previewLabel.text = t( 'Equation preview' ); + + // Math element + this.mathView = new MathView( engine, lazyLoad, locale, previewUid, previewClassName, katexRenderOptions ); + this.mathView.bind( 'display' ).to( this.displayButtonView, 'isOn' ); + + children = [ + this.mathInputView, + this.displayButtonView, + this.previewLabel, + this.mathView + ]; + } else { + children = [ + this.mathInputView, + this.displayButtonView + ]; + } + + // Add UI elements to template + this.setTemplate( { + tag: 'form', + attributes: { + class: [ + 'ck', + 'ck-math-form', + ...popupClassName + ], + tabindex: '-1', + spellcheck: 'false' + }, + children: [ + { + tag: 'div', + attributes: { + class: [ + 'ck-math-view' + ] + }, + children + }, + this.saveButtonView, + this.cancelButtonView + ] + } ); + } + + public render(): void { + super.render(); + + // Prevent default form submit event & trigger custom 'submit' + submitHandler( { + view: this + } ); + + // Register form elements to focusable elements + const childViews = [ + this.mathInputView, + this.displayButtonView, + this.saveButtonView, + this.cancelButtonView + ]; + + childViews.forEach( v => { + if ( v.element ) { + this._focusables.add( v ); + this.focusTracker.add( v.element ); + } + } ); + + // Listen to keypresses inside form element + if ( this.element ) { + this.keystrokes.listenTo( this.element ); + } + } + + public focus(): void { + this._focusCycler.focusFirst(); + } + + public get equation(): string { + return this.mathInputView.fieldView.element?.value ?? ''; + } + + public set equation( equation: string ) { + if ( this.mathInputView.fieldView.element ) { + this.mathInputView.fieldView.element.value = equation; + } + if ( this.previewEnabled && this.mathView ) { + this.mathView.value = equation; + } + } + + public focusTracker: FocusTracker = new FocusTracker(); + public keystrokes: KeystrokeHandler = new KeystrokeHandler(); + private _focusables = new ViewCollection(); + private _focusCycler: FocusCycler = new FocusCycler( { + focusables: this._focusables, + focusTracker: this.focusTracker, + keystrokeHandler: this.keystrokes, + actions: { + focusPrevious: 'shift + tab', + focusNext: 'tab' + } + } ); + + private _createMathInput() { + const t = this.locale.t; + + // Create equation input + const mathInput = new MathInputView( this.locale ); + const fieldView = mathInput.fieldView; + mathInput.infoText = t( 'Insert equation in TeX format.' ); + + const onInput = () => { + if ( fieldView.element != null ) { + let equationInput = fieldView.element.value.trim(); + + // If input has delimiters + if ( hasDelimiters( equationInput ) ) { + // Get equation without delimiters + const params = extractDelimiters( equationInput ); + + // Remove delimiters from input field + fieldView.element.value = params.equation; + + equationInput = params.equation; + + // update display button and preview + this.displayButtonView.isOn = params.display; + } + if ( this.previewEnabled && this.mathView ) { + // Update preview view + this.mathView.value = equationInput; + } + + this.saveButtonView.isEnabled = !!equationInput; + } + }; + + fieldView.on( 'render', onInput ); + fieldView.on( 'input', onInput ); + + return mathInput; + } + + private _createButton( + label: string, + icon: string, + className: string, + eventName: string | null + ) { + const button = new ButtonView( this.locale ); + + button.set( { + label, + icon, + tooltip: true + } ); + + button.extendTemplate( { + attributes: { + class: className + } + } ); + + if ( eventName ) { + button.delegate( 'execute' ).to( this, eventName ); + } + + return button; + } + + private _createDisplayButton() { + const t = this.locale.t; + + const switchButton = new SwitchButtonView( this.locale ); + + switchButton.set( { + label: t( 'Display mode' ), + withText: true + } ); + + switchButton.extendTemplate( { + attributes: { + class: 'ck-button-display-toggle' + } + } ); + + switchButton.on( 'execute', () => { + // Toggle state + switchButton.isOn = !switchButton.isOn; + + if ( this.previewEnabled && this.mathView ) { + // Update preview view + this.mathView.display = switchButton.isOn; + } + } ); + + return switchButton; + } +} diff --git a/src/ui/mathview.ts b/src/ui/mathview.ts new file mode 100644 index 0000000..ac8c3a5 --- /dev/null +++ b/src/ui/mathview.ts @@ -0,0 +1,80 @@ +import { View } from 'ckeditor5/src/ui'; +import { renderEquation } from '../utils'; +import type { Locale } from 'ckeditor5/src/utils'; +import type { KatexOptions } from '../katex'; + +export default class MathView extends View { + public value: string; + public display: boolean; + public previewUid: string; + public previewClassName: Array; + public katexRenderOptions: KatexOptions; + public engine: + | 'mathjax' + | 'katex' + | ( ( equation: string, element: HTMLElement, display: boolean ) => void ); + public lazyLoad: undefined | ( () => Promise ); + + constructor( + engine: + | 'mathjax' + | 'katex' + | ( ( + equation: string, + element: HTMLElement, + display: boolean, + ) => void ), + lazyLoad: undefined | ( () => Promise ), + locale: Locale, + previewUid: string, + previewClassName: Array, + katexRenderOptions: KatexOptions + ) { + super( locale ); + + this.engine = engine; + this.lazyLoad = lazyLoad; + this.previewUid = previewUid; + this.katexRenderOptions = katexRenderOptions; + this.previewClassName = previewClassName; + + this.set( 'value', '' ); + this.value = ''; + this.set( 'display', false ); + this.display = false; + + this.on( 'change', () => { + if ( this.isRendered ) { + this.updateMath(); + } + } ); + + this.setTemplate( { + tag: 'div', + attributes: { + class: [ 'ck', 'ck-math-preview' ] + } + } ); + } + + public updateMath(): void { + if ( this.element ) { + void renderEquation( + this.value, + this.element, + this.engine, + this.lazyLoad, + this.display, + true, + this.previewUid, + this.previewClassName, + this.katexRenderOptions + ); + } + } + + public render(): void { + super.render(); + this.updateMath(); + } +} diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 0000000..31a68e9 --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,346 @@ +import type { Editor } from 'ckeditor5/src/core'; +import type { + Element as CKElement, + DocumentSelection +} from 'ckeditor5/src/engine'; +import { BalloonPanelView } from 'ckeditor5/src/ui'; +import { CKEditorError, type PositioningFunction } from 'ckeditor5/src/utils'; +import type { KatexOptions, MathJax2, MathJax3 } from './katex'; + +export function getSelectedMathModelWidget( + selection: DocumentSelection +): null | CKElement { + const selectedElement = selection.getSelectedElement(); + + if ( + selectedElement && + ( selectedElement.is( 'element', 'mathtex-inline' ) || + selectedElement.is( 'element', 'mathtex-display' ) ) + ) { + return selectedElement; + } + + return null; +} + +// Simple MathJax 3 version check +export function isMathJaxVersion3( MathJax: unknown ): MathJax is MathJax3 { + return ( + MathJax != null && typeof MathJax == 'object' && 'version' in MathJax && typeof MathJax.version == 'string' && + MathJax.version.split( '.' ).length === 3 && + MathJax.version.split( '.' )[ 0 ] === '3' + ); +} + +// Simple MathJax 2 version check +export function isMathJaxVersion2( MathJax: unknown ): MathJax is MathJax2 { + return ( + MathJax != null && typeof MathJax == 'object' && 'Hub' in MathJax ); +} + +// Check if equation has delimiters. +export function hasDelimiters( text: string ): RegExpMatchArray | null { + return text.match( /^(\\\[.*?\\\]|\\\(.*?\\\))$/ ); +} + +// Find delimiters count +export function delimitersCounts( text: string ): number | undefined { + return text.match( /(\\\[|\\\]|\\\(|\\\))/g )?.length; +} + +// Extract delimiters and figure display mode for the model +export function extractDelimiters( equation: string ): { + equation: string; + display: boolean; +} { + equation = equation.trim(); + + // Remove delimiters (e.g. \( \) or \[ \]) + const hasInlineDelimiters = + equation.includes( '\\(' ) && equation.includes( '\\)' ); + const hasDisplayDelimiters = + equation.includes( '\\[' ) && equation.includes( '\\]' ); + if ( hasInlineDelimiters || hasDisplayDelimiters ) { + equation = equation.substring( 2, equation.length - 2 ).trim(); + } + + return { + equation, + display: hasDisplayDelimiters + }; +} + +export async function renderEquation( + equation: string, + element: HTMLElement, + engine: + | 'katex' + | 'mathjax' + | undefined + | ( ( + equation: string, + element: HTMLElement, + display: boolean, + ) => void ) = 'katex', + lazyLoad?: () => Promise, + display = false, + preview = false, + previewUid = '', + previewClassName: Array = [], + katexRenderOptions: KatexOptions = {} +): Promise { + if ( engine == 'mathjax' ) { + if ( isMathJaxVersion3( MathJax ) ) { + selectRenderMode( + element, + preview, + previewUid, + previewClassName, + el => { + renderMathJax3( equation, el, display, () => { + if ( preview ) { + moveAndScaleElement( element, el ); + el.style.visibility = 'visible'; + } + } ); + } + ); + } else { + selectRenderMode( + element, + preview, + previewUid, + previewClassName, + el => { + // Fixme: MathJax typesetting cause occasionally math processing error without asynchronous call + global.window.setTimeout( () => { + renderMathJax2( equation, el, display ); + + // Move and scale after rendering + if ( preview && isMathJaxVersion2( MathJax ) ) { + // eslint-disable-next-line new-cap + MathJax.Hub.Queue( () => { + moveAndScaleElement( element, el ); + el.style.visibility = 'visible'; + } ); + } + } ); + } + ); + } + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + } else if ( engine === 'katex' ) { + selectRenderMode( + element, + preview, + previewUid, + previewClassName, + el => { + if ( katex ) { + katex.render( equation, el, { + throwOnError: false, + displayMode: display, + ...katexRenderOptions + } ); + } + if ( preview ) { + moveAndScaleElement( element, el ); + el.style.visibility = 'visible'; + } + } + ); + } else if ( typeof engine === 'function' ) { + engine( equation, element, display ); + } else { + if ( lazyLoad != null ) { + try { + global.window.CKEDITOR_MATH_LAZY_LOAD ??= lazyLoad(); + element.innerHTML = equation; + await global.window.CKEDITOR_MATH_LAZY_LOAD; + await renderEquation( + equation, + element, + engine, + undefined, + display, + preview, + previewUid, + previewClassName, + katexRenderOptions + ); + } catch ( err ) { + element.innerHTML = equation; + console.error( + `math-tex-typesetting-lazy-load-failed: Lazy load failed: ${ String( err ) }` + ); + } + } else { + element.innerHTML = equation; + console.warn( + `math-tex-typesetting-missing: Missing the mathematical typesetting engine (${ String( engine ) }) for tex.` + ); + } + } +} + +export function getBalloonPositionData( editor: Editor ): { + target: Range | HTMLElement; + positions: Array; +} { + const view = editor.editing.view; + const defaultPositions = BalloonPanelView.defaultPositions; + + const selectedElement = view.document.selection.getSelectedElement(); + if ( selectedElement ) { + return { + target: view.domConverter.viewToDom( selectedElement ), + positions: [ + defaultPositions.southArrowNorth, + defaultPositions.southArrowNorthWest, + defaultPositions.southArrowNorthEast + ] + }; + } else { + const viewDocument = view.document; + const firstRange = viewDocument.selection.getFirstRange(); + if ( !firstRange ) { + /** + * Missing first range. + * @error math-missing-range + */ + throw new CKEditorError( 'math-missing-range' ); + } + return { + target: view.domConverter.viewRangeToDom( + firstRange + ), + positions: [ + defaultPositions.southArrowNorth, + defaultPositions.southArrowNorthWest, + defaultPositions.southArrowNorthEast + ] + }; + } +} + +function selectRenderMode( + element: HTMLElement, + preview: boolean, + previewUid: string, + previewClassName: Array, + cb: ( previewEl: HTMLElement ) => void +) { + if ( preview ) { + createPreviewElement( + element, + previewUid, + previewClassName, + previewEl => { + cb( previewEl ); + } + ); + } else { + cb( element ); + } +} + +function renderMathJax3( equation: string, element: HTMLElement, display: boolean, cb: () => void ) { + let promiseFunction: undefined | ( ( input: string, options: { display: boolean } ) => Promise ) = undefined; + if ( !isMathJaxVersion3( MathJax ) ) { + return; + } + if ( MathJax.tex2chtmlPromise ) { + promiseFunction = MathJax.tex2chtmlPromise; + } else if ( MathJax.tex2svgPromise ) { + promiseFunction = MathJax.tex2svgPromise; + } + + if ( promiseFunction != null ) { + void promiseFunction( equation, { display } ).then( ( node: Element ) => { + if ( element.firstChild ) { + element.removeChild( element.firstChild ); + } + element.appendChild( node ); + cb(); + } ); + } +} + +function renderMathJax2( equation: string, element: HTMLElement, display?: boolean ) { + if ( isMathJaxVersion2( MathJax ) ) { + if ( display ) { + element.innerHTML = '\\[' + equation + '\\]'; + } else { + element.innerHTML = '\\(' + equation + '\\)'; + } + // eslint-disable-next-line + MathJax.Hub.Queue(['Typeset', MathJax.Hub, element]); + } +} + +function createPreviewElement( + element: HTMLElement, + previewUid: string, + previewClassName: Array, + render: ( previewEl: HTMLElement ) => void +): void { + const previewEl = getPreviewElement( element, previewUid, previewClassName ); + render( previewEl ); +} + +function getPreviewElement( + element: HTMLElement, + previewUid: string, + previewClassName: Array +) { + let previewEl = global.document.getElementById( previewUid ); + // Create if not found + if ( !previewEl ) { + previewEl = global.document.createElement( 'div' ); + previewEl.setAttribute( 'id', previewUid ); + previewEl.classList.add( ...previewClassName ); + previewEl.style.visibility = 'hidden'; + global.document.body.appendChild( previewEl ); + + let ticking = false; + + const renderTransformation = () => { + if ( !ticking ) { + global.window.requestAnimationFrame( () => { + if ( previewEl ) { + moveElement( element, previewEl ); + ticking = false; + } + } ); + + ticking = true; + } + }; + + // Create scroll listener for following + global.window.addEventListener( 'resize', renderTransformation ); + global.window.addEventListener( 'scroll', renderTransformation ); + } + return previewEl; +} + +function moveAndScaleElement( parent: HTMLElement, child: HTMLElement ) { + // Move to right place + moveElement( parent, child ); + + // Scale parent element same as preview + const domRect = child.getBoundingClientRect(); + parent.style.width = domRect.width + 'px'; + parent.style.height = domRect.height + 'px'; +} + +function moveElement( parent: HTMLElement, child: HTMLElement ) { + const domRect = parent.getBoundingClientRect(); + const left = global.window.scrollX + domRect.left; + const top = global.window.scrollY + domRect.top; + child.style.position = 'absolute'; + child.style.left = left + 'px'; + child.style.top = top + 'px'; + child.style.zIndex = 'var(--ck-z-panel)'; + child.style.pointerEvents = 'none'; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..6ec1240 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/yarn.lock b/yarn.lock index c59bab0..f8e22a0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,13 +15,6 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.22.13": version "7.22.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" @@ -153,7 +146,7 @@ "@babel/traverse" "^7.23.2" "@babel/types" "^7.23.0" -"@babel/highlight@^7.10.4", "@babel/highlight@^7.22.13": +"@babel/highlight@^7.22.13": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== @@ -665,7 +658,7 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz#8cfaf2ff603e9aabb910e9c0558c26cf32744061" integrity sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA== -"@eslint-community/eslint-utils@^4.2.0": +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== @@ -677,39 +670,54 @@ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.9.1.tgz#449dfa81a57a1d755b09aa58d826c1262e4283b4" integrity sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA== -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.3.tgz#9e42981ef035beb3dd49add17acb96e8ff6f394c" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" + js-yaml "^4.1.0" + minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== + "@gar/promisify@^1.0.1": version "1.1.3" resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== +"@humanwhocodes/config-array@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== dependencies: - "@humanwhocodes/object-schema" "^1.2.0" - debug "^4.1.1" - minimatch "^3.0.4" + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" + minimatch "^3.0.5" -"@humanwhocodes/object-schema@^1.2.0": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917" + integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== "@istanbuljs/schema@^0.1.2": version "0.1.3" @@ -782,7 +790,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3": +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -994,6 +1002,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== +"@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/mdast@^3.0.0": version "3.0.13" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.13.tgz#b7ba6e52d0faeb9c493e32c205f3831022be4e1b" @@ -1058,6 +1071,11 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.3.tgz#9a726e116beb26c24f1ccd6850201e1246122e04" integrity sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw== +"@types/semver@^7.5.0": + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== + "@types/send@*": version "0.17.2" resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.2.tgz#af78a4495e3c2b79bfbdac3955fdd50e03cc98f2" @@ -1117,6 +1135,23 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/eslint-plugin@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.2.0.tgz#5a5fcad1a7baed85c10080d71ad901f98c38d5b7" + integrity sha512-mdekAHOqS9UjlmyF/LSs6AIEvfceV749GFxoBAjwAv0nkevfKHWQFDMcBZWUiIC5ft6ePWivXoS36aKQ0Cy3sw== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "7.2.0" + "@typescript-eslint/type-utils" "7.2.0" + "@typescript-eslint/utils" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/parser@^5.26.0", "@typescript-eslint/parser@^5.52.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7" @@ -1127,6 +1162,17 @@ "@typescript-eslint/typescript-estree" "5.62.0" debug "^4.3.4" +"@typescript-eslint/parser@^7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.2.0.tgz#44356312aea8852a3a82deebdacd52ba614ec07a" + integrity sha512-5FKsVcHTk6TafQKQbuIVkXq58Fnbkd2wDL4LB7AURN7RUOu1utVP+G8+6u3ZhEroW3DF6hyo3ZEXxgKgp4KeCg== + dependencies: + "@typescript-eslint/scope-manager" "7.2.0" + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/typescript-estree" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" + debug "^4.3.4" + "@typescript-eslint/scope-manager@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" @@ -1135,6 +1181,14 @@ "@typescript-eslint/types" "5.62.0" "@typescript-eslint/visitor-keys" "5.62.0" +"@typescript-eslint/scope-manager@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.2.0.tgz#cfb437b09a84f95a0930a76b066e89e35d94e3da" + integrity sha512-Qh976RbQM/fYtjx9hs4XkayYujB/aPwglw2choHmf3zBjB4qOywWSdt9+KLRdHubGcoSwBnXUH2sR3hkyaERRg== + dependencies: + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" + "@typescript-eslint/type-utils@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" @@ -1145,11 +1199,26 @@ debug "^4.3.4" tsutils "^3.21.0" +"@typescript-eslint/type-utils@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.2.0.tgz#7be5c30e9b4d49971b79095a1181324ef6089a19" + integrity sha512-xHi51adBHo9O9330J8GQYQwrKBqbIPJGZZVQTHHmy200hvkLZFWJIFtAG/7IYTWUyun6DE6w5InDReePJYJlJA== + dependencies: + "@typescript-eslint/typescript-estree" "7.2.0" + "@typescript-eslint/utils" "7.2.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/types@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== +"@typescript-eslint/types@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.2.0.tgz#0feb685f16de320e8520f13cca30779c8b7c403f" + integrity sha512-XFtUHPI/abFhm4cbCDc5Ykc8npOKBSJePY3a3s+lwumt7XWJuzP5cZcfZ610MIPHjQjNsOLlYK8ASPaNG8UiyA== + "@typescript-eslint/typescript-estree@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" @@ -1163,6 +1232,20 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.2.0.tgz#5beda2876c4137f8440c5a84b4f0370828682556" + integrity sha512-cyxS5WQQCoBwSakpMrvMXuMDEbhOo9bNHHrNcEWis6XHx6KF518tkF1wBvKIn/tpq5ZpUYK7Bdklu8qY0MsFIA== + dependencies: + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/visitor-keys" "7.2.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/utils@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" @@ -1177,6 +1260,19 @@ eslint-scope "^5.1.1" semver "^7.3.7" +"@typescript-eslint/utils@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.2.0.tgz#fc8164be2f2a7068debb4556881acddbf0b7ce2a" + integrity sha512-YfHpnMAGb1Eekpm3XRK8hcMwGLGsnT6L+7b2XyRv6ouDuJU1tZir1GS2i0+VXRatMwSI1/UfcyPe53ADkU+IuA== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "7.2.0" + "@typescript-eslint/types" "7.2.0" + "@typescript-eslint/typescript-estree" "7.2.0" + semver "^7.5.4" + "@typescript-eslint/visitor-keys@5.62.0": version "5.62.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" @@ -1185,6 +1281,19 @@ "@typescript-eslint/types" "5.62.0" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@7.2.0": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.2.0.tgz#5035f177752538a5750cca1af6044b633610bf9e" + integrity sha512-c6EIQRHhcpl6+tO8EMR+kjkkV+ugUNXOmeASA1rlzkd8EPIriavpWoiEz1HR/VLhbVIdhqnV6E7JZm00cBDx2A== + dependencies: + "@typescript-eslint/types" "7.2.0" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": version "1.11.6" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" @@ -1329,7 +1438,7 @@ acorn-import-assertions@^1.9.0: resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== -acorn-jsx@^5.3.1: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== @@ -1339,16 +1448,16 @@ acorn-walk@^8.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.2: version "8.10.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== +acorn@^8.9.0: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -1386,7 +1495,7 @@ ajv@^5.0.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" -ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1487,6 +1596,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + array-buffer-byte-length@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" @@ -1764,6 +1878,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -2430,7 +2551,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: +debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -2713,7 +2834,7 @@ enhanced-resolve@^5.0.0, enhanced-resolve@^5.15.0: graceful-fs "^4.2.4" tapable "^2.2.0" -enquirer@^2.3.5, enquirer@^2.3.6: +enquirer@^2.3.6: version "2.4.1" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.4.1.tgz#93334b3fbd74fc7097b224ab4a8fb7e40bf4ae56" integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== @@ -2912,89 +3033,90 @@ eslint-scope@5.1.1, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-utils@^2.0.0, eslint-utils@^2.1.0: +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: +eslint-visitor-keys@^1.1.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.3.0: +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^7.32.0: - version "7.32.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== +eslint@^8.57.0: + version "8.57.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" - ajv "^6.10.0" + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" + debug "^4.3.2" doctrine "^3.0.0" - enquirer "^2.3.5" escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" esutils "^2.0.2" fast-deep-equal "^3.1.3" file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" - import-fresh "^3.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" lodash.merge "^4.6.2" - minimatch "^3.0.4" + minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.9" + optionator "^0.9.3" + strip-ansi "^6.0.1" text-table "^0.2.0" - v8-compile-cache "^2.0.3" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0, esquery@^1.5.0: +esquery@^1.4.2, esquery@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== @@ -3375,11 +3497,6 @@ function.prototype.name@^1.1.6: es-abstract "^1.22.1" functions-have-names "^1.2.3" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== - functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -3454,6 +3571,13 @@ glob-parent@^5.1.2, glob-parent@~5.1.0, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" @@ -3504,10 +3628,10 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.6.0, globals@^13.9.0: - version "13.23.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.23.0.tgz#ef31673c926a0976e1f61dab4dca57e0c0a8af02" - integrity sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA== +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== dependencies: type-fest "^0.20.2" @@ -3825,17 +3949,17 @@ ieee754@^1.2.1: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - ignore@^5.1.1, ignore@^5.1.8, ignore@^5.2.0: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== -import-fresh@^3.0.0, import-fresh@^3.2.1: +ignore@^5.2.4: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + +import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -4083,7 +4207,7 @@ is-path-cwd@^2.2.0: resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== -is-path-inside@^3.0.1: +is-path-inside@^3.0.1, is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== @@ -4314,13 +4438,12 @@ js-yaml@3.13.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: - argparse "^1.0.7" - esprima "^4.0.0" + argparse "^2.0.1" jsdoc-type-pratt-parser@~4.0.0: version "4.0.0" @@ -4919,7 +5042,14 @@ minimatch@3.0.4: dependencies: brace-expansion "^1.1.7" -minimatch@^3.0.4, minimatch@^3.1.1: +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -5286,7 +5416,7 @@ opener@^1.5.1: resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== -optionator@^0.9.1: +optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== @@ -5872,11 +6002,6 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - promise-inflight@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" @@ -6068,11 +6193,6 @@ regexp.prototype.flags@^1.5.1: define-properties "^1.2.0" set-function-name "^2.0.0" -regexpp@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - remark-parse@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-9.0.0.tgz#4d20a299665880e4f4af5d90b7c7b8a935853640" @@ -6305,13 +6425,20 @@ semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.2.1, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3: +semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" +semver@^7.5.4: + version "7.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -6758,7 +6885,7 @@ strip-json-comments@2.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -6931,7 +7058,7 @@ svgo@^2.7.0: picocolors "^1.0.0" stable "^0.1.8" -table@^6.0.9, table@^6.6.0: +table@^6.6.0: version "6.8.1" resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== @@ -7074,6 +7201,11 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== +ts-api-utils@^1.0.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + ts-loader@^9.4.2: version "9.5.0" resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.0.tgz#f0a51dda37cc4d8e43e6cb14edebbc599b0c3aa2" @@ -7217,6 +7349,11 @@ typescript@^4.7.2, typescript@^4.7.4: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@^5.4.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" + integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== + ua-parser-js@^0.7.30: version "0.7.36" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.36.tgz#382c5d6fc09141b6541be2cae446ecfcec284db2" @@ -7349,7 +7486,7 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: +v8-compile-cache@^2.3.0: version "2.4.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== From d7af3f1bd58639ce9d9cdc90332e66705a83fcbf Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 05:01:34 -0500 Subject: [PATCH 02/17] Remove JavaScript files --- src/autoformatmath.js | 49 -------- src/automath.js | 120 -------------------- src/index.js | 6 - src/math.js | 16 --- src/mathcommand.js | 41 ------- src/mathediting.js | 214 ----------------------------------- src/mathui.js | 246 ----------------------------------------- src/ui/mainformview.js | 234 --------------------------------------- src/ui/mathview.js | 43 ------- src/utils.js | 233 -------------------------------------- 10 files changed, 1202 deletions(-) delete mode 100644 src/autoformatmath.js delete mode 100644 src/automath.js delete mode 100644 src/index.js delete mode 100644 src/math.js delete mode 100644 src/mathcommand.js delete mode 100644 src/mathediting.js delete mode 100644 src/mathui.js delete mode 100644 src/ui/mainformview.js delete mode 100644 src/ui/mathview.js delete mode 100644 src/utils.js diff --git a/src/autoformatmath.js b/src/autoformatmath.js deleted file mode 100644 index 18b5501..0000000 --- a/src/autoformatmath.js +++ /dev/null @@ -1,49 +0,0 @@ -import { Plugin } from 'ckeditor5/src/core'; -import { global, logWarning } from 'ckeditor5/src/utils'; -import blockAutoformatEditing from '@ckeditor/ckeditor5-autoformat/src/blockautoformatediting'; -import Math from './math'; - -export default class AutoformatMath extends Plugin { - static get requires() { - return [ Math, 'Autoformat' ]; - } - - /** - * @inheritDoc - */ - init() { - const editor = this.editor; - - if ( !editor.plugins.has( 'Math' ) ) { - logWarning( 'autoformat-math-feature-missing', editor ); - } - } - - afterInit() { - const editor = this.editor; - const command = editor.commands.get( 'math' ); - - if ( command ) { - const callback = () => { - if ( !command.isEnabled ) { - return false; - } - - command.display = true; - - // Wait until selection is removed. - global.window.setTimeout( - () => editor.plugins.get( 'MathUI' )._showUI(), - 50 - ); - }; - - blockAutoformatEditing( editor, this, /^\$\$$/, callback ); - blockAutoformatEditing( editor, this, /^\\\[$/, callback ); - } - } - - static get pluginName() { - return 'AutoformatMath'; - } -} diff --git a/src/automath.js b/src/automath.js deleted file mode 100644 index a3b06dd..0000000 --- a/src/automath.js +++ /dev/null @@ -1,120 +0,0 @@ -import { Clipboard } from 'ckeditor5/src/clipboard'; -import { Plugin } from 'ckeditor5/src/core'; -import { LivePosition, LiveRange } from 'ckeditor5/src/engine'; -import { Undo } from 'ckeditor5/src/undo'; -import { global } from 'ckeditor5/src/utils'; -import { extractDelimiters, hasDelimiters, delimitersCounts } from './utils'; - -export default class AutoMath extends Plugin { - static get requires() { - return [ Clipboard, Undo ]; - } - - static get pluginName() { - return 'AutoMath'; - } - - constructor( editor ) { - super( editor ); - - this._timeoutId = null; - - this._positionToInsert = null; - } - - init() { - const editor = this.editor; - const modelDocument = editor.model.document; - - this.listenTo( editor.plugins.get( Clipboard ), 'inputTransformation', () => { - const firstRange = modelDocument.selection.getFirstRange(); - - const leftLivePosition = LivePosition.fromPosition( firstRange.start ); - leftLivePosition.stickiness = 'toPrevious'; - - const rightLivePosition = LivePosition.fromPosition( firstRange.end ); - rightLivePosition.stickiness = 'toNext'; - - modelDocument.once( 'change:data', () => { - this._mathBetweenPositions( leftLivePosition, rightLivePosition ); - - leftLivePosition.detach(); - rightLivePosition.detach(); - }, { priority: 'high' } ); - } ); - - editor.commands.get( 'undo' ).on( 'execute', () => { - if ( this._timeoutId ) { - global.window.clearTimeout( this._timeoutId ); - this._positionToInsert.detach(); - - this._timeoutId = null; - this._positionToInsert = null; - } - }, { priority: 'high' } ); - } - - _mathBetweenPositions( leftPosition, rightPosition ) { - const editor = this.editor; - - const mathConfig = this.editor.config.get( 'math' ); - - const equationRange = new LiveRange( leftPosition, rightPosition ); - const walker = equationRange.getWalker( { ignoreElementEnd: true } ); - - let text = ''; - - // Get equation text - for ( const node of walker ) { - if ( node.item.is( '$textProxy' ) ) { - text += node.item.data; - } - } - - text = text.trim(); - - // Skip if don't have delimiters - if ( !hasDelimiters( text ) || delimitersCounts( text ) !== 2 ) { - return; - } - - const mathCommand = editor.commands.get( 'math' ); - - // Do not anything if math element cannot be inserted at the current position - if ( !mathCommand.isEnabled ) { - return; - } - - this._positionToInsert = LivePosition.fromPosition( leftPosition ); - - // With timeout user can undo conversation if want use plain text - this._timeoutId = global.window.setTimeout( () => { - editor.model.change( writer => { - this._timeoutId = null; - - writer.remove( equationRange ); - - let insertPosition; - - // Check if position where the math element should be inserted is still valid. - if ( this._positionToInsert.root.rootName !== '$graveyard' ) { - insertPosition = this._positionToInsert; - } - - editor.model.change( innerWriter => { - const params = Object.assign( extractDelimiters( text ), { - type: mathConfig.outputType - } ); - const mathElement = innerWriter.createElement( params.display ? 'mathtex-display' : 'mathtex-inline', params ); - - editor.model.insertContent( mathElement, insertPosition ); - - innerWriter.setSelection( mathElement, 'on' ); - } ); - - this._positionToInsert.detach(); - this._positionToInsert = null; - } ); - }, 100 ); - } -} diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 433ed38..0000000 --- a/src/index.js +++ /dev/null @@ -1,6 +0,0 @@ -/** - * @module math - */ - -export { default as Math } from './math'; -export { default as AutoformatMath } from './autoformatmath'; diff --git a/src/math.js b/src/math.js deleted file mode 100644 index 3a3b05e..0000000 --- a/src/math.js +++ /dev/null @@ -1,16 +0,0 @@ -import { Plugin } from 'ckeditor5/src/core'; -import { Widget } from 'ckeditor5/src/widget'; - -import MathUI from './mathui'; -import MathEditing from './mathediting'; -import AutoMath from './automath'; - -export default class Math extends Plugin { - static get requires() { - return [ MathEditing, MathUI, AutoMath, Widget ]; - } - - static get pluginName() { - return 'Math'; - } -} diff --git a/src/mathcommand.js b/src/mathcommand.js deleted file mode 100644 index 3d032f6..0000000 --- a/src/mathcommand.js +++ /dev/null @@ -1,41 +0,0 @@ -import { Command } from 'ckeditor5/src/core'; -import { getSelectedMathModelWidget } from './utils'; - -export default class MathCommand extends Command { - execute( equation, display, outputType, forceOutputType ) { - const model = this.editor.model; - const selection = model.document.selection; - const selectedElement = selection.getSelectedElement(); - - model.change( writer => { - let mathtex; - if ( selectedElement && ( selectedElement.is( 'element', 'mathtex-inline' ) || - selectedElement.is( 'element', 'mathtex-display' ) ) ) { - // Update selected element - const typeAttr = selectedElement.getAttribute( 'type' ); - - // Use already set type if found and is not forced - const type = forceOutputType ? outputType : typeAttr || outputType; - - mathtex = writer.createElement( display ? 'mathtex-display' : 'mathtex-inline', { equation, type, display } ); - } else { - // Create new model element - mathtex = writer.createElement( display ? 'mathtex-display' : 'mathtex-inline', { equation, type: outputType, display } ); - } - model.insertContent( mathtex ); - } ); - } - - refresh() { - const model = this.editor.model; - const selection = model.document.selection; - const selectedElement = selection.getSelectedElement(); - - this.isEnabled = selectedElement === null || ( selectedElement.is( 'element', 'mathtex-inline' ) || - selectedElement.is( 'element', 'mathtex-display' ) ); - - const selectedEquation = getSelectedMathModelWidget( selection ); - this.value = selectedEquation ? selectedEquation.getAttribute( 'equation' ) : null; - this.display = selectedEquation ? selectedEquation.getAttribute( 'display' ) : null; - } -} diff --git a/src/mathediting.js b/src/mathediting.js deleted file mode 100644 index 31d14f4..0000000 --- a/src/mathediting.js +++ /dev/null @@ -1,214 +0,0 @@ -import MathCommand from './mathcommand'; -import { Plugin } from 'ckeditor5/src/core'; -import { toWidget, Widget, viewToModelPositionOutsideModelElement } from 'ckeditor5/src/widget'; -import { renderEquation, extractDelimiters } from './utils'; - -export default class MathEditing extends Plugin { - static get requires() { - return [ Widget ]; - } - - static get pluginName() { - return 'MathEditing'; - } - - constructor( editor ) { - super( editor ); - editor.config.define( 'math', { - engine: 'mathjax', - outputType: 'script', - className: 'math-tex', - forceOutputType: false, - enablePreview: true, - previewClassName: [], - popupClassName: [], - katexRenderOptions: {} - } ); - } - - init() { - const editor = this.editor; - editor.commands.add( 'math', new MathCommand( editor ) ); - - this._defineSchema(); - this._defineConverters(); - - editor.editing.mapper.on( - 'viewToModelPosition', - viewToModelPositionOutsideModelElement( editor.model, viewElement => viewElement.hasClass( 'math' ) ) - ); - } - - _defineSchema() { - const schema = this.editor.model.schema; - schema.register( 'mathtex-inline', { - allowWhere: '$text', - isInline: true, - isObject: true, - allowAttributes: [ 'equation', 'type', 'display' ] - } ); - - schema.register( 'mathtex-display', { - allowWhere: '$block', - isInline: false, - isObject: true, - allowAttributes: [ 'equation', 'type', 'display' ] - } ); - } - - _defineConverters() { - const conversion = this.editor.conversion; - const mathConfig = this.editor.config.get( 'math' ); - - // View -> Model - conversion.for( 'upcast' ) - // MathJax inline way (e.g. ) - .elementToElement( { - view: { - name: 'script', - attributes: { - type: 'math/tex' - } - }, - model: ( viewElement, { writer } ) => { - const equation = viewElement.getChild( 0 ).data.trim(); - return writer.createElement( 'mathtex-inline', { - equation, - type: mathConfig.forceOutputType ? mathConfig.outputType : 'script', - display: false - } ); - } - } ) - // MathJax display way (e.g. ) - .elementToElement( { - view: { - name: 'script', - attributes: { - type: 'math/tex; mode=display' - } - }, - model: ( viewElement, { writer } ) => { - const equation = viewElement.getChild( 0 ).data.trim(); - return writer.createElement( 'mathtex-display', { - equation, - type: mathConfig.forceOutputType ? mathConfig.outputType : 'script', - display: true - } ); - } - } ) - // CKEditor 4 way (e.g. \( \sqrt{\frac{a}{b}} \)) - .elementToElement( { - view: { - name: 'span', - classes: [ mathConfig.className ] - }, - model: ( viewElement, { writer } ) => { - const equation = viewElement.getChild( 0 ).data.trim(); - - const params = Object.assign( extractDelimiters( equation ), { - type: mathConfig.forceOutputType ? mathConfig.outputType : 'span' - } ); - - return writer.createElement( params.display ? 'mathtex-display' : 'mathtex-inline', params ); - } - } ) - // KaTeX from Quill: https://github.com/quilljs/quill/blob/develop/formats/formula.js - .elementToElement( { - view: { - name: 'span', - classes: [ 'ql-formula' ] - }, - model: ( viewElement, { writer } ) => { - const equation = viewElement.getAttribute( 'data-value' ).trim(); - return writer.createElement( 'mathtex-inline', { - equation, - type: mathConfig.forceOutputType ? mathConfig.outputType : 'script', - display: false - } ); - } - } ); - - // Model -> View (element) - conversion.for( 'editingDowncast' ) - .elementToElement( { - model: 'mathtex-inline', - view: ( modelItem, { writer } ) => { - const widgetElement = createMathtexEditingView( modelItem, writer ); - return toWidget( widgetElement, writer, 'span' ); - } - } ).elementToElement( { - model: 'mathtex-display', - view: ( modelItem, { writer } ) => { - const widgetElement = createMathtexEditingView( modelItem, writer ); - return toWidget( widgetElement, writer, 'div' ); - } - } ); - - // Model -> Data - conversion.for( 'dataDowncast' ) - .elementToElement( { - model: 'mathtex-inline', - view: createMathtexView - } ) - .elementToElement( { - model: 'mathtex-display', - view: createMathtexView - } ); - - // Create view for editor - function createMathtexEditingView( modelItem, writer ) { - const equation = modelItem.getAttribute( 'equation' ); - const display = modelItem.getAttribute( 'display' ); - - const styles = 'user-select: none; ' + ( display ? '' : 'display: inline-block;' ); - const classes = 'ck-math-tex ' + ( display ? 'ck-math-tex-display' : 'ck-math-tex-inline' ); - - const mathtexView = writer.createContainerElement( display ? 'div' : 'span', { - style: styles, - class: classes - } ); - - const uiElement = writer.createUIElement( 'div', null, function( domDocument ) { - const domElement = this.toDomElement( domDocument ); - - renderEquation( equation, domElement, mathConfig.engine, mathConfig.lazyLoad, display, false, mathConfig.previewClassName, - null, mathConfig.katexRenderOptions ); - - return domElement; - } ); - - writer.insert( writer.createPositionAt( mathtexView, 0 ), uiElement ); - - return mathtexView; - } - - // Create view for data - function createMathtexView( modelItem, { writer } ) { - const equation = modelItem.getAttribute( 'equation' ); - const type = modelItem.getAttribute( 'type' ); - const display = modelItem.getAttribute( 'display' ); - - if ( type === 'span' ) { - const mathtexView = writer.createContainerElement( 'span', { - class: mathConfig.className - } ); - - if ( display ) { - writer.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( '\\[' + equation + '\\]' ) ); - } else { - writer.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( '\\(' + equation + '\\)' ) ); - } - - return mathtexView; - } else { - const mathtexView = writer.createContainerElement( 'script', { - type: display ? 'math/tex; mode=display' : 'math/tex' - } ); - - writer.insert( writer.createPositionAt( mathtexView, 0 ), writer.createText( equation ) ); - - return mathtexView; - } - } - } -} diff --git a/src/mathui.js b/src/mathui.js deleted file mode 100644 index cba4f5d..0000000 --- a/src/mathui.js +++ /dev/null @@ -1,246 +0,0 @@ -import MathEditing from './mathediting'; -import MainFormView from './ui/mainformview'; -import mathIcon from '../theme/icons/math.svg'; -import { Plugin } from 'ckeditor5/src/core'; -import { ClickObserver } from 'ckeditor5/src/engine'; -import { ButtonView, ContextualBalloon, clickOutsideHandler } from 'ckeditor5/src/ui'; -import { global, uid } from 'ckeditor5/src/utils'; -import { getBalloonPositionData } from './utils'; - -const mathKeystroke = 'Ctrl+M'; - -export default class MathUI extends Plugin { - static get requires() { - return [ ContextualBalloon, MathEditing ]; - } - - static get pluginName() { - return 'MathUI'; - } - - init() { - const editor = this.editor; - editor.editing.view.addObserver( ClickObserver ); - - this._previewUid = `math-preview-${ uid() }`; - - this.formView = this._createFormView(); - - this._balloon = editor.plugins.get( ContextualBalloon ); - - this._createToolbarMathButton(); - - this._enableUserBalloonInteractions(); - } - - destroy() { - super.destroy(); - - this.formView.destroy(); - - // Destroy preview element - const previewEl = global.document.getElementById( this._previewUid ); - if ( previewEl ) { - previewEl.parentNode.removeChild( previewEl ); - } - } - - _showUI() { - const editor = this.editor; - const mathCommand = editor.commands.get( 'math' ); - - if ( !mathCommand.isEnabled ) { - return; - } - - this._addFormView(); - - this._balloon.showStack( 'main' ); - } - - _createFormView() { - const editor = this.editor; - const mathCommand = editor.commands.get( 'math' ); - - const mathConfig = editor.config.get( 'math' ); - - const formView = new MainFormView( - editor.locale, - mathConfig.engine, - mathConfig.lazyLoad, - mathConfig.enablePreview, - this._previewUid, - mathConfig.previewClassName, - mathConfig.popupClassName, - mathConfig.katexRenderOptions - ); - - formView.mathInputView.bind( 'value' ).to( mathCommand, 'value' ); - formView.displayButtonView.bind( 'isOn' ).to( mathCommand, 'display' ); - - // Form elements should be read-only when corresponding commands are disabled. - formView.mathInputView.bind( 'isReadOnly' ).to( mathCommand, 'isEnabled', value => !value ); - formView.saveButtonView.bind( 'isEnabled' ).to( mathCommand ); - formView.displayButtonView.bind( 'isEnabled' ).to( mathCommand ); - - // Listen to submit button click - this.listenTo( formView, 'submit', () => { - editor.execute( 'math', formView.equation, formView.displayButtonView.isOn, mathConfig.outputType, mathConfig.forceOutputType ); - this._closeFormView(); - } ); - - // Listen to cancel button click - this.listenTo( formView, 'cancel', () => { - this._closeFormView(); - } ); - - // Close plugin ui, if esc is pressed (while ui is focused) - formView.keystrokes.set( 'esc', ( data, cancel ) => { - this._closeFormView(); - cancel(); - } ); - - return formView; - } - - _addFormView() { - if ( this._isFormInPanel ) { - return; - } - - const editor = this.editor; - const mathCommand = editor.commands.get( 'math' ); - - this._balloon.add( { - view: this.formView, - position: getBalloonPositionData( editor ) - } ); - - if ( this._balloon.visibleView === this.formView ) { - this.formView.mathInputView.fieldView.element.select(); - } - - // Show preview element - const previewEl = global.document.getElementById( this._previewUid ); - if ( previewEl && this.formView.previewEnabled ) { - // Force refresh preview - this.formView.mathView.updateMath(); - } - - this.formView.equation = mathCommand.value || ''; - this.formView.displayButtonView.isOn = mathCommand.display || false; - } - - _hideUI() { - if ( !this._isFormInPanel ) { - return; - } - - const editor = this.editor; - - this.stopListening( editor.ui, 'update' ); - this.stopListening( this._balloon, 'change:visibleView' ); - - editor.editing.view.focus(); - - // Remove form first because it's on top of the stack. - this._removeFormView(); - } - - _closeFormView() { - const mathCommand = this.editor.commands.get( 'math' ); - if ( mathCommand.value !== undefined ) { - this._removeFormView(); - } else { - this._hideUI(); - } - } - - _removeFormView() { - if ( this._isFormInPanel ) { - this.formView.saveButtonView.focus(); - - this._balloon.remove( this.formView ); - - // Hide preview element - const previewEl = global.document.getElementById( this._previewUid ); - if ( previewEl ) { - previewEl.style.visibility = 'hidden'; - } - - this.editor.editing.view.focus(); - } - } - - _createToolbarMathButton() { - const editor = this.editor; - const mathCommand = editor.commands.get( 'math' ); - const t = editor.t; - - // Handle the `Ctrl+M` keystroke and show the panel. - editor.keystrokes.set( mathKeystroke, ( keyEvtData, cancel ) => { - // Prevent focusing the search bar in FF and opening new tab in Edge. #153, #154. - cancel(); - - if ( mathCommand.isEnabled ) { - this._showUI(); - } - } ); - - this.editor.ui.componentFactory.add( 'math', locale => { - const button = new ButtonView( locale ); - - button.isEnabled = true; - button.label = t( 'Insert math' ); - button.icon = mathIcon; - button.keystroke = mathKeystroke; - button.tooltip = true; - button.isToggleable = true; - - button.bind( 'isEnabled' ).to( mathCommand, 'isEnabled' ); - - this.listenTo( button, 'execute', () => this._showUI() ); - - return button; - } ); - } - - _enableUserBalloonInteractions() { - const editor = this.editor; - const viewDocument = this.editor.editing.view.document; - this.listenTo( viewDocument, 'click', () => { - const mathCommand = editor.commands.get( 'math' ); - if ( mathCommand.value ) { - if ( mathCommand.isEnabled ) { - this._showUI(); - } - } - } ); - - // Close the panel on the Esc key press when the editable has focus and the balloon is visible. - editor.keystrokes.set( 'Esc', ( data, cancel ) => { - if ( this._isUIVisible ) { - this._hideUI(); - cancel(); - } - } ); - - // Close on click outside of balloon panel element. - clickOutsideHandler( { - emitter: this.formView, - activator: () => this._isFormInPanel, - contextElements: [ this._balloon.view.element ], - callback: () => this._hideUI() - } ); - } - - get _isUIVisible() { - const visibleView = this._balloon.visibleView; - - return visibleView == this.formView; - } - - get _isFormInPanel() { - return this._balloon.hasView( this.formView ); - } -} diff --git a/src/ui/mainformview.js b/src/ui/mainformview.js deleted file mode 100644 index 8f25efa..0000000 --- a/src/ui/mainformview.js +++ /dev/null @@ -1,234 +0,0 @@ -import { icons } from 'ckeditor5/src/core'; -import { - ButtonView, createLabeledInputText, FocusCycler, LabelView, LabeledFieldView, - submitHandler, SwitchButtonView, View, ViewCollection -} from 'ckeditor5/src/ui'; -import { FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils'; -import { extractDelimiters, hasDelimiters } from '../utils'; -import MathView from './mathview'; -import '../../theme/mathform.css'; - -const { check: checkIcon, cancel: cancelIcon } = icons; - -export default class MainFormView extends View { - constructor( locale, engine, lazyLoad, previewEnabled, previewUid, previewClassName, popupClassName, katexRenderOptions ) { - super( locale ); - - const t = locale.t; - - // Create key event & focus trackers - this._createKeyAndFocusTrackers(); - - // Submit button - this.saveButtonView = this._createButton( t( 'Save' ), checkIcon, 'ck-button-save', null ); - this.saveButtonView.type = 'submit'; - - // Equation input - this.mathInputView = this._createMathInput(); - - // Display button - this.displayButtonView = this._createDisplayButton(); - - // Cancel button - this.cancelButtonView = this._createButton( t( 'Cancel' ), cancelIcon, 'ck-button-cancel', 'cancel' ); - - this.previewEnabled = previewEnabled; - - let children = []; - if ( this.previewEnabled ) { - // Preview label - this.previewLabel = new LabelView( locale ); - this.previewLabel.text = t( 'Equation preview' ); - - // Math element - this.mathView = new MathView( engine, lazyLoad, locale, previewUid, previewClassName, katexRenderOptions ); - this.mathView.bind( 'display' ).to( this.displayButtonView, 'isOn' ); - - children = [ - this.mathInputView, - this.displayButtonView, - this.previewLabel, - this.mathView - ]; - } else { - children = [ - this.mathInputView, - this.displayButtonView - ]; - } - - // Add UI elements to template - this.setTemplate( { - tag: 'form', - attributes: { - class: [ - 'ck', - 'ck-math-form', - ...popupClassName - ], - tabindex: '-1', - spellcheck: 'false' - }, - children: [ - { - tag: 'div', - attributes: { - class: [ - 'ck-math-view' - ] - }, - children - }, - this.saveButtonView, - this.cancelButtonView - ] - } ); - } - - render() { - super.render(); - - // Prevent default form submit event & trigger custom 'submit' - submitHandler( { - view: this - } ); - - // Register form elements to focusable elements - const childViews = [ - this.mathInputView, - this.displayButtonView, - this.saveButtonView, - this.cancelButtonView - ]; - - childViews.forEach( v => { - this._focusables.add( v ); - this.focusTracker.add( v.element ); - } ); - - // Listen to keypresses inside form element - this.keystrokes.listenTo( this.element ); - } - - focus() { - this._focusCycler.focusFirst(); - } - - get equation() { - return this.mathInputView.fieldView.element.value; - } - - set equation( equation ) { - this.mathInputView.fieldView.element.value = equation; - if ( this.previewEnabled ) { - this.mathView.value = equation; - } - } - - _createKeyAndFocusTrackers() { - this.focusTracker = new FocusTracker(); - this.keystrokes = new KeystrokeHandler(); - this._focusables = new ViewCollection(); - - this._focusCycler = new FocusCycler( { - focusables: this._focusables, - focusTracker: this.focusTracker, - keystrokeHandler: this.keystrokes, - actions: { - focusPrevious: 'shift + tab', - focusNext: 'tab' - } - } ); - } - - _createMathInput() { - const t = this.locale.t; - - // Create equation input - const mathInput = new LabeledFieldView( this.locale, createLabeledInputText ); - const fieldView = mathInput.fieldView; - mathInput.infoText = t( 'Insert equation in TeX format.' ); - - const onInput = () => { - if ( fieldView.element != null ) { - let equationInput = fieldView.element.value.trim(); - - // If input has delimiters - if ( hasDelimiters( equationInput ) ) { - // Get equation without delimiters - const params = extractDelimiters( equationInput ); - - // Remove delimiters from input field - fieldView.element.value = params.equation; - - equationInput = params.equation; - - // update display button and preview - this.displayButtonView.isOn = params.display; - } - if ( this.previewEnabled ) { - // Update preview view - this.mathView.value = equationInput; - } - - this.saveButtonView.isEnabled = !!equationInput; - } - }; - - fieldView.on( 'render', onInput ); - fieldView.on( 'input', onInput ); - - return mathInput; - } - - _createButton( label, icon, className, eventName ) { - const button = new ButtonView( this.locale ); - - button.set( { - label, - icon, - tooltip: true - } ); - - button.extendTemplate( { - attributes: { - class: className - } - } ); - - if ( eventName ) { - button.delegate( 'execute' ).to( this, eventName ); - } - - return button; - } - - _createDisplayButton() { - const t = this.locale.t; - - const switchButton = new SwitchButtonView( this.locale ); - - switchButton.set( { - label: t( 'Display mode' ), - withText: true - } ); - - switchButton.extendTemplate( { - attributes: { - class: 'ck-button-display-toggle' - } - } ); - - switchButton.on( 'execute', () => { - // Toggle state - switchButton.isOn = !switchButton.isOn; - - if ( this.previewEnabled ) { - // Update preview view - this.mathView.display = switchButton.isOn; - } - } ); - - return switchButton; - } -} diff --git a/src/ui/mathview.js b/src/ui/mathview.js deleted file mode 100644 index 0badcd3..0000000 --- a/src/ui/mathview.js +++ /dev/null @@ -1,43 +0,0 @@ -import { View } from 'ckeditor5/src/ui'; -import { renderEquation } from '../utils'; - -export default class MathView extends View { - constructor( engine, lazyLoad, locale, previewUid, previewClassName, katexRenderOptions ) { - super( locale ); - - this.engine = engine; - this.lazyLoad = lazyLoad; - this.previewUid = previewUid; - this.katexRenderOptions = katexRenderOptions; - this.previewClassName = previewClassName; - - this.set( 'value', '' ); - this.set( 'display', false ); - - this.on( 'change', () => { - if ( this.isRendered ) { - this.updateMath(); - } - } ); - - this.setTemplate( { - tag: 'div', - attributes: { - class: [ - 'ck', - 'ck-math-preview' - ] - } - } ); - } - - updateMath() { - renderEquation( this.value, this.element, this.engine, this.lazyLoad, this.display, true, this.previewUid, this.previewClassName, - this.katexRenderOptions ); - } - - render() { - super.render(); - this.updateMath(); - } -} diff --git a/src/utils.js b/src/utils.js deleted file mode 100644 index f4aed49..0000000 --- a/src/utils.js +++ /dev/null @@ -1,233 +0,0 @@ -import { BalloonPanelView } from 'ckeditor5/src/ui'; -import { global } from 'ckeditor5/src/utils'; - -export function getSelectedMathModelWidget( selection ) { - const selectedElement = selection.getSelectedElement(); - - if ( selectedElement && ( selectedElement.is( 'element', 'mathtex-inline' ) || selectedElement.is( 'element', 'mathtex-display' ) ) ) { - return selectedElement; - } - - return null; -} - -// Simple MathJax 3 version check -export function isMathJaxVersion3( version ) { - return version && typeof version === 'string' && version.split( '.' ).length === 3 && version.split( '.' )[ 0 ] === '3'; -} - -// Check if equation has delimiters. -export function hasDelimiters( text ) { - return text.match( /^(\\\[.*?\\\]|\\\(.*?\\\))$/ ); -} - -// Find delimiters count -export function delimitersCounts( text ) { - return text.match( /(\\\[|\\\]|\\\(|\\\))/g ).length; -} - -// Extract delimiters and figure display mode for the model -export function extractDelimiters( equation ) { - equation = equation.trim(); - - // Remove delimiters (e.g. \( \) or \[ \]) - const hasInlineDelimiters = equation.includes( '\\(' ) && equation.includes( '\\)' ); - const hasDisplayDelimiters = equation.includes( '\\[' ) && equation.includes( '\\]' ); - if ( hasInlineDelimiters || hasDisplayDelimiters ) { - equation = equation.substring( 2, equation.length - 2 ).trim(); - } - - return { - equation, - display: hasDisplayDelimiters - }; -} - -export async function renderEquation( - equation, element, engine = 'katex', lazyLoad, display = false, preview = false, previewUid, previewClassName = [], - katexRenderOptions = {} -) { - if ( engine === 'mathjax' && typeof MathJax !== 'undefined' ) { - if ( isMathJaxVersion3( MathJax.version ) ) { - selectRenderMode( element, preview, previewUid, previewClassName, el => { - renderMathJax3( equation, el, display, () => { - if ( preview ) { - moveAndScaleElement( element, el ); - el.style.visibility = 'visible'; - } - } ); - } ); - } else { - selectRenderMode( element, preview, previewUid, previewClassName, el => { - // Fixme: MathJax typesetting cause occasionally math processing error without asynchronous call - global.window.setTimeout( () => { - renderMathJax2( equation, el, display ); - - // Move and scale after rendering - if ( preview ) { - // eslint-disable-next-line - MathJax.Hub.Queue( () => { - moveAndScaleElement( element, el ); - el.style.visibility = 'visible'; - } ); - } - } ); - } ); - } - } else if ( engine === 'katex' && typeof katex !== 'undefined' ) { - selectRenderMode( element, preview, previewUid, previewClassName, el => { - katex.render( equation, el, { - throwOnError: false, - displayMode: display, - ...katexRenderOptions - } ); - if ( preview ) { - moveAndScaleElement( element, el ); - el.style.visibility = 'visible'; - } - } ); - } else if ( typeof engine === 'function' ) { - engine( equation, element, display ); - } else { - if ( typeof lazyLoad !== 'undefined' ) { - try { - if ( !global.window.CKEDITOR_MATH_LAZY_LOAD ) { - global.window.CKEDITOR_MATH_LAZY_LOAD = lazyLoad(); - } - element.innerHTML = equation; - await global.window.CKEDITOR_MATH_LAZY_LOAD; - renderEquation( equation, element, engine, undefined, display, preview, previewUid, previewClassName, katexRenderOptions ); - } - catch ( err ) { - element.innerHTML = equation; - console.error( `math-tex-typesetting-lazy-load-failed: Lazy load failed: ${ err }` ); - } - } else { - element.innerHTML = equation; - console.warn( `math-tex-typesetting-missing: Missing the mathematical typesetting engine (${ engine }) for tex.` ); - } - } -} - -export function getBalloonPositionData( editor ) { - const view = editor.editing.view; - const defaultPositions = BalloonPanelView.defaultPositions; - - const selectedElement = view.document.selection.getSelectedElement(); - if ( selectedElement ) { - return { - target: view.domConverter.viewToDom( selectedElement ), - positions: [ - defaultPositions.southArrowNorth, - defaultPositions.southArrowNorthWest, - defaultPositions.southArrowNorthEast - ] - }; - } - else { - const viewDocument = view.document; - return { - target: view.domConverter.viewRangeToDom( viewDocument.selection.getFirstRange() ), - positions: [ - defaultPositions.southArrowNorth, - defaultPositions.southArrowNorthWest, - defaultPositions.southArrowNorthEast - ] - }; - } -} - -function selectRenderMode( element, preview, previewUid, previewClassName, cb ) { - if ( preview ) { - createPreviewElement( element, previewUid, previewClassName, previewEl => { - cb( previewEl ); - } ); - } else { - cb( element ); - } -} - -function renderMathJax3( equation, element, display, cb ) { - let promiseFunction = undefined; - if ( typeof MathJax.tex2chtmlPromise !== 'undefined' ) { - promiseFunction = MathJax.tex2chtmlPromise; - } else if ( typeof MathJax.tex2svgPromise !== 'undefined' ) { - promiseFunction = MathJax.tex2svgPromise; - } - - if ( typeof promiseFunction !== 'undefined' ) { - promiseFunction( equation, { display } ).then( node => { - if ( element.firstChild ) { - element.removeChild( element.firstChild ); - } - element.appendChild( node ); - cb(); - } ); - } -} - -function renderMathJax2( equation, element, display ) { - if ( display ) { - element.innerHTML = '\\[' + equation + '\\]'; - } else { - element.innerHTML = '\\(' + equation + '\\)'; - } - // eslint-disable-next-line - MathJax.Hub.Queue( [ 'Typeset', MathJax.Hub, element ] ); -} - -function createPreviewElement( element, previewUid, previewClassName, render ) { - const previewEl = getPreviewElement( element, previewUid, previewClassName ); - render( previewEl ); -} - -function getPreviewElement( element, previewUid, previewClassName ) { - let previewEl = global.document.getElementById( previewUid ); - // Create if not found - if ( !previewEl ) { - previewEl = global.document.createElement( 'div' ); - previewEl.setAttribute( 'id', previewUid ); - previewEl.classList.add( ...previewClassName ); - previewEl.style.visibility = 'hidden'; - global.document.body.appendChild( previewEl ); - - let ticking = false; - - const renderTransformation = () => { - if ( !ticking ) { - global.window.requestAnimationFrame( () => { - moveElement( element, previewEl ); - ticking = false; - } ); - - ticking = true; - } - }; - - // Create scroll listener for following - global.window.addEventListener( 'resize', renderTransformation ); - global.window.addEventListener( 'scroll', renderTransformation ); - } - return previewEl; -} - -function moveAndScaleElement( parent, child ) { - // Move to right place - moveElement( parent, child ); - - // Scale parent element same as preview - const domRect = child.getBoundingClientRect(); - parent.style.width = domRect.width + 'px'; - parent.style.height = domRect.height + 'px'; -} - -function moveElement( parent, child ) { - const domRect = parent.getBoundingClientRect(); - const left = global.window.scrollX + domRect.left; - const top = global.window.scrollY + domRect.top; - child.style.position = 'absolute'; - child.style.left = left + 'px'; - child.style.top = top + 'px'; - child.style.zIndex = 'var(--ck-z-panel)'; - child.style.pointerEvents = 'none'; -} From a10d5ee4335a25fa54bd73eb3749ae3248f08f6b Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 05:25:25 -0500 Subject: [PATCH 03/17] Tag v41.2.1-alpha.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7599e53..8d5bc35 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@isaul32/ckeditor5-math", - "version": "41.2.0", + "version": "41.2.1-alpha.0", "description": "Math feature for CKEditor 5.", "keywords": [ "ckeditor", From cdcebdcbb48bc6e285a690a11e91a8811a23b4ed Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 05:32:25 -0500 Subject: [PATCH 04/17] Use tsconfig.json inspired by CKEditor5, CKEditor5 plugins --- tsconfig.json | 130 +++++++++----------------------------------------- 1 file changed, 23 insertions(+), 107 deletions(-) diff --git a/tsconfig.json b/tsconfig.json index 6ec1240..20be471 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,109 +1,25 @@ { - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - - /* Projects */ - // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ - // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ - // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ - // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ - // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ - // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ - - /* Language and Environment */ - "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ - // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ - // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ - // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ - // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ - // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ - // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ - // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ - // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ - // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ - - /* Modules */ - "module": "commonjs" /* Specify what module code is generated. */, - // "rootDir": "./", /* Specify the root folder within your source files. */ - // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ - // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ - // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - // "types": [], /* Specify type package names to be included without being referenced in a source file. */ - // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ - // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ - // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ - // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ - // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ - // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ - - /* JavaScript Support */ - // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ - // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ - // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ - - /* Emit */ - // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ - // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ - // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ - // "outDir": "./", /* Specify an output folder for all emitted files. */ - // "removeComments": true, /* Disable emitting comments. */ - // "noEmit": true, /* Disable emitting files from a compilation. */ - // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ - // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ - // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ - // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ - // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ - // "newLine": "crlf", /* Set the newline character for emitting files. */ - // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ - // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ - // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ - // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ - // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ - - /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ - // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ - "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, - // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ - "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, - - /* Type Checking */ - "strict": true /* Enable all strict type-checking options. */, - // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ - // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ - // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ - // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ - // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ - // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ - // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ - // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ - // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ - // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ - // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ - - /* Completeness */ - // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ - "skipLibCheck": true /* Skip type checking all .d.ts files. */ - } + "compilerOptions": { + "lib": [ + "DOM" + ], + "noImplicitAny": true, + "noImplicitOverride": true, + "strict": true, + "module": "es6", + "target": "es2020", + "sourceMap": true, + "allowJs": true, + "moduleResolution": "node", + "typeRoots": [ + "typings", + "node_modules/@types" + ] + }, + "include": [ + "./sample", + "./src", + "./tests", + "./typings" + ] } From 76c7faf8a297415c82fd2018c0be4b4440c70e18 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 05:33:33 -0500 Subject: [PATCH 05/17] package.json: Add ts:{build,clear}, prepublishOnly, postpublish --- package.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.json b/package.json index 8d5bc35..445acce 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,8 @@ "CHANGELOG.md" ], "scripts": { + "ts:build": "tsc -p ./tsconfig.release.json", + "ts:clear": "npx rimraf \"src/**/*.@(js|d.ts)\"", "dll:build": "ckeditor5-package-tools dll:build", "dll:serve": "http-server ./ -o sample/dll.html", "lint": "eslint --quiet --ext .ts src/", @@ -73,6 +75,8 @@ "stylelint": "stylelint --quiet --allow-empty-input 'theme/**/*.css'", "test": "ckeditor5-package-tools test", "prepare": "yarn run dll:build", + "prepublishOnly": "yarn run ts:build && ckeditor5-package-tools export-package-as-javascript", + "postpublish": "yarn run ts:clear && ckeditor5-package-tools export-package-as-typescript", "start": "ckeditor5-package-tools start" }, "lint-staged": { From 4ee7430b5af01c030ce3b450169f55be9bd27c3b Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 05:35:27 -0500 Subject: [PATCH 06/17] eslint: Check .ts files --- .eslintrc.cjs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 33b7fac..100e2b9 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -21,6 +21,10 @@ module.exports = { ignorePatterns: [ // Ignore the entire `build/` (the DLL build). "build/**", + // Ignore compiled JavaScript files, as they are generated automatically. + 'src/**/*.js', + // Also, do not check typing declarations, too. + 'src/**/*.d.ts' ], rules: { // This rule disallows importing core DLL packages directly. Imports should be done using the `ckeditor5` package. @@ -36,7 +40,7 @@ module.exports = { }, overrides: [ { - files: ["tests/**/*.js", "sample/**/*.js"], + files: [ 'tests/**/*.[jt]s', 'sample/**/*.[jt]s' ], rules: { // To write complex tests, you may need to import files that are not exported in DLL files by default. // Hence, imports CKEditor 5 packages in test files are not checked. From 9a9d627dcb57579a4e8e168023f4560af57d62a7 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 05:36:14 -0500 Subject: [PATCH 07/17] Add tsconfig.release.json --- tsconfig.release.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tsconfig.release.json diff --git a/tsconfig.release.json b/tsconfig.release.json new file mode 100644 index 0000000..cd8b6f5 --- /dev/null +++ b/tsconfig.release.json @@ -0,0 +1,11 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "sourceMap": false, + "declaration": true + }, + "exclude": [ + "./tests/", + "./sample/" + ] +} From 55201bb6b5602a9a3a6e3fa11630dc1a89f9b705 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 05:40:55 -0500 Subject: [PATCH 08/17] chore: Add override for methods ERROR in ckeditor5-math/src/mathcommand.ts ./src/mathcommand.ts 5:8-13 [tsl] ERROR in ckeditor5-math/src/mathcommand.ts(5,9) TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'Command'. @ ./src/autoformatmath.ts 6:0-40 24:31-42 @ ./src/index.ts 5:0-61 5:0-61 ERROR in ckeditor5-math/src/mathcommand.ts ./src/mathcommand.ts 6:8-15 [tsl] ERROR in ckeditor5-math/src/mathcommand.ts(6,9) TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'Command'. @ ./src/autoformatmath.ts 6:0-40 24:31-42 @ ./src/index.ts 5:0-61 5:0-61 ERROR in ckeditor5-math/src/mathcommand.ts ./src/mathcommand.ts 48:8-15 [tsl] ERROR in ckeditor5-math/src/mathcommand.ts(48,9) TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'Command'. @ ./src/autoformatmath.ts 6:0-40 24:31-42 @ ./src/index.ts 5:0-61 5:0-61 ERROR in ckeditor5-math/src/mathui.ts ./src/mathui.ts 41:8-15 [tsl] ERROR in ckeditor5-math/src/mathui.ts(41,9) TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'Plugin'. @ ./src/autoformatmath.ts 7:0-30 33:50-56 @ ./src/index.ts 5:0-61 5:0-61 ERROR in ckeditor5-math/src/ui/mainformview.ts ./src/ui/mainformview.ts 40:8-14 [tsl] ERROR in ckeditor5-math/src/ui/mainformview.ts(40,9) TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'View'. @ ./src/mathui.ts 2:0-45 61:29-41 @ ./src/autoformatmath.ts 7:0-30 33:50-56 @ ./src/index.ts 5:0-61 5:0-61 ERROR in ckeditor5-math/src/ui/mainformview.ts ./src/ui/mainformview.ts 130:8-14 [tsl] ERROR in ckeditor5-math/src/ui/mainformview.ts(130,9) TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'View'. @ ./src/mathui.ts 2:0-45 61:29-41 @ ./src/autoformatmath.ts 7:0-30 33:50-56 @ ./src/index.ts 5:0-61 5:0-61 ERROR in ckeditor5-math/src/ui/mathview.ts ./src/ui/mathview.ts 76:8-14 [tsl] ERROR in ckeditor5-math/src/ui/mathview.ts(76,9) TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'View'. @ ./src/ui/mainformview.ts 5:0-34 48:32-40 @ ./src/mathui.ts 2:0-45 61:29-41 @ ./src/autoformatmath.ts 7:0-30 33:50-56 @ ./src/index.ts 5:0-61 5:0-61 7 errors have detailed information that is not shown. Use 'stats.errorDetails: true' resp. '--stats-error-details' to show it. --- src/mathcommand.ts | 6 +++--- src/mathui.ts | 2 +- src/ui/mainformview.ts | 4 ++-- src/ui/mathview.ts | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mathcommand.ts b/src/mathcommand.ts index 644da0b..5a8dbbe 100644 --- a/src/mathcommand.ts +++ b/src/mathcommand.ts @@ -2,8 +2,8 @@ import { Command } from 'ckeditor5/src/core'; import { getSelectedMathModelWidget } from './utils'; export default class MathCommand extends Command { - public value: string | null = null; - public execute( + public override value: string | null = null; + public override execute( equation: string, display?: boolean, outputType: 'script' | 'span' = 'script', @@ -45,7 +45,7 @@ export default class MathCommand extends Command { public display = false; - public refresh(): void { + public override refresh(): void { const model = this.editor.model; const selection = model.document.selection; const selectedElement = selection.getSelectedElement(); diff --git a/src/mathui.ts b/src/mathui.ts index 92bc290..12a9b27 100644 --- a/src/mathui.ts +++ b/src/mathui.ts @@ -38,7 +38,7 @@ export default class MathUI extends Plugin { this._enableUserBalloonInteractions(); } - public destroy(): void { + public override destroy(): void { super.destroy(); this.formView?.destroy(); diff --git a/src/ui/mainformview.ts b/src/ui/mainformview.ts index 0af0e8a..dc48978 100644 --- a/src/ui/mainformview.ts +++ b/src/ui/mainformview.ts @@ -37,7 +37,7 @@ export default class MainFormView extends View { public previewEnabled: boolean; public previewLabel?: LabelView; public mathView?: MathView; - public locale: Locale = new Locale(); + public override locale: Locale = new Locale(); public lazyLoad: undefined | ( () => Promise ); constructor( @@ -127,7 +127,7 @@ export default class MainFormView extends View { } ); } - public render(): void { + public override render(): void { super.render(); // Prevent default form submit event & trigger custom 'submit' diff --git a/src/ui/mathview.ts b/src/ui/mathview.ts index ac8c3a5..5ee587d 100644 --- a/src/ui/mathview.ts +++ b/src/ui/mathview.ts @@ -73,7 +73,7 @@ export default class MathView extends View { } } - public render(): void { + public override render(): void { super.render(); this.updateMath(); } From 8abb816cc47308db25b302b7c39b439c0df888ae Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 05:43:56 -0500 Subject: [PATCH 09/17] .gitignore: Ignore .js and .d.ts files --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 48a9b0a..3c5cf98 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ tmp/ sample/ckeditor.dist.js package-lock.json yarn-error.log + +# Ignore compiled TypeScript files. +src/**/*.js +src/**/*.d.ts From c990a51f95a6ad192d80cc274b761115528415d6 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 06:05:29 -0500 Subject: [PATCH 10/17] katex.d.ts: Genericize TrustContext for now src/katex.d.ts:145:36 - error TS2304: Cannot find name 'TrustContext'. 145 trust?: boolean | ( ( context: TrustContext ) => boolean ) | undefined; --- src/katex.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/katex.d.ts b/src/katex.d.ts index da254b6..8a0dff9 100644 --- a/src/katex.d.ts +++ b/src/katex.d.ts @@ -142,7 +142,7 @@ export interface KatexOptions { * * @default false */ - trust?: boolean | ( ( context: TrustContext ) => boolean ) | undefined; + trust?: boolean | ( ( context: object ) => boolean ) | undefined; /** * Place KaTeX code in the global group. From 0622d46a0690c138423ea4a4bb7b69b9075c54de Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 06:07:56 -0500 Subject: [PATCH 11/17] Tag v41.2.1-alpha.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 445acce..94da9aa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@isaul32/ckeditor5-math", - "version": "41.2.1-alpha.0", + "version": "41.2.1-alpha.1", "description": "Math feature for CKEditor 5.", "keywords": [ "ckeditor", From 9ad24cd7189cccbca53e1b16ab90290d2b049fdc Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 06:14:15 -0500 Subject: [PATCH 12/17] package.json: Export src/index.ts --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 94da9aa..769c2b0 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "ckeditor5-math", "katex" ], - "main": "src/index.js", + "main": "src/index.ts", "dependencies": { "ckeditor5": "41.2.0" }, From 98483998513835d3185fad7d832637d87feb5679 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 06:22:06 -0500 Subject: [PATCH 13/17] chore: src/svg.d.ts -> typings/svg.d.ts More appropriate to be stored in the typings directory, as it is not a source file, but a type definition file for SVGs. --- {src => typings}/svg.d.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {src => typings}/svg.d.ts (100%) diff --git a/src/svg.d.ts b/typings/svg.d.ts similarity index 100% rename from src/svg.d.ts rename to typings/svg.d.ts From 973f053036dc064455c8936199d43d85a2579f70 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 06:26:49 -0500 Subject: [PATCH 14/17] refactor: katex.d.ts -> typings-external.ts This way the .d.ts will not be deleted when filse are deleted through rimraf --- src/augmentation.ts | 2 +- src/{katex.d.ts => typings-external.ts} | 9 ++++++--- src/ui/mainformview.ts | 2 +- src/ui/mathview.ts | 2 +- src/utils.ts | 2 +- 5 files changed, 10 insertions(+), 7 deletions(-) rename src/{katex.d.ts => typings-external.ts} (96%) diff --git a/src/augmentation.ts b/src/augmentation.ts index 3f95f24..0651763 100644 --- a/src/augmentation.ts +++ b/src/augmentation.ts @@ -1,4 +1,4 @@ -import type { KatexOptions } from './katex'; +import type { KatexOptions } from './typings-external'; declare module '@ckeditor/ckeditor5-core' { interface EditorConfig { diff --git a/src/katex.d.ts b/src/typings-external.ts similarity index 96% rename from src/katex.d.ts rename to src/typings-external.ts index 8a0dff9..d0bcf8b 100644 --- a/src/katex.d.ts +++ b/src/typings-external.ts @@ -1,14 +1,17 @@ -interface MathJax3 { +/** + * Basic typings for third party, external libraries (KaTeX, MathJax). + */ +export interface MathJax3 { version: string; tex2chtmlPromise?: ( input: string, options: { display: boolean } ) => Promise; tex2svgPromise?: ( input: string, options: { display: boolean } ) => Promise; } -interface MathJax2 { +export interface MathJax2 { Hub: { Queue: ( callback: [string, MathJax2['Hub'], string | HTMLElement] | ( () => void ) ) => void }; } -interface Katex { +export interface Katex { render( equation: string, el: HTMLElement, options: KatexOptions ): void; } diff --git a/src/ui/mainformview.ts b/src/ui/mainformview.ts index dc48978..0f30272 100644 --- a/src/ui/mainformview.ts +++ b/src/ui/mainformview.ts @@ -16,7 +16,7 @@ import { Locale, FocusTracker, KeystrokeHandler } from 'ckeditor5/src/utils'; import { extractDelimiters, hasDelimiters } from '../utils'; import MathView from './mathview'; import '../../theme/mathform.css'; -import type { KatexOptions } from '../katex'; +import type { KatexOptions } from '../typings-external'; const { check: checkIcon, cancel: cancelIcon } = icons; diff --git a/src/ui/mathview.ts b/src/ui/mathview.ts index 5ee587d..98cb875 100644 --- a/src/ui/mathview.ts +++ b/src/ui/mathview.ts @@ -1,7 +1,7 @@ import { View } from 'ckeditor5/src/ui'; +import type { KatexOptions } from '../typings-external'; import { renderEquation } from '../utils'; import type { Locale } from 'ckeditor5/src/utils'; -import type { KatexOptions } from '../katex'; export default class MathView extends View { public value: string; diff --git a/src/utils.ts b/src/utils.ts index 31a68e9..a5a8690 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,7 +5,7 @@ import type { } from 'ckeditor5/src/engine'; import { BalloonPanelView } from 'ckeditor5/src/ui'; import { CKEditorError, type PositioningFunction } from 'ckeditor5/src/utils'; -import type { KatexOptions, MathJax2, MathJax3 } from './katex'; +import type { KatexOptions, MathJax2, MathJax3 } from './typings-external'; export function getSelectedMathModelWidget( selection: DocumentSelection From e2acae2d7b5cd7da6e7cedffb9d95fbd02e8064e Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sat, 16 Mar 2024 06:33:44 -0500 Subject: [PATCH 15/17] Tag v41.2.1-alpha.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 769c2b0..3f59b3c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@isaul32/ckeditor5-math", - "version": "41.2.1-alpha.1", + "version": "41.2.1-alpha.2", "description": "Math feature for CKEditor 5.", "keywords": [ "ckeditor", From 1a6f1b3d41cdee903ab98094bd21b241b7e0b398 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 17 Mar 2024 04:07:28 -0500 Subject: [PATCH 16/17] package.json: Export .js and .d.ts in builds --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 3f59b3c..b381975 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,8 @@ }, "files": [ "lang", - "src", + "src/**/*.js", + "src/**/*.d.ts", "build", "theme", "ckeditor5-metadata.json", From 3fa4e0ca257e849d1e4923ddf6aa5bdb4f70ed21 Mon Sep 17 00:00:00 2001 From: Tony Narlock Date: Sun, 17 Mar 2024 04:07:39 -0500 Subject: [PATCH 17/17] Tag v41.2.1-alpha.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b381975..8b89eeb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@isaul32/ckeditor5-math", - "version": "41.2.1-alpha.2", + "version": "41.2.1-alpha.3", "description": "Math feature for CKEditor 5.", "keywords": [ "ckeditor",