2
0
mirror of https://github.com/Ionaru/easy-markdown-editor synced 2025-07-30 13:24:28 -06:00

Modernize code

This commit is contained in:
Jeroen akkerman 2025-05-01 17:44:31 +02:00
parent 31d9ae828e
commit 58cb51e2d7
8 changed files with 533 additions and 84 deletions

447
package-lock.json generated
View File

@ -22,6 +22,7 @@
"@eslint/js": "^9.25.1",
"@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.2",
"@types/node": "^22.15.3",
"@vitest/coverage-v8": "^3.1.2",
"@vitest/ui": "^3.1.2",
@ -35,6 +36,8 @@
"prettier": "^3.5.3",
"rollup": "^4.40.1",
"rollup-plugin-cleaner": "^1.0.0",
"rollup-plugin-scss": "^4.0.1",
"sass": "^1.87.0",
"tslib": "^2.8.1",
"typescript": "^5.8.3",
"typescript-eslint": "^8.31.1",
@ -1333,6 +1336,316 @@
"node": ">= 8"
}
},
"node_modules/@parcel/watcher": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"detect-libc": "^1.0.3",
"is-glob": "^4.0.3",
"micromatch": "^4.0.5",
"node-addon-api": "^7.0.0"
},
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"@parcel/watcher-android-arm64": "2.5.1",
"@parcel/watcher-darwin-arm64": "2.5.1",
"@parcel/watcher-darwin-x64": "2.5.1",
"@parcel/watcher-freebsd-x64": "2.5.1",
"@parcel/watcher-linux-arm-glibc": "2.5.1",
"@parcel/watcher-linux-arm-musl": "2.5.1",
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
"@parcel/watcher-linux-arm64-musl": "2.5.1",
"@parcel/watcher-linux-x64-glibc": "2.5.1",
"@parcel/watcher-linux-x64-musl": "2.5.1",
"@parcel/watcher-win32-arm64": "2.5.1",
"@parcel/watcher-win32-ia32": "2.5.1",
"@parcel/watcher-win32-x64": "2.5.1"
}
},
"node_modules/@parcel/watcher-android-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
"integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
"integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
"integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-freebsd-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
"integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
"integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
"integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
"integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
"integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
"integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
"integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
"integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-ia32": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
"integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
"integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@pkgjs/parseargs": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
@ -1399,6 +1712,33 @@
}
}
},
"node_modules/@rollup/plugin-typescript": {
"version": "12.1.2",
"resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.1.2.tgz",
"integrity": "sha512-cdtSp154H5sv637uMr1a8OTWB0L1SWDSm1rDGiyfcGcvQ6cuTs4MDk2BVEBGysUWago4OJN4EQZqOTl/QY3Jgg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@rollup/pluginutils": "^5.1.0",
"resolve": "^1.22.1"
},
"engines": {
"node": ">=14.0.0"
},
"peerDependencies": {
"rollup": "^2.14.0||^3.0.0||^4.0.0",
"tslib": "*",
"typescript": ">=3.7.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
},
"tslib": {
"optional": true
}
}
},
"node_modules/@rollup/pluginutils": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
@ -2893,6 +3233,22 @@
"node": ">= 0.8.0"
}
},
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"readdirp": "^4.0.1"
},
"engines": {
"node": ">= 14.16.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/ci-info": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz",
@ -3356,6 +3712,20 @@
"node": ">=0.4.0"
}
},
"node_modules/detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
"dev": true,
"license": "Apache-2.0",
"optional": true,
"bin": {
"detect-libc": "bin/detect-libc.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@ -4916,6 +5286,13 @@
"node": ">= 4"
}
},
"node_modules/immutable": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.1.tgz",
"integrity": "sha512-3jatXi9ObIsPGr3N5hGw/vWWcTkq6hUYhpQz4k0wLC+owqWi/LiugIw9x0EdNZ2yGedKN/HzePiBvaJRXa0Ujg==",
"dev": true,
"license": "MIT"
},
"node_modules/import-fresh": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
@ -6036,6 +6413,14 @@
"dev": true,
"license": "MIT"
},
"node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
"dev": true,
"license": "MIT",
"optional": true
},
"node_modules/node-releases": {
"version": "2.0.19",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
@ -6577,6 +6962,20 @@
"safe-buffer": "^5.1.0"
}
},
"node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 14.18.0"
},
"funding": {
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/refa": {
"version": "0.12.1",
"resolved": "https://registry.npmjs.org/refa/-/refa-0.12.1.tgz",
@ -6799,6 +7198,33 @@
"rimraf": "bin.js"
}
},
"node_modules/rollup-plugin-scss": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/rollup-plugin-scss/-/rollup-plugin-scss-4.0.1.tgz",
"integrity": "sha512-3W3+3OzR+shkDl3hJ1XTAuGkP4AfiLgIjie2GtcoZ9pHfRiNqeDbtCu1EUnkjZ98EPIM6nnMIXkKlc7Sx5bRvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"rollup-pluginutils": "^2.3.3"
}
},
"node_modules/rollup-pluginutils": {
"version": "2.8.2",
"resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz",
"integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"estree-walker": "^0.6.1"
}
},
"node_modules/rollup-pluginutils/node_modules/estree-walker": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz",
"integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==",
"dev": true,
"license": "MIT"
},
"node_modules/rrweb-cssom": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz",
@ -6905,6 +7331,27 @@
"dev": true,
"license": "MIT"
},
"node_modules/sass": {
"version": "1.87.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.87.0.tgz",
"integrity": "sha512-d0NoFH4v6SjEK7BoX810Jsrhj7IQSYHAHLi/iSpgqKc7LaIDshFRlSg5LOymf9FqQhxEHs2W5ZQXlvy0KD45Uw==",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": "^4.0.0",
"immutable": "^5.0.2",
"source-map-js": ">=0.6.2 <2.0.0"
},
"bin": {
"sass": "sass.js"
},
"engines": {
"node": ">=14.0.0"
},
"optionalDependencies": {
"@parcel/watcher": "^2.4.1"
}
},
"node_modules/saxes": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",

View File

@ -16,8 +16,7 @@
"author": "Jeroen Akkerman",
"repository": "github:Ionaru/easy-markdown-editor",
"scripts": {
"clean": "npx rimraf dist",
"prebuild": "npm run clean",
"clean": "npx -y rimraf dist",
"build": "rollup -c",
"build:watch": "rollup -c -w",
"build:types": "tsc --emitDeclarationOnly --declaration --outDir dist/types",
@ -43,6 +42,7 @@
"@eslint/js": "^9.25.1",
"@rollup/plugin-node-resolve": "^16.0.1",
"@rollup/plugin-terser": "^0.4.4",
"@rollup/plugin-typescript": "^12.1.2",
"@types/node": "^22.15.3",
"@vitest/coverage-v8": "^3.1.2",
"@vitest/ui": "^3.1.2",
@ -56,6 +56,8 @@
"prettier": "^3.5.3",
"rollup": "^4.40.1",
"rollup-plugin-cleaner": "^1.0.0",
"rollup-plugin-scss": "^4.0.1",
"sass": "^1.87.0",
"tslib": "^2.8.1",
"typescript": "^5.8.3",
"typescript-eslint": "^8.31.1",

View File

@ -17,15 +17,14 @@ import { InputOptions, Options } from "./options";
import "./styles.scss";
export class EasyMDE {
private readonly element: HTMLTextAreaElement;
readonly #element: HTMLTextAreaElement;
#container?: HTMLDivElement;
#codemirror?: EditorView;
// private rendered = false;
readonly #options: Options;
private readonly plugins: IEasyMDEPlugin[] = [];
readonly #plugins: IEasyMDEPlugin[] = [];
public constructor(options: InputOptions) {
constructor(options: InputOptions) {
this.#options = {
...options,
blockStyles: {
@ -35,33 +34,31 @@ export class EasyMDE {
code: "`",
},
};
this.element = EasyMDE.verifyAndReturnElement(options.element);
this.#element = EasyMDE.#verifyAndReturnElement(options.element);
marked.parse("# EasyMDE", { async: false });
// eslint-disable-next-line sonarjs/no-async-constructor
void this.construct();
}
public get container(): HTMLDivElement {
get container(): HTMLDivElement {
if (!this.#container) {
throw new NotConstructedError();
}
return this.#container;
}
public get codemirror(): EditorView {
get codemirror(): EditorView {
if (!this.#codemirror) {
throw new NotConstructedError();
}
return this.#codemirror;
}
public get options(): Readonly<Options> {
get options(): Readonly<Options> {
return Object.freeze(this.#options);
}
private static verifyAndReturnElement(
element?: HTMLElement,
): HTMLTextAreaElement {
static #verifyAndReturnElement(element?: HTMLElement): HTMLTextAreaElement {
if (!(element instanceof HTMLTextAreaElement)) {
throw new TypeError(
'EasyMDE: Parameter "element" must be a TextArea.',
@ -71,11 +68,11 @@ export class EasyMDE {
return element;
}
public get isRendered(): boolean {
get isRendered(): boolean {
return Boolean(this.container && this.codemirror);
}
public async construct(): Promise<void> {
async construct(): Promise<void> {
if (this.#container && this.#codemirror) {
throw new AlreadyConstructedError();
}
@ -126,10 +123,10 @@ export class EasyMDE {
},
]);
this.element.hidden = true;
this.#element.hidden = true;
this.#codemirror = new EditorView({
state: EditorState.create({
doc: this.element.value,
doc: this.#element.value,
extensions: [
syntaxHighlighting(highlightStyle),
syntaxHighlighting(defaultHighlightStyle),
@ -140,35 +137,35 @@ export class EasyMDE {
drawSelection(),
],
selection: {
anchor: this.element.value.length,
anchor: this.#element.value.length,
},
}),
// parent: this.element.parentElement || document.body,
});
const easyMDEContainer = this.createContainer();
const easyMDEContainer = this.#createContainer();
if (this.options.toolbar !== false) {
easyMDEContainer.append(await this.createToolbar());
easyMDEContainer.append(await this.#createToolbar());
}
easyMDEContainer.append(this.codemirror.dom);
if (this.options.statusbar !== false) {
easyMDEContainer.append(await this.createStatusBar());
easyMDEContainer.append(await this.#createStatusBar());
}
this.element.insertAdjacentElement("afterend", easyMDEContainer);
this.#element.insertAdjacentElement("afterend", easyMDEContainer);
this.codemirror.focus();
this.#container = easyMDEContainer;
}
public destruct(): void {
this.element.value = this.codemirror.state.doc.toString();
destruct(): void {
this.#element.value = this.codemirror.state.doc.toString();
for (const plugin of this.plugins) {
for (const plugin of this.#plugins) {
void plugin.destroy();
}
@ -178,15 +175,15 @@ export class EasyMDE {
this.#container = undefined;
this.#codemirror = undefined;
this.element.hidden = false;
this.#element.hidden = false;
}
public addPlugin(plugin: IEasyMDEPlugin): IEasyMDEPlugin {
this.plugins.push(plugin);
addPlugin(plugin: IEasyMDEPlugin): IEasyMDEPlugin {
this.#plugins.push(plugin);
return plugin;
}
private async createToolbar(): Promise<HTMLDivElement> {
async #createToolbar(): Promise<HTMLDivElement> {
const [{ Toolbar }, { defaultToolbar }] = await Promise.all([
importToolbar(),
importDefaultToolbar(),
@ -197,13 +194,13 @@ export class EasyMDE {
return toolbar.element;
}
private async createStatusBar(): Promise<HTMLDivElement> {
async #createStatusBar(): Promise<HTMLDivElement> {
const { StatusBar } = await import("./status-bar/status-bar");
const statusBar = new StatusBar(this);
return statusBar.element;
}
private createContainer(): HTMLDivElement {
#createContainer(): HTMLDivElement {
const container = document.createElement("div");
container.classList.add("easymde-container");
return container;

View File

@ -1,5 +1,5 @@
export class AlreadyConstructedError extends Error {
public constructor() {
constructor() {
super("EasyMDE is already initialized.");
this.name = "AlreadyConstructedError";
}

View File

@ -1,5 +1,5 @@
export class NotConstructedError extends Error {
public constructor() {
constructor() {
super(
'EasyMDE is not initialized, run the "construct()" method to do so.',
);

View File

@ -5,34 +5,34 @@ import { EasyMDE } from "../easymde";
import { countWords } from "../utils/count-words";
export class StatusBar {
public element: HTMLDivElement;
element: HTMLDivElement;
private characterCount = 0;
private wordCount = 0;
private lineCount = 1;
private cursorLine = 1;
private cursorColumn = 1;
#characterCount = 0;
#wordCount = 0;
#lineCount = 1;
#cursorLine = 1;
#cursorColumn = 1;
private selectionStart = 0;
private selectionEnd = 0;
#selectionStart = 0;
#selectionEnd = 0;
public constructor(private editor: EasyMDE) {
constructor(private editor: EasyMDE) {
this.element = document.createElement("div");
this.element.className = "easymde-statusbar";
// Initial values
this.characterCount = this.editor.codemirror.state.doc.length;
this.wordCount = countWords(this.editor.codemirror.state.doc);
this.lineCount = this.editor.codemirror.state.doc.lines;
this.#characterCount = this.editor.codemirror.state.doc.length;
this.#wordCount = countWords(this.editor.codemirror.state.doc);
this.#lineCount = this.editor.codemirror.state.doc.lines;
const line = this.editor.codemirror.state.doc.lineAt(
this.editor.codemirror.state.selection.main.to,
);
this.cursorLine = line.number;
this.cursorColumn =
this.#cursorLine = line.number;
this.#cursorColumn =
this.editor.codemirror.state.selection.main.to - line.from + 1;
this.selectionStart = this.editor.codemirror.state.selection.main.from;
this.selectionEnd = this.editor.codemirror.state.selection.main.to;
this.#selectionStart = this.editor.codemirror.state.selection.main.from;
this.#selectionEnd = this.editor.codemirror.state.selection.main.to;
this.editor.codemirror.dispatch({
effects: StateEffect.appendConfig.of(
@ -41,11 +41,12 @@ export class StatusBar {
const document = update.state.doc;
const selection = update.state.selection.main;
this.characterCount = document.length;
this.wordCount = countWords(document);
this.lineCount = document.lines;
this.#characterCount = document.length;
this.#wordCount = countWords(document);
this.#lineCount = document.lines;
const direction = this.getSelectionDirection(selection);
const direction =
this.#getSelectionDirection(selection);
const toLine = document.lineAt(selection.to);
const fromLine = document.lineAt(selection.from);
@ -54,25 +55,25 @@ export class StatusBar {
if (direction === "left") {
// Cursor is at the start of the selection.
cursorLine = fromLine;
this.cursorColumn =
this.#cursorColumn =
selection.from - cursorLine.from;
} else {
// Cursor is at the end of the selection, or there is no selection.
cursorLine = toLine;
this.cursorColumn = selection.to - cursorLine.from;
this.#cursorColumn = selection.to - cursorLine.from;
if (this.cursorColumn > toLine.length) {
if (this.#cursorColumn > toLine.length) {
// Column is incorrect, can happen when Ctrl+A is used. We need to manually adjust it.
this.cursorColumn = toLine.length;
this.#cursorColumn = toLine.length;
}
}
this.cursorLine = cursorLine.number;
this.selectionStart = selection.from;
this.selectionEnd = selection.to;
this.#cursorLine = cursorLine.number;
this.#selectionStart = selection.from;
this.#selectionEnd = selection.to;
// We start counting columns at 1.
this.cursorColumn++;
this.#cursorColumn++;
this.render();
},
@ -83,22 +84,22 @@ export class StatusBar {
this.render();
}
public render() {
render() {
this.element.innerHTML = `
<span class="status-bar-element">Lines: ${this.lineCount}</span>
<span class="status-bar-element">Words: ${this.wordCount}</span>
<span class="status-bar-element">Characters: ${this.characterCount}</span>
<span class="status-bar-element">Pos: ${this.cursorLine}:${this.cursorColumn}</span>
<span class="status-bar-element">Lines: ${this.#lineCount}</span>
<span class="status-bar-element">Words: ${this.#wordCount}</span>
<span class="status-bar-element">Characters: ${this.#characterCount}</span>
<span class="status-bar-element">Pos: ${this.#cursorLine}:${this.#cursorColumn}</span>
`;
}
private getSelectionDirection(
#getSelectionDirection(
selection: SelectionRange,
): "right" | "left" | undefined {
return selection.from === this.selectionStart
return selection.from === this.#selectionStart
? "right"
: // eslint-disable-next-line sonarjs/no-nested-conditional
selection.to === this.selectionEnd
selection.to === this.#selectionEnd
? "left"
: undefined;
}

View File

@ -1,10 +1,12 @@
@use "sass:color";
$light-border-color: #d1d1d1;
:root {
--easymde-border-color: #{$light-border-color};
--easymde-enabled-color: #{lighten($light-border-color, 5%)};
--easymde-enabled-color: #{color.adjust($light-border-color, $lightness: 5%)};
--easymde-hover-color: #{$light-border-color};
--easymde-active-color: #{darken($light-border-color, 5%)};
--easymde-active-color: #{color.adjust($light-border-color, $lightness: -5%)};
}
// @media (prefers-color-scheme: dark) {

View File

@ -6,11 +6,11 @@ import { EasyMDE, IEasyMDEPlugin } from "../easymde";
import { IToolbarButtonOptions } from "./default-toolbar";
export class Toolbar implements IEasyMDEPlugin {
private static readonly activeClass = "enabled";
static readonly #activeClass = "enabled";
public element: HTMLDivElement;
element: HTMLDivElement;
public constructor(
constructor(
private editor: EasyMDE,
toolbarLayout: IToolbarButtonOptions[][],
) {
@ -22,7 +22,7 @@ export class Toolbar implements IEasyMDEPlugin {
for (const toolBarButtonOptions of toolBarButtonSection) {
toolBarSection.push(
this.createToolBarButton(toolBarButtonOptions),
this.#createToolBarButton(toolBarButtonOptions),
);
}
@ -31,7 +31,7 @@ export class Toolbar implements IEasyMDEPlugin {
toolbarLayout.indexOf(toolBarButtonSection) !==
toolbarLayout.length - 1
) {
toolBarSection.push(this.createToolBarSeparator());
toolBarSection.push(this.#createToolBarSeparator());
}
for (const toolBarEntry of toolBarSection) {
@ -52,13 +52,13 @@ export class Toolbar implements IEasyMDEPlugin {
}
// eslint-disable-next-line @typescript-eslint/require-await
public async build(toolbarLayout: IToolbarButtonOptions[][]) {
async build(toolbarLayout: IToolbarButtonOptions[][]) {
for (const toolBarButtonSection of toolbarLayout) {
const toolBarSection: (HTMLButtonElement | HTMLSpanElement)[] = [];
for (const toolBarButtonOptions of toolBarButtonSection) {
toolBarSection.push(
this.createToolBarButton(toolBarButtonOptions),
this.#createToolBarButton(toolBarButtonOptions),
);
}
@ -67,7 +67,7 @@ export class Toolbar implements IEasyMDEPlugin {
toolbarLayout.indexOf(toolBarButtonSection) !==
toolbarLayout.length - 1
) {
toolBarSection.push(this.createToolBarSeparator());
toolBarSection.push(this.#createToolBarSeparator());
}
for (const toolBarEntry of toolBarSection) {
@ -76,18 +76,18 @@ export class Toolbar implements IEasyMDEPlugin {
}
}
// eslint-disable-next-line @typescript-eslint/require-await
public async destroy() {
async destroy() {
this.element.remove();
}
private createToolBarSeparator() {
#createToolBarSeparator() {
const separatorElement = document.createElement("span");
separatorElement.className = "separator";
separatorElement.innerHTML = "|";
return separatorElement;
}
private createToolBarButton(
#createToolBarButton(
toolBarButtonOptions: IToolbarButtonOptions,
): HTMLButtonElement {
const buttonElement: HTMLButtonElement =
@ -114,7 +114,7 @@ export class Toolbar implements IEasyMDEPlugin {
if (typeof toolBarButtonOptions.active === "boolean") {
buttonElement.classList.toggle(
Toolbar.activeClass,
Toolbar.#activeClass,
toolBarButtonOptions.active,
);
} else if (typeof toolBarButtonOptions.active === "function") {
@ -132,7 +132,7 @@ export class Toolbar implements IEasyMDEPlugin {
update,
);
buttonElement.classList.toggle(
Toolbar.activeClass,
Toolbar.#activeClass,
result,
);
}