From d4f2fcdf7908ffa176350468a85e631f0497646c Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 2 Aug 2022 20:11:02 +0100 Subject: [PATCH 01/22] Started codemirror update, In broken state --- dev/build/esbuild.js | 16 +- package-lock.json | 633 +++++++++++++++------- package.json | 13 +- resources/js/{code.mjs => code/index.mjs} | 161 ++---- resources/js/code/modes.js | 134 +++++ resources/js/code/setups.js | 32 ++ 6 files changed, 661 insertions(+), 328 deletions(-) rename resources/js/{code.mjs => code/index.mjs} (55%) create mode 100644 resources/js/code/modes.js create mode 100644 resources/js/code/setups.js diff --git a/dev/build/esbuild.js b/dev/build/esbuild.js index 46357038a..57a224876 100644 --- a/dev/build/esbuild.js +++ b/dev/build/esbuild.js @@ -1,7 +1,6 @@ #!/usr/bin/env node const esbuild = require('esbuild'); -const fs = require('fs'); const path = require('path'); // Check if we're building for production @@ -9,20 +8,19 @@ const path = require('path'); const isProd = process.argv[2] === 'production'; // Gather our input files -const jsInDir = path.join(__dirname, '../../resources/js'); -const jsInDirFiles = fs.readdirSync(jsInDir, 'utf8'); -const entryFiles = jsInDirFiles - .filter(f => f.endsWith('.js') || f.endsWith('.mjs')) - .map(f => path.join(jsInDir, f)); +const entryPoints = { + app: path.join(__dirname, '../../resources/js/app.js'), + code: path.join(__dirname, '../../resources/js/code/index.mjs'), +}; // Locate our output directory -const outDir = path.join(__dirname, '../../public/dist'); +const outdir = path.join(__dirname, '../../public/dist'); // Build via esbuild esbuild.build({ bundle: true, - entryPoints: entryFiles, - outdir: outDir, + entryPoints, + outdir, sourcemap: true, target: 'es2020', mainFields: ['module', 'main'], diff --git a/package-lock.json b/package-lock.json index 1448d592f..c141e654a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,21 +5,131 @@ "packages": { "": { "dependencies": { + "@codemirror/commands": "^6.0.1", + "@codemirror/language": "^6.2.1", + "@codemirror/legacy-modes": "^6.1.0", + "@codemirror/state": "^6.1.0", + "@codemirror/view": "^6.1.2", "clipboard": "^2.0.11", - "codemirror": "^5.65.5", + "codemirror": "^6.0.1", "dropzone": "^5.9.3", "markdown-it": "^13.0.1", "markdown-it-task-lists": "^2.1.1", - "snabbdom": "^3.5.0", + "snabbdom": "^3.5.1", "sortablejs": "^1.15.0" }, "devDependencies": { "chokidar-cli": "^3.0", - "esbuild": "0.14.42", + "esbuild": "0.14.51", "livereload": "^0.9.3", "npm-run-all": "^4.1.5", "punycode": "^2.1.1", - "sass": "^1.52.1" + "sass": "^1.54.0" + } + }, + "node_modules/@codemirror/autocomplete": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.1.0.tgz", + "integrity": "sha512-wtO4O5WDyXhhCd4q4utDIDZxnQfmJ++3dGBCG9LMtI79+92OcA1DVk/n7BEupKmjIr8AzvptDz7YQ9ud6OkU+A==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + }, + "peerDependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/commands": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.0.1.tgz", + "integrity": "sha512-iNHDByicYqQjs0Wo1MKGfqNbMYMyhS9WV6EwMVwsHXImlFemgEUC+c5X22bXKBStN3qnwg4fArNZM+gkv22baQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@codemirror/language": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz", + "integrity": "sha512-MC3svxuvIj0MRpFlGHxLS6vPyIdbTr2KKPEW46kCoCXw2ktb4NTkpkPBI/lSP/FoNXLCBJ0mrnUi1OoZxtpW1Q==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "node_modules/@codemirror/legacy-modes": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.1.0.tgz", + "integrity": "sha512-V/PgGpndkZeTn3Hdlg/gd8MLFdyvTCIX+iwJzjUw5iNziWiNsAY8X0jvf7m3gSfxnKkNzmid6l0g4rYSpiDaCw==", + "dependencies": { + "@codemirror/language": "^6.0.0" + } + }, + "node_modules/@codemirror/lint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.0.0.tgz", + "integrity": "sha512-nUUXcJW1Xp54kNs+a1ToPLK8MadO0rMTnJB8Zk4Z8gBdrN0kqV7uvUraU/T2yqg+grDNR38Vmy/MrhQN/RgwiA==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/search": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.0.1.tgz", + "integrity": "sha512-uOinkOrM+daMduCgMPomDfKLr7drGHB4jHl3Vq6xY2WRlL7MkNsBE0b+XHYa/Mee2npsJOgwvkW4n1lMFeBW2Q==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "node_modules/@codemirror/state": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.1.0.tgz", + "integrity": "sha512-qbUr94DZTe6/V1VS7LDLz11rM/1t/nJxR1El4I6UaxDEdc0aZZvq6JCLJWiRmUf95NRAnDH6fhXn+PWp9wGCIg==" + }, + "node_modules/@codemirror/view": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.1.2.tgz", + "integrity": "sha512-puUydfKwfmOo+ixtuB+uN/ZpcteEYSnpjHmMaow1sOQhNICsKtGBup3i9ybVqyzDagARRYzSHTWjbdeHqmn31w==", + "dependencies": { + "@codemirror/state": "^6.0.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, + "node_modules/@lezer/common": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz", + "integrity": "sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA==" + }, + "node_modules/@lezer/highlight": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.0.0.tgz", + "integrity": "sha512-nsCnNtim90UKsB5YxoX65v3GEIw3iCHw9RM2DtdgkiqAbKh9pCdvi8AWNwkYf10Lu6fxNhXPpkpHbW6mihhvJA==", + "dependencies": { + "@lezer/common": "^1.0.0" + } + }, + "node_modules/@lezer/lr": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.0.tgz", + "integrity": "sha512-TgEpfm9br2SX8JwtwKT8HsQZKuFkLRg6g+IRxObk9nVKQLKnkP3oMh+QGcTBL9GQsfQ2ADtKPbj2iGSMf3ytiA==", + "dependencies": { + "@lezer/common": "^1.0.0" } }, "node_modules/ansi-regex": { @@ -195,9 +305,18 @@ } }, "node_modules/codemirror": { - "version": "5.65.5", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.5.tgz", - "integrity": "sha512-HNyhvGLnYz5c+kIsB9QKVitiZUevha3ovbIYaQiGzKo7ECSL/elWD9RXt3JgNr0NdnyqE9/Rc/7uLfkJQL638w==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } }, "node_modules/color-convert": { "version": "1.9.3", @@ -220,6 +339,11 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "node_modules/crelt": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", + "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==" + }, "node_modules/cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -345,9 +469,9 @@ } }, "node_modules/esbuild": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.42.tgz", - "integrity": "sha512-V0uPZotCEHokJdNqyozH6qsaQXqmZEOiZWrXnds/zaH/0SyrIayRXWRB98CENO73MIZ9T3HBIOsmds5twWtmgw==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.51.tgz", + "integrity": "sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==", "dev": true, "hasInstallScript": true, "bin": { @@ -357,32 +481,32 @@ "node": ">=12" }, "optionalDependencies": { - "esbuild-android-64": "0.14.42", - "esbuild-android-arm64": "0.14.42", - "esbuild-darwin-64": "0.14.42", - "esbuild-darwin-arm64": "0.14.42", - "esbuild-freebsd-64": "0.14.42", - "esbuild-freebsd-arm64": "0.14.42", - "esbuild-linux-32": "0.14.42", - "esbuild-linux-64": "0.14.42", - "esbuild-linux-arm": "0.14.42", - "esbuild-linux-arm64": "0.14.42", - "esbuild-linux-mips64le": "0.14.42", - "esbuild-linux-ppc64le": "0.14.42", - "esbuild-linux-riscv64": "0.14.42", - "esbuild-linux-s390x": "0.14.42", - "esbuild-netbsd-64": "0.14.42", - "esbuild-openbsd-64": "0.14.42", - "esbuild-sunos-64": "0.14.42", - "esbuild-windows-32": "0.14.42", - "esbuild-windows-64": "0.14.42", - "esbuild-windows-arm64": "0.14.42" + "esbuild-android-64": "0.14.51", + "esbuild-android-arm64": "0.14.51", + "esbuild-darwin-64": "0.14.51", + "esbuild-darwin-arm64": "0.14.51", + "esbuild-freebsd-64": "0.14.51", + "esbuild-freebsd-arm64": "0.14.51", + "esbuild-linux-32": "0.14.51", + "esbuild-linux-64": "0.14.51", + "esbuild-linux-arm": "0.14.51", + "esbuild-linux-arm64": "0.14.51", + "esbuild-linux-mips64le": "0.14.51", + "esbuild-linux-ppc64le": "0.14.51", + "esbuild-linux-riscv64": "0.14.51", + "esbuild-linux-s390x": "0.14.51", + "esbuild-netbsd-64": "0.14.51", + "esbuild-openbsd-64": "0.14.51", + "esbuild-sunos-64": "0.14.51", + "esbuild-windows-32": "0.14.51", + "esbuild-windows-64": "0.14.51", + "esbuild-windows-arm64": "0.14.51" } }, "node_modules/esbuild-android-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.42.tgz", - "integrity": "sha512-P4Y36VUtRhK/zivqGVMqhptSrFILAGlYp0Z8r9UQqHJ3iWztRCNWnlBzD9HRx0DbueXikzOiwyOri+ojAFfW6A==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.51.tgz", + "integrity": "sha512-6FOuKTHnC86dtrKDmdSj2CkcKF8PnqkaIXqvgydqfJmqBazCPdw+relrMlhGjkvVdiiGV70rpdnyFmA65ekBCQ==", "cpu": [ "x64" ], @@ -396,9 +520,9 @@ } }, "node_modules/esbuild-android-arm64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.42.tgz", - "integrity": "sha512-0cOqCubq+RWScPqvtQdjXG3Czb3AWI2CaKw3HeXry2eoA2rrPr85HF7IpdU26UWdBXgPYtlTN1LUiuXbboROhg==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.51.tgz", + "integrity": "sha512-vBtp//5VVkZWmYYvHsqBRCMMi1MzKuMIn5XDScmnykMTu9+TD9v0NMEDqQxvtFToeYmojdo5UCV2vzMQWJcJ4A==", "cpu": [ "arm64" ], @@ -412,9 +536,9 @@ } }, "node_modules/esbuild-darwin-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.42.tgz", - "integrity": "sha512-ipiBdCA3ZjYgRfRLdQwP82rTiv/YVMtW36hTvAN5ZKAIfxBOyPXY7Cejp3bMXWgzKD8B6O+zoMzh01GZsCuEIA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.51.tgz", + "integrity": "sha512-YFmXPIOvuagDcwCejMRtCDjgPfnDu+bNeh5FU2Ryi68ADDVlWEpbtpAbrtf/lvFTWPexbgyKgzppNgsmLPr8PA==", "cpu": [ "x64" ], @@ -428,9 +552,9 @@ } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.42.tgz", - "integrity": "sha512-bU2tHRqTPOaoH/4m0zYHbFWpiYDmaA0gt90/3BMEFaM0PqVK/a6MA2V/ypV5PO0v8QxN6gH5hBPY4YJ2lopXgA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.51.tgz", + "integrity": "sha512-juYD0QnSKwAMfzwKdIF6YbueXzS6N7y4GXPDeDkApz/1RzlT42mvX9jgNmyOlWKN7YzQAYbcUEJmZJYQGdf2ow==", "cpu": [ "arm64" ], @@ -444,9 +568,9 @@ } }, "node_modules/esbuild-freebsd-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.42.tgz", - "integrity": "sha512-75h1+22Ivy07+QvxHyhVqOdekupiTZVLN1PMwCDonAqyXd8TVNJfIRFrdL8QmSJrOJJ5h8H1I9ETyl2L8LQDaw==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.51.tgz", + "integrity": "sha512-cLEI/aXjb6vo5O2Y8rvVSQ7smgLldwYY5xMxqh/dQGfWO+R1NJOFsiax3IS4Ng300SVp7Gz3czxT6d6qf2cw0g==", "cpu": [ "x64" ], @@ -460,9 +584,9 @@ } }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.42.tgz", - "integrity": "sha512-W6Jebeu5TTDQMJUJVarEzRU9LlKpNkPBbjqSu+GUPTHDCly5zZEQq9uHkmHHl7OKm+mQ2zFySN83nmfCeZCyNA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.51.tgz", + "integrity": "sha512-TcWVw/rCL2F+jUgRkgLa3qltd5gzKjIMGhkVybkjk6PJadYInPtgtUBp1/hG+mxyigaT7ib+od1Xb84b+L+1Mg==", "cpu": [ "arm64" ], @@ -476,9 +600,9 @@ } }, "node_modules/esbuild-linux-32": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.42.tgz", - "integrity": "sha512-Ooy/Bj+mJ1z4jlWcK5Dl6SlPlCgQB9zg1UrTCeY8XagvuWZ4qGPyYEWGkT94HUsRi2hKsXvcs6ThTOjBaJSMfg==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.51.tgz", + "integrity": "sha512-RFqpyC5ChyWrjx8Xj2K0EC1aN0A37H6OJfmUXIASEqJoHcntuV3j2Efr9RNmUhMfNE6yEj2VpYuDteZLGDMr0w==", "cpu": [ "ia32" ], @@ -492,9 +616,9 @@ } }, "node_modules/esbuild-linux-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.42.tgz", - "integrity": "sha512-2L0HbzQfbTuemUWfVqNIjOfaTRt9zsvjnme6lnr7/MO9toz/MJ5tZhjqrG6uDWDxhsaHI2/nsDgrv8uEEN2eoA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.51.tgz", + "integrity": "sha512-dxjhrqo5i7Rq6DXwz5v+MEHVs9VNFItJmHBe1CxROWNf4miOGoQhqSG8StStbDkQ1Mtobg6ng+4fwByOhoQoeA==", "cpu": [ "x64" ], @@ -508,9 +632,9 @@ } }, "node_modules/esbuild-linux-arm": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.42.tgz", - "integrity": "sha512-STq69yzCMhdRaWnh29UYrLSr/qaWMm/KqwaRF1pMEK7kDiagaXhSL1zQGXbYv94GuGY/zAwzK98+6idCMUOOCg==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.51.tgz", + "integrity": "sha512-LsJynDxYF6Neg7ZC7748yweCDD+N8ByCv22/7IAZglIEniEkqdF4HCaa49JNDLw1UQGlYuhOB8ZT/MmcSWzcWg==", "cpu": [ "arm" ], @@ -524,9 +648,9 @@ } }, "node_modules/esbuild-linux-arm64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.42.tgz", - "integrity": "sha512-c3Ug3e9JpVr8jAcfbhirtpBauLxzYPpycjWulD71CF6ZSY26tvzmXMJYooQ2YKqDY4e/fPu5K8bm7MiXMnyxuA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.51.tgz", + "integrity": "sha512-D9rFxGutoqQX3xJPxqd6o+kvYKeIbM0ifW2y0bgKk5HPgQQOo2k9/2Vpto3ybGYaFPCE5qTGtqQta9PoP6ZEzw==", "cpu": [ "arm64" ], @@ -540,9 +664,9 @@ } }, "node_modules/esbuild-linux-mips64le": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.42.tgz", - "integrity": "sha512-QuvpHGbYlkyXWf2cGm51LBCHx6eUakjaSrRpUqhPwjh/uvNUYvLmz2LgPTTPwCqaKt0iwL+OGVL0tXA5aDbAbg==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.51.tgz", + "integrity": "sha512-vS54wQjy4IinLSlb5EIlLoln8buh1yDgliP4CuEHumrPk4PvvP4kTRIG4SzMXm6t19N0rIfT4bNdAxzJLg2k6A==", "cpu": [ "mips64el" ], @@ -556,9 +680,9 @@ } }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.42.tgz", - "integrity": "sha512-8ohIVIWDbDT+i7lCx44YCyIRrOW1MYlks9fxTo0ME2LS/fxxdoJBwHWzaDYhjvf8kNpA+MInZvyOEAGoVDrMHg==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.51.tgz", + "integrity": "sha512-xcdd62Y3VfGoyphNP/aIV9LP+RzFw5M5Z7ja+zdpQHHvokJM7d0rlDRMN+iSSwvUymQkqZO+G/xjb4/75du8BQ==", "cpu": [ "ppc64" ], @@ -572,9 +696,9 @@ } }, "node_modules/esbuild-linux-riscv64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.42.tgz", - "integrity": "sha512-DzDqK3TuoXktPyG1Lwx7vhaF49Onv3eR61KwQyxYo4y5UKTpL3NmuarHSIaSVlTFDDpcIajCDwz5/uwKLLgKiQ==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.51.tgz", + "integrity": "sha512-syXHGak9wkAnFz0gMmRBoy44JV0rp4kVCEA36P5MCeZcxFq8+fllBC2t6sKI23w3qd8Vwo9pTADCgjTSf3L3rA==", "cpu": [ "riscv64" ], @@ -588,9 +712,9 @@ } }, "node_modules/esbuild-linux-s390x": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.42.tgz", - "integrity": "sha512-YFRhPCxl8nb//Wn6SiS5pmtplBi4z9yC2gLrYoYI/tvwuB1jldir9r7JwAGy1Ck4D7sE7wBN9GFtUUX/DLdcEQ==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.51.tgz", + "integrity": "sha512-kFAJY3dv+Wq8o28K/C7xkZk/X34rgTwhknSsElIqoEo8armCOjMJ6NsMxm48KaWY2h2RUYGtQmr+RGuUPKBhyw==", "cpu": [ "s390x" ], @@ -604,9 +728,9 @@ } }, "node_modules/esbuild-netbsd-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.42.tgz", - "integrity": "sha512-QYSD2k+oT9dqB/4eEM9c+7KyNYsIPgzYOSrmfNGDIyJrbT1d+CFVKvnKahDKNJLfOYj8N4MgyFaU9/Ytc6w5Vw==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.51.tgz", + "integrity": "sha512-ZZBI7qrR1FevdPBVHz/1GSk1x5GDL/iy42Zy8+neEm/HA7ma+hH/bwPEjeHXKWUDvM36CZpSL/fn1/y9/Hb+1A==", "cpu": [ "x64" ], @@ -620,9 +744,9 @@ } }, "node_modules/esbuild-openbsd-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.42.tgz", - "integrity": "sha512-M2meNVIKWsm2HMY7+TU9AxM7ZVwI9havdsw6m/6EzdXysyCFFSoaTQ/Jg03izjCsK17FsVRHqRe26Llj6x0MNA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.51.tgz", + "integrity": "sha512-7R1/p39M+LSVQVgDVlcY1KKm6kFKjERSX1lipMG51NPcspJD1tmiZSmmBXoY5jhHIu6JL1QkFDTx94gMYK6vfA==", "cpu": [ "x64" ], @@ -636,9 +760,9 @@ } }, "node_modules/esbuild-sunos-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.42.tgz", - "integrity": "sha512-uXV8TAZEw36DkgW8Ak3MpSJs1ofBb3Smkc/6pZ29sCAN1KzCAQzsje4sUwugf+FVicrHvlamCOlFZIXgct+iqQ==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.51.tgz", + "integrity": "sha512-HoHaCswHxLEYN8eBTtyO0bFEWvA3Kdb++hSQ/lLG7TyKF69TeSG0RNoBRAs45x/oCeWaTDntEZlYwAfQlhEtJA==", "cpu": [ "x64" ], @@ -652,9 +776,9 @@ } }, "node_modules/esbuild-windows-32": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.42.tgz", - "integrity": "sha512-4iw/8qWmRICWi9ZOnJJf9sYt6wmtp3hsN4TdI5NqgjfOkBVMxNdM9Vt3626G1Rda9ya2Q0hjQRD9W1o+m6Lz6g==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.51.tgz", + "integrity": "sha512-4rtwSAM35A07CBt1/X8RWieDj3ZUHQqUOaEo5ZBs69rt5WAFjP4aqCIobdqOy4FdhYw1yF8Z0xFBTyc9lgPtEg==", "cpu": [ "ia32" ], @@ -668,9 +792,9 @@ } }, "node_modules/esbuild-windows-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.42.tgz", - "integrity": "sha512-j3cdK+Y3+a5H0wHKmLGTJcq0+/2mMBHPWkItR3vytp/aUGD/ua/t2BLdfBIzbNN9nLCRL9sywCRpOpFMx3CxzA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.51.tgz", + "integrity": "sha512-HoN/5HGRXJpWODprGCgKbdMvrC3A2gqvzewu2eECRw2sYxOUoh2TV1tS+G7bHNapPGI79woQJGV6pFH7GH7qnA==", "cpu": [ "x64" ], @@ -684,9 +808,9 @@ } }, "node_modules/esbuild-windows-arm64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.42.tgz", - "integrity": "sha512-+lRAARnF+hf8J0mN27ujO+VbhPbDqJ8rCcJKye4y7YZLV6C4n3pTRThAb388k/zqF5uM0lS5O201u0OqoWSicw==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.51.tgz", + "integrity": "sha512-JQDqPjuOH7o+BsKMSddMfmVJXrnYZxXDHsoLHc0xgmAZkOOCflRmC43q31pk79F9xuyWY45jDBPolb5ZgGOf9g==", "cpu": [ "arm64" ], @@ -1524,9 +1648,9 @@ } }, "node_modules/sass": { - "version": "1.52.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.1.tgz", - "integrity": "sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.0.tgz", + "integrity": "sha512-C4zp79GCXZfK0yoHZg+GxF818/aclhp9F48XBu/+bm9vXEVAYov9iU3FBVRMq3Hx3OA4jfKL+p2K9180mEh0xQ==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -1602,9 +1726,9 @@ } }, "node_modules/snabbdom": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.0.tgz", - "integrity": "sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.1.tgz", + "integrity": "sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA==", "engines": { "node": ">=8.3.0" } @@ -1733,6 +1857,11 @@ "node": ">=4" } }, + "node_modules/style-mod": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", + "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1792,6 +1921,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/w3c-keyname": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.5.tgz", + "integrity": "sha512-WJrK7i6w+ULuZsGscCezbCH4Aev5U3xY87vnSimzzEgPQhb0Sa0a1rE3c2jtEwrFtSfi61Jefw3jI5/DD/3jbQ==" + }, "node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -1897,6 +2031,105 @@ } }, "dependencies": { + "@codemirror/autocomplete": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.1.0.tgz", + "integrity": "sha512-wtO4O5WDyXhhCd4q4utDIDZxnQfmJ++3dGBCG9LMtI79+92OcA1DVk/n7BEupKmjIr8AzvptDz7YQ9ud6OkU+A==", + "requires": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "@codemirror/commands": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.0.1.tgz", + "integrity": "sha512-iNHDByicYqQjs0Wo1MKGfqNbMYMyhS9WV6EwMVwsHXImlFemgEUC+c5X22bXKBStN3qnwg4fArNZM+gkv22baQ==", + "requires": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0" + } + }, + "@codemirror/language": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz", + "integrity": "sha512-MC3svxuvIj0MRpFlGHxLS6vPyIdbTr2KKPEW46kCoCXw2ktb4NTkpkPBI/lSP/FoNXLCBJ0mrnUi1OoZxtpW1Q==", + "requires": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0", + "style-mod": "^4.0.0" + } + }, + "@codemirror/legacy-modes": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/legacy-modes/-/legacy-modes-6.1.0.tgz", + "integrity": "sha512-V/PgGpndkZeTn3Hdlg/gd8MLFdyvTCIX+iwJzjUw5iNziWiNsAY8X0jvf7m3gSfxnKkNzmid6l0g4rYSpiDaCw==", + "requires": { + "@codemirror/language": "^6.0.0" + } + }, + "@codemirror/lint": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.0.0.tgz", + "integrity": "sha512-nUUXcJW1Xp54kNs+a1ToPLK8MadO0rMTnJB8Zk4Z8gBdrN0kqV7uvUraU/T2yqg+grDNR38Vmy/MrhQN/RgwiA==", + "requires": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "@codemirror/search": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.0.1.tgz", + "integrity": "sha512-uOinkOrM+daMduCgMPomDfKLr7drGHB4jHl3Vq6xY2WRlL7MkNsBE0b+XHYa/Mee2npsJOgwvkW4n1lMFeBW2Q==", + "requires": { + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "crelt": "^1.0.5" + } + }, + "@codemirror/state": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.1.0.tgz", + "integrity": "sha512-qbUr94DZTe6/V1VS7LDLz11rM/1t/nJxR1El4I6UaxDEdc0aZZvq6JCLJWiRmUf95NRAnDH6fhXn+PWp9wGCIg==" + }, + "@codemirror/view": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.1.2.tgz", + "integrity": "sha512-puUydfKwfmOo+ixtuB+uN/ZpcteEYSnpjHmMaow1sOQhNICsKtGBup3i9ybVqyzDagARRYzSHTWjbdeHqmn31w==", + "requires": { + "@codemirror/state": "^6.0.0", + "style-mod": "^4.0.0", + "w3c-keyname": "^2.2.4" + } + }, + "@lezer/common": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz", + "integrity": "sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA==" + }, + "@lezer/highlight": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.0.0.tgz", + "integrity": "sha512-nsCnNtim90UKsB5YxoX65v3GEIw3iCHw9RM2DtdgkiqAbKh9pCdvi8AWNwkYf10Lu6fxNhXPpkpHbW6mihhvJA==", + "requires": { + "@lezer/common": "^1.0.0" + } + }, + "@lezer/lr": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.0.tgz", + "integrity": "sha512-TgEpfm9br2SX8JwtwKT8HsQZKuFkLRg6g+IRxObk9nVKQLKnkP3oMh+QGcTBL9GQsfQ2ADtKPbj2iGSMf3ytiA==", + "requires": { + "@lezer/common": "^1.0.0" + } + }, "ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -2035,9 +2268,18 @@ } }, "codemirror": { - "version": "5.65.5", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.5.tgz", - "integrity": "sha512-HNyhvGLnYz5c+kIsB9QKVitiZUevha3ovbIYaQiGzKo7ECSL/elWD9RXt3JgNr0NdnyqE9/Rc/7uLfkJQL638w==" + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz", + "integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/commands": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/search": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0" + } }, "color-convert": { "version": "1.9.3", @@ -2060,6 +2302,11 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, + "crelt": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.5.tgz", + "integrity": "sha512-+BO9wPPi+DWTDcNYhr/W90myha8ptzftZT+LwcmUbbok0rcP/fequmFYCw8NMoH7pkAZQzU78b3kYrlua5a9eA==" + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -2158,170 +2405,170 @@ } }, "esbuild": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.42.tgz", - "integrity": "sha512-V0uPZotCEHokJdNqyozH6qsaQXqmZEOiZWrXnds/zaH/0SyrIayRXWRB98CENO73MIZ9T3HBIOsmds5twWtmgw==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.51.tgz", + "integrity": "sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==", "dev": true, "requires": { - "esbuild-android-64": "0.14.42", - "esbuild-android-arm64": "0.14.42", - "esbuild-darwin-64": "0.14.42", - "esbuild-darwin-arm64": "0.14.42", - "esbuild-freebsd-64": "0.14.42", - "esbuild-freebsd-arm64": "0.14.42", - "esbuild-linux-32": "0.14.42", - "esbuild-linux-64": "0.14.42", - "esbuild-linux-arm": "0.14.42", - "esbuild-linux-arm64": "0.14.42", - "esbuild-linux-mips64le": "0.14.42", - "esbuild-linux-ppc64le": "0.14.42", - "esbuild-linux-riscv64": "0.14.42", - "esbuild-linux-s390x": "0.14.42", - "esbuild-netbsd-64": "0.14.42", - "esbuild-openbsd-64": "0.14.42", - "esbuild-sunos-64": "0.14.42", - "esbuild-windows-32": "0.14.42", - "esbuild-windows-64": "0.14.42", - "esbuild-windows-arm64": "0.14.42" + "esbuild-android-64": "0.14.51", + "esbuild-android-arm64": "0.14.51", + "esbuild-darwin-64": "0.14.51", + "esbuild-darwin-arm64": "0.14.51", + "esbuild-freebsd-64": "0.14.51", + "esbuild-freebsd-arm64": "0.14.51", + "esbuild-linux-32": "0.14.51", + "esbuild-linux-64": "0.14.51", + "esbuild-linux-arm": "0.14.51", + "esbuild-linux-arm64": "0.14.51", + "esbuild-linux-mips64le": "0.14.51", + "esbuild-linux-ppc64le": "0.14.51", + "esbuild-linux-riscv64": "0.14.51", + "esbuild-linux-s390x": "0.14.51", + "esbuild-netbsd-64": "0.14.51", + "esbuild-openbsd-64": "0.14.51", + "esbuild-sunos-64": "0.14.51", + "esbuild-windows-32": "0.14.51", + "esbuild-windows-64": "0.14.51", + "esbuild-windows-arm64": "0.14.51" } }, "esbuild-android-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.42.tgz", - "integrity": "sha512-P4Y36VUtRhK/zivqGVMqhptSrFILAGlYp0Z8r9UQqHJ3iWztRCNWnlBzD9HRx0DbueXikzOiwyOri+ojAFfW6A==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.51.tgz", + "integrity": "sha512-6FOuKTHnC86dtrKDmdSj2CkcKF8PnqkaIXqvgydqfJmqBazCPdw+relrMlhGjkvVdiiGV70rpdnyFmA65ekBCQ==", "dev": true, "optional": true }, "esbuild-android-arm64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.42.tgz", - "integrity": "sha512-0cOqCubq+RWScPqvtQdjXG3Czb3AWI2CaKw3HeXry2eoA2rrPr85HF7IpdU26UWdBXgPYtlTN1LUiuXbboROhg==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.51.tgz", + "integrity": "sha512-vBtp//5VVkZWmYYvHsqBRCMMi1MzKuMIn5XDScmnykMTu9+TD9v0NMEDqQxvtFToeYmojdo5UCV2vzMQWJcJ4A==", "dev": true, "optional": true }, "esbuild-darwin-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.42.tgz", - "integrity": "sha512-ipiBdCA3ZjYgRfRLdQwP82rTiv/YVMtW36hTvAN5ZKAIfxBOyPXY7Cejp3bMXWgzKD8B6O+zoMzh01GZsCuEIA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.51.tgz", + "integrity": "sha512-YFmXPIOvuagDcwCejMRtCDjgPfnDu+bNeh5FU2Ryi68ADDVlWEpbtpAbrtf/lvFTWPexbgyKgzppNgsmLPr8PA==", "dev": true, "optional": true }, "esbuild-darwin-arm64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.42.tgz", - "integrity": "sha512-bU2tHRqTPOaoH/4m0zYHbFWpiYDmaA0gt90/3BMEFaM0PqVK/a6MA2V/ypV5PO0v8QxN6gH5hBPY4YJ2lopXgA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.51.tgz", + "integrity": "sha512-juYD0QnSKwAMfzwKdIF6YbueXzS6N7y4GXPDeDkApz/1RzlT42mvX9jgNmyOlWKN7YzQAYbcUEJmZJYQGdf2ow==", "dev": true, "optional": true }, "esbuild-freebsd-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.42.tgz", - "integrity": "sha512-75h1+22Ivy07+QvxHyhVqOdekupiTZVLN1PMwCDonAqyXd8TVNJfIRFrdL8QmSJrOJJ5h8H1I9ETyl2L8LQDaw==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.51.tgz", + "integrity": "sha512-cLEI/aXjb6vo5O2Y8rvVSQ7smgLldwYY5xMxqh/dQGfWO+R1NJOFsiax3IS4Ng300SVp7Gz3czxT6d6qf2cw0g==", "dev": true, "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.42.tgz", - "integrity": "sha512-W6Jebeu5TTDQMJUJVarEzRU9LlKpNkPBbjqSu+GUPTHDCly5zZEQq9uHkmHHl7OKm+mQ2zFySN83nmfCeZCyNA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.51.tgz", + "integrity": "sha512-TcWVw/rCL2F+jUgRkgLa3qltd5gzKjIMGhkVybkjk6PJadYInPtgtUBp1/hG+mxyigaT7ib+od1Xb84b+L+1Mg==", "dev": true, "optional": true }, "esbuild-linux-32": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.42.tgz", - "integrity": "sha512-Ooy/Bj+mJ1z4jlWcK5Dl6SlPlCgQB9zg1UrTCeY8XagvuWZ4qGPyYEWGkT94HUsRi2hKsXvcs6ThTOjBaJSMfg==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.51.tgz", + "integrity": "sha512-RFqpyC5ChyWrjx8Xj2K0EC1aN0A37H6OJfmUXIASEqJoHcntuV3j2Efr9RNmUhMfNE6yEj2VpYuDteZLGDMr0w==", "dev": true, "optional": true }, "esbuild-linux-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.42.tgz", - "integrity": "sha512-2L0HbzQfbTuemUWfVqNIjOfaTRt9zsvjnme6lnr7/MO9toz/MJ5tZhjqrG6uDWDxhsaHI2/nsDgrv8uEEN2eoA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.51.tgz", + "integrity": "sha512-dxjhrqo5i7Rq6DXwz5v+MEHVs9VNFItJmHBe1CxROWNf4miOGoQhqSG8StStbDkQ1Mtobg6ng+4fwByOhoQoeA==", "dev": true, "optional": true }, "esbuild-linux-arm": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.42.tgz", - "integrity": "sha512-STq69yzCMhdRaWnh29UYrLSr/qaWMm/KqwaRF1pMEK7kDiagaXhSL1zQGXbYv94GuGY/zAwzK98+6idCMUOOCg==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.51.tgz", + "integrity": "sha512-LsJynDxYF6Neg7ZC7748yweCDD+N8ByCv22/7IAZglIEniEkqdF4HCaa49JNDLw1UQGlYuhOB8ZT/MmcSWzcWg==", "dev": true, "optional": true }, "esbuild-linux-arm64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.42.tgz", - "integrity": "sha512-c3Ug3e9JpVr8jAcfbhirtpBauLxzYPpycjWulD71CF6ZSY26tvzmXMJYooQ2YKqDY4e/fPu5K8bm7MiXMnyxuA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.51.tgz", + "integrity": "sha512-D9rFxGutoqQX3xJPxqd6o+kvYKeIbM0ifW2y0bgKk5HPgQQOo2k9/2Vpto3ybGYaFPCE5qTGtqQta9PoP6ZEzw==", "dev": true, "optional": true }, "esbuild-linux-mips64le": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.42.tgz", - "integrity": "sha512-QuvpHGbYlkyXWf2cGm51LBCHx6eUakjaSrRpUqhPwjh/uvNUYvLmz2LgPTTPwCqaKt0iwL+OGVL0tXA5aDbAbg==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.51.tgz", + "integrity": "sha512-vS54wQjy4IinLSlb5EIlLoln8buh1yDgliP4CuEHumrPk4PvvP4kTRIG4SzMXm6t19N0rIfT4bNdAxzJLg2k6A==", "dev": true, "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.42.tgz", - "integrity": "sha512-8ohIVIWDbDT+i7lCx44YCyIRrOW1MYlks9fxTo0ME2LS/fxxdoJBwHWzaDYhjvf8kNpA+MInZvyOEAGoVDrMHg==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.51.tgz", + "integrity": "sha512-xcdd62Y3VfGoyphNP/aIV9LP+RzFw5M5Z7ja+zdpQHHvokJM7d0rlDRMN+iSSwvUymQkqZO+G/xjb4/75du8BQ==", "dev": true, "optional": true }, "esbuild-linux-riscv64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.42.tgz", - "integrity": "sha512-DzDqK3TuoXktPyG1Lwx7vhaF49Onv3eR61KwQyxYo4y5UKTpL3NmuarHSIaSVlTFDDpcIajCDwz5/uwKLLgKiQ==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.51.tgz", + "integrity": "sha512-syXHGak9wkAnFz0gMmRBoy44JV0rp4kVCEA36P5MCeZcxFq8+fllBC2t6sKI23w3qd8Vwo9pTADCgjTSf3L3rA==", "dev": true, "optional": true }, "esbuild-linux-s390x": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.42.tgz", - "integrity": "sha512-YFRhPCxl8nb//Wn6SiS5pmtplBi4z9yC2gLrYoYI/tvwuB1jldir9r7JwAGy1Ck4D7sE7wBN9GFtUUX/DLdcEQ==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.51.tgz", + "integrity": "sha512-kFAJY3dv+Wq8o28K/C7xkZk/X34rgTwhknSsElIqoEo8armCOjMJ6NsMxm48KaWY2h2RUYGtQmr+RGuUPKBhyw==", "dev": true, "optional": true }, "esbuild-netbsd-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.42.tgz", - "integrity": "sha512-QYSD2k+oT9dqB/4eEM9c+7KyNYsIPgzYOSrmfNGDIyJrbT1d+CFVKvnKahDKNJLfOYj8N4MgyFaU9/Ytc6w5Vw==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.51.tgz", + "integrity": "sha512-ZZBI7qrR1FevdPBVHz/1GSk1x5GDL/iy42Zy8+neEm/HA7ma+hH/bwPEjeHXKWUDvM36CZpSL/fn1/y9/Hb+1A==", "dev": true, "optional": true }, "esbuild-openbsd-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.42.tgz", - "integrity": "sha512-M2meNVIKWsm2HMY7+TU9AxM7ZVwI9havdsw6m/6EzdXysyCFFSoaTQ/Jg03izjCsK17FsVRHqRe26Llj6x0MNA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.51.tgz", + "integrity": "sha512-7R1/p39M+LSVQVgDVlcY1KKm6kFKjERSX1lipMG51NPcspJD1tmiZSmmBXoY5jhHIu6JL1QkFDTx94gMYK6vfA==", "dev": true, "optional": true }, "esbuild-sunos-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.42.tgz", - "integrity": "sha512-uXV8TAZEw36DkgW8Ak3MpSJs1ofBb3Smkc/6pZ29sCAN1KzCAQzsje4sUwugf+FVicrHvlamCOlFZIXgct+iqQ==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.51.tgz", + "integrity": "sha512-HoHaCswHxLEYN8eBTtyO0bFEWvA3Kdb++hSQ/lLG7TyKF69TeSG0RNoBRAs45x/oCeWaTDntEZlYwAfQlhEtJA==", "dev": true, "optional": true }, "esbuild-windows-32": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.42.tgz", - "integrity": "sha512-4iw/8qWmRICWi9ZOnJJf9sYt6wmtp3hsN4TdI5NqgjfOkBVMxNdM9Vt3626G1Rda9ya2Q0hjQRD9W1o+m6Lz6g==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.51.tgz", + "integrity": "sha512-4rtwSAM35A07CBt1/X8RWieDj3ZUHQqUOaEo5ZBs69rt5WAFjP4aqCIobdqOy4FdhYw1yF8Z0xFBTyc9lgPtEg==", "dev": true, "optional": true }, "esbuild-windows-64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.42.tgz", - "integrity": "sha512-j3cdK+Y3+a5H0wHKmLGTJcq0+/2mMBHPWkItR3vytp/aUGD/ua/t2BLdfBIzbNN9nLCRL9sywCRpOpFMx3CxzA==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.51.tgz", + "integrity": "sha512-HoN/5HGRXJpWODprGCgKbdMvrC3A2gqvzewu2eECRw2sYxOUoh2TV1tS+G7bHNapPGI79woQJGV6pFH7GH7qnA==", "dev": true, "optional": true }, "esbuild-windows-arm64": { - "version": "0.14.42", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.42.tgz", - "integrity": "sha512-+lRAARnF+hf8J0mN27ujO+VbhPbDqJ8rCcJKye4y7YZLV6C4n3pTRThAb388k/zqF5uM0lS5O201u0OqoWSicw==", + "version": "0.14.51", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.51.tgz", + "integrity": "sha512-JQDqPjuOH7o+BsKMSddMfmVJXrnYZxXDHsoLHc0xgmAZkOOCflRmC43q31pk79F9xuyWY45jDBPolb5ZgGOf9g==", "dev": true, "optional": true }, @@ -2922,9 +3169,9 @@ } }, "sass": { - "version": "1.52.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.52.1.tgz", - "integrity": "sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q==", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.0.tgz", + "integrity": "sha512-C4zp79GCXZfK0yoHZg+GxF818/aclhp9F48XBu/+bm9vXEVAYov9iU3FBVRMq3Hx3OA4jfKL+p2K9180mEh0xQ==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -2982,9 +3229,9 @@ } }, "snabbdom": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.0.tgz", - "integrity": "sha512-Ff5BKG18KrrPuskHJlA9aujPHqEabItaDl96l7ZZndF4zt5AYSczz7ZjjgQAX5IBd5cd25lw9NfgX21yVUJ+9g==" + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/snabbdom/-/snabbdom-3.5.1.tgz", + "integrity": "sha512-wHMNIOjkm/YNE5EM3RCbr/+DVgPg6AqQAX1eOxO46zYNvCXjKP5Y865tqQj3EXnaMBjkxmQA5jFuDpDK/dbfiA==" }, "sortablejs": { "version": "1.15.0", @@ -3086,6 +3333,11 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, + "style-mod": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.0.0.tgz", + "integrity": "sha512-OPhtyEjyyN9x3nhPsu76f52yUGXiZcgvsrFVtvTkyGRQJ0XK+GPc6ov1z+lRpbeabka+MYEQxOYRnt5nF30aMw==" + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -3136,6 +3388,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "w3c-keyname": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.5.tgz", + "integrity": "sha512-WJrK7i6w+ULuZsGscCezbCH4Aev5U3xY87vnSimzzEgPQhb0Sa0a1rE3c2jtEwrFtSfi61Jefw3jI5/DD/3jbQ==" + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index 9a2f66448..8407ffc77 100644 --- a/package.json +++ b/package.json @@ -16,19 +16,24 @@ }, "devDependencies": { "chokidar-cli": "^3.0", - "esbuild": "0.14.42", + "esbuild": "0.14.51", "livereload": "^0.9.3", "npm-run-all": "^4.1.5", "punycode": "^2.1.1", - "sass": "^1.52.1" + "sass": "^1.54.0" }, "dependencies": { + "@codemirror/commands": "^6.0.1", + "@codemirror/language": "^6.2.1", + "@codemirror/legacy-modes": "^6.1.0", + "@codemirror/state": "^6.1.0", + "@codemirror/view": "^6.1.2", "clipboard": "^2.0.11", - "codemirror": "^5.65.5", + "codemirror": "^6.0.1", "dropzone": "^5.9.3", "markdown-it": "^13.0.1", "markdown-it-task-lists": "^2.1.1", - "snabbdom": "^3.5.0", + "snabbdom": "^3.5.1", "sortablejs": "^1.15.0" } } diff --git a/resources/js/code.mjs b/resources/js/code/index.mjs similarity index 55% rename from resources/js/code.mjs rename to resources/js/code/index.mjs index eca941f1c..ff60cbff5 100644 --- a/resources/js/code.mjs +++ b/resources/js/code/index.mjs @@ -1,106 +1,10 @@ -import CodeMirror from "codemirror"; +import {EditorView} from "@codemirror/view" +// import {EditorState} from "@codemirror/state" import Clipboard from "clipboard/dist/clipboard.min"; // Modes -import 'codemirror/mode/css/css'; -import 'codemirror/mode/clike/clike'; -import 'codemirror/mode/diff/diff'; -import 'codemirror/mode/fortran/fortran'; -import 'codemirror/mode/go/go'; -import 'codemirror/mode/haskell/haskell'; -import 'codemirror/mode/htmlmixed/htmlmixed'; -import 'codemirror/mode/javascript/javascript'; -import 'codemirror/mode/julia/julia'; -import 'codemirror/mode/lua/lua'; -import 'codemirror/mode/markdown/markdown'; -import 'codemirror/mode/mllike/mllike'; -import 'codemirror/mode/nginx/nginx'; -import 'codemirror/mode/perl/perl'; -import 'codemirror/mode/pascal/pascal'; -import 'codemirror/mode/php/php'; -import 'codemirror/mode/powershell/powershell'; -import 'codemirror/mode/properties/properties'; -import 'codemirror/mode/python/python'; -import 'codemirror/mode/ruby/ruby'; -import 'codemirror/mode/rust/rust'; -import 'codemirror/mode/shell/shell'; -import 'codemirror/mode/sql/sql'; -import 'codemirror/mode/stex/stex'; -import 'codemirror/mode/toml/toml'; -import 'codemirror/mode/vb/vb'; -import 'codemirror/mode/vbscript/vbscript'; -import 'codemirror/mode/xml/xml'; -import 'codemirror/mode/yaml/yaml'; - -// Addons -import 'codemirror/addon/scroll/scrollpastend'; - -// Mapping of possible languages or formats from user input to their codemirror modes. -// Value can be a mode string or a function that will receive the code content & return the mode string. -// The function option is used in the event the exact mode could be dynamic depending on the code. -const modeMap = { - bash: 'shell', - css: 'css', - c: 'text/x-csrc', - java: 'text/x-java', - scala: 'text/x-scala', - kotlin: 'text/x-kotlin', - 'c++': 'text/x-c++src', - 'c#': 'text/x-csharp', - csharp: 'text/x-csharp', - diff: 'diff', - for: 'fortran', - fortran: 'fortran', - 'f#': 'text/x-fsharp', - fsharp: 'text/x-fsharp', - go: 'go', - haskell: 'haskell', - hs: 'haskell', - html: 'htmlmixed', - ini: 'properties', - javascript: 'text/javascript', - json: 'application/json', - js: 'text/javascript', - jl: 'text/x-julia', - julia: 'text/x-julia', - latex: 'text/x-stex', - lua: 'lua', - md: 'markdown', - mdown: 'markdown', - markdown: 'markdown', - ml: 'mllike', - nginx: 'nginx', - perl: 'perl', - pl: 'perl', - powershell: 'powershell', - properties: 'properties', - ocaml: 'text/x-ocaml', - pascal: 'text/x-pascal', - pas: 'text/x-pascal', - php: (content) => { - return content.includes('`; - const copyButton = document.createElement('div'); - copyButton.classList.add('CodeMirror-copy'); - copyButton.innerHTML = copyIcon; - cmInstance.display.wrapper.appendChild(copyButton); - - const clipboard = new Clipboard(copyButton, { - text: function(trigger) { - return cmInstance.getValue() - } - }); - - clipboard.on('success', event => { - copyButton.classList.add('success'); - setTimeout(() => { - copyButton.classList.remove('success'); - }, 240); - }); + // TODO + // const copyIcon = ``; + // const copyButton = document.createElement('div'); + // copyButton.classList.add('CodeMirror-copy'); + // copyButton.innerHTML = copyIcon; + // cmInstance.display.wrapper.appendChild(copyButton); + // + // const clipboard = new Clipboard(copyButton, { + // text: function(trigger) { + // return cmInstance.getValue() + // } + // }); + // + // clipboard.on('success', event => { + // copyButton.classList.add('success'); + // setTimeout(() => { + // copyButton.classList.remove('success'); + // }, 240); + // }); } /** diff --git a/resources/js/code/modes.js b/resources/js/code/modes.js new file mode 100644 index 000000000..5a89255a5 --- /dev/null +++ b/resources/js/code/modes.js @@ -0,0 +1,134 @@ +import {StreamLanguage} from "@codemirror/language" + +import {css as langCss} from '@codemirror/legacy-modes/mode/css'; +import {clike as langClike} from '@codemirror/legacy-modes/mode/clike'; +import {diff as langDiff} from '@codemirror/legacy-modes/mode/diff'; +import {fortran as langFortran} from '@codemirror/legacy-modes/mode/fortran'; +import {go as langGo} from '@codemirror/legacy-modes/mode/go'; +import {haskell as langHaskell} from '@codemirror/legacy-modes/mode/haskell'; +// import {htmlmixed as langHtmlmixed} from '@codemirror/legacy-modes/mode/htmlmixed'; +import {javascript as langJavascript} from '@codemirror/legacy-modes/mode/javascript'; +import {julia as langJulia} from '@codemirror/legacy-modes/mode/julia'; +import {lua as langLua} from '@codemirror/legacy-modes/mode/lua'; +// import {markdown as langMarkdown} from '@codemirror/legacy-modes/mode/markdown'; +import {oCaml as langMllike} from '@codemirror/legacy-modes/mode/mllike'; +import {nginx as langNginx} from '@codemirror/legacy-modes/mode/nginx'; +import {perl as langPerl} from '@codemirror/legacy-modes/mode/perl'; +import {pascal as langPascal} from '@codemirror/legacy-modes/mode/pascal'; +// import {php as langPhp} from '@codemirror/legacy-modes/mode/php'; +import {powerShell as langPowershell} from '@codemirror/legacy-modes/mode/powershell'; +import {properties as langProperties} from '@codemirror/legacy-modes/mode/properties'; +import {python as langPython} from '@codemirror/legacy-modes/mode/python'; +import {ruby as langRuby} from '@codemirror/legacy-modes/mode/ruby'; +import {rust as langRust} from '@codemirror/legacy-modes/mode/rust'; +import {shell as langShell} from '@codemirror/legacy-modes/mode/shell'; +import {sql as langSql} from '@codemirror/legacy-modes/mode/sql'; +import {stex as langStex} from '@codemirror/legacy-modes/mode/stex'; +import {toml as langToml} from '@codemirror/legacy-modes/mode/toml'; +import {vb as langVb} from '@codemirror/legacy-modes/mode/vb'; +import {vbScript as langVbscript} from '@codemirror/legacy-modes/mode/vbscript'; +import {xml as langXml} from '@codemirror/legacy-modes/mode/xml'; +import {yaml as langYaml} from '@codemirror/legacy-modes/mode/yaml'; + +export const modes = [ + langCss, + langClike, + langDiff, + langFortran, + langGo, + langHaskell, + // langHtmlmixed, + langJavascript, + langJulia, + langLua, + // langMarkdown, + langMllike, + langNginx, + langPerl, + langPascal, + // langPhp, + langPowershell, + langProperties, + langPython, + langRuby, + langRust, + langShell, + langSql, + langStex, + langToml, + langVb, + langVbscript, + langXml, + langYaml, +]; + +// Mapping of possible languages or formats from user input to their codemirror modes. +// Value can be a mode string or a function that will receive the code content & return the mode string. +// The function option is used in the event the exact mode could be dynamic depending on the code. +export const modeMap = { + bash: 'shell', + css: 'css', + c: 'text/x-csrc', + java: 'text/x-java', + scala: 'text/x-scala', + kotlin: 'text/x-kotlin', + 'c++': 'text/x-c++src', + 'c#': 'text/x-csharp', + csharp: 'text/x-csharp', + diff: 'diff', + for: 'fortran', + fortran: 'fortran', + 'f#': 'text/x-fsharp', + fsharp: 'text/x-fsharp', + go: 'go', + haskell: 'haskell', + hs: 'haskell', + html: 'htmlmixed', + ini: 'properties', + javascript: 'text/javascript', + json: 'application/json', + js: 'text/javascript', + jl: 'text/x-julia', + julia: 'text/x-julia', + latex: 'text/x-stex', + lua: 'lua', + md: 'markdown', + mdown: 'markdown', + markdown: 'markdown', + ml: 'mllike', + nginx: 'nginx', + perl: 'perl', + pl: 'perl', + powershell: 'powershell', + properties: 'properties', + ocaml: 'text/x-ocaml', + pascal: 'text/x-pascal', + pas: 'text/x-pascal', + php: (content) => { + return content.includes(' StreamLanguage.define(mode)); +} \ No newline at end of file diff --git a/resources/js/code/setups.js b/resources/js/code/setups.js new file mode 100644 index 000000000..768d3a35d --- /dev/null +++ b/resources/js/code/setups.js @@ -0,0 +1,32 @@ + +import {keymap, highlightSpecialChars, drawSelection, highlightActiveLine, dropCursor, + rectangularSelection, lineNumbers, highlightActiveLineGutter} from "@codemirror/view" +import {defaultHighlightStyle, syntaxHighlighting, bracketMatching, + foldKeymap} from "@codemirror/language" +import {defaultKeymap, history, historyKeymap} from "@codemirror/commands" +import {EditorState} from "@codemirror/state" + +import {modesAsStreamLanguages} from "./modes"; + + +export function viewer() { + return [ + lineNumbers(), + highlightActiveLineGutter(), + highlightSpecialChars(), + history(), + drawSelection(), + dropCursor(), + syntaxHighlighting(defaultHighlightStyle, {fallback: true}), + bracketMatching(), + rectangularSelection(), + highlightActiveLine(), + keymap.of([ + ...defaultKeymap, + ...historyKeymap, + ...foldKeymap, + ]), + EditorState.readOnly.of(true), + ...modesAsStreamLanguages(), + ]; +} \ No newline at end of file From 97146a63590fa193a4958c09202b40340e840a1f Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Wed, 3 Aug 2022 19:40:16 +0100 Subject: [PATCH 02/22] Added handling of codemirror 6 code languages --- package-lock.json | 261 +++++++++++++++++++++++++++++++++ package.json | 5 + resources/js/code/index.mjs | 49 ++----- resources/js/code/languages.js | 120 +++++++++++++++ resources/js/code/modes.js | 134 ----------------- resources/js/code/setups.js | 4 - resources/js/code/views.js | 38 +++++ 7 files changed, 437 insertions(+), 174 deletions(-) create mode 100644 resources/js/code/languages.js delete mode 100644 resources/js/code/modes.js create mode 100644 resources/js/code/views.js diff --git a/package-lock.json b/package-lock.json index c141e654a..0eca777cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,11 @@ "": { "dependencies": { "@codemirror/commands": "^6.0.1", + "@codemirror/lang-html": "^6.1.0", + "@codemirror/lang-javascript": "^6.0.2", + "@codemirror/lang-json": "^6.0.0", + "@codemirror/lang-markdown": "^6.0.1", + "@codemirror/lang-php": "^6.0.0", "@codemirror/language": "^6.2.1", "@codemirror/legacy-modes": "^6.1.0", "@codemirror/state": "^6.1.0", @@ -55,6 +60,79 @@ "@lezer/common": "^1.0.0" } }, + "node_modules/@codemirror/lang-css": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.0.0.tgz", + "integrity": "sha512-jBqc+BTuwhNOTlrimFghLlSrN6iFuE44HULKWoR4qKYObhOIl9Lci1iYj6zMIte1XTQmZguNvjXMyr43LUKwSw==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/css": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-html": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.1.0.tgz", + "integrity": "sha512-gA7NmJxqvnhwza05CvR7W/39Ap9r/4Vs9uiC0IeFYo1hSlJzc/8N6Evviz6vTW1x8SpHcRYyqKOf6rpl6LfWtg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/html": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.0.2.tgz", + "integrity": "sha512-BZRJ9u/zl16hLkSpDAWm73mrfIR7HJrr0lvnhoSOCQVea5BglguWI/slxexhvUb0CB5cXgKWuo2bM+N9EhIaZw==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-json": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.0.tgz", + "integrity": "sha512-DvTcYTKLmg2viADXlTdufrT334M9jowe1qO02W28nvm+nejcvhM5vot5mE8/kPrxYw/HJHhwu1z2PyBpnMLCNQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/json": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-markdown": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.0.1.tgz", + "integrity": "sha512-pHPQuRwf9cUrmkmsTHRjtS9ZnGu3fA9YzAdh2++d+L9wbfnC2XbKh0Xvm/0YiUjdCnoCx9wDFEoCuAnkqKWLIw==", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/markdown": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-php": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.0.tgz", + "integrity": "sha512-96CEjq0xEgbzc6bdFPwILPfZ6m8917JRbh2oPszZJABlYxG4Y+eYjtYkUTDb4yuyjQKyigHoeGC6zoIOYA1NWA==", + "dependencies": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/php": "^1.0.0" + } + }, "node_modules/@codemirror/language": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz", @@ -116,6 +194,15 @@ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz", "integrity": "sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA==" }, + "node_modules/@lezer/css": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.0.0.tgz", + "integrity": "sha512-616VqgDKumHmYIuxs3tnX1irEQmoDHgF/TlP4O5ICWwyHwLMErq+8iKVuzTkOdBqvYAVmObqThcDEAaaMJjAdg==", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "node_modules/@lezer/highlight": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.0.0.tgz", @@ -124,6 +211,34 @@ "@lezer/common": "^1.0.0" } }, + "node_modules/@lezer/html": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.0.1.tgz", + "integrity": "sha512-sC00zEt3GBh3vVO6QaGX4YZCl41S9dHWN/WGBsDixy9G+sqOC7gsa4cxA/fmRVAiBvhqYkJk+5Ul4oul92CPVw==", + "dependencies": { + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/javascript": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.0.2.tgz", + "integrity": "sha512-IjOVeIRhM8IuafWNnk+UzRz7p4/JSOKBNINLYLsdSGuJS9Ju7vFdc82AlTt0jgtV5D8eBZf4g0vK4d3ttBNz7A==", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz", + "integrity": "sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "node_modules/@lezer/lr": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.0.tgz", @@ -132,6 +247,24 @@ "@lezer/common": "^1.0.0" } }, + "node_modules/@lezer/markdown": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.0.1.tgz", + "integrity": "sha512-LlpNWLqes3XQvd8TwpJTHf9ENl4fI6H32xQkMgltUITFMMdQpOASXQtDawWR03yS6hskh4bkhATQbgjdGMoUvA==", + "dependencies": { + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "node_modules/@lezer/php": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.0.tgz", + "integrity": "sha512-kFQu/mk/vmjpA+fjQU87d9eimqKJ9PFCa8CZCPFWGEwNnm7Ahpw32N+HYEU/YAQ0XcfmOAnW/YJCEa8WpUOMMw==", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "node_modules/ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -2053,6 +2186,79 @@ "@lezer/common": "^1.0.0" } }, + "@codemirror/lang-css": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.0.0.tgz", + "integrity": "sha512-jBqc+BTuwhNOTlrimFghLlSrN6iFuE44HULKWoR4qKYObhOIl9Lci1iYj6zMIte1XTQmZguNvjXMyr43LUKwSw==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/css": "^1.0.0" + } + }, + "@codemirror/lang-html": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-html/-/lang-html-6.1.0.tgz", + "integrity": "sha512-gA7NmJxqvnhwza05CvR7W/39Ap9r/4Vs9uiC0IeFYo1hSlJzc/8N6Evviz6vTW1x8SpHcRYyqKOf6rpl6LfWtg==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/lang-css": "^6.0.0", + "@codemirror/lang-javascript": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/html": "^1.0.0" + } + }, + "@codemirror/lang-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.0.2.tgz", + "integrity": "sha512-BZRJ9u/zl16hLkSpDAWm73mrfIR7HJrr0lvnhoSOCQVea5BglguWI/slxexhvUb0CB5cXgKWuo2bM+N9EhIaZw==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/lint": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/javascript": "^1.0.0" + } + }, + "@codemirror/lang-json": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.0.tgz", + "integrity": "sha512-DvTcYTKLmg2viADXlTdufrT334M9jowe1qO02W28nvm+nejcvhM5vot5mE8/kPrxYw/HJHhwu1z2PyBpnMLCNQ==", + "requires": { + "@codemirror/language": "^6.0.0", + "@lezer/json": "^1.0.0" + } + }, + "@codemirror/lang-markdown": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.0.1.tgz", + "integrity": "sha512-pHPQuRwf9cUrmkmsTHRjtS9ZnGu3fA9YzAdh2++d+L9wbfnC2XbKh0Xvm/0YiUjdCnoCx9wDFEoCuAnkqKWLIw==", + "requires": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/markdown": "^1.0.0" + } + }, + "@codemirror/lang-php": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-php/-/lang-php-6.0.0.tgz", + "integrity": "sha512-96CEjq0xEgbzc6bdFPwILPfZ6m8917JRbh2oPszZJABlYxG4Y+eYjtYkUTDb4yuyjQKyigHoeGC6zoIOYA1NWA==", + "requires": { + "@codemirror/lang-html": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/php": "^1.0.0" + } + }, "@codemirror/language": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz", @@ -2114,6 +2320,15 @@ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz", "integrity": "sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA==" }, + "@lezer/css": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.0.0.tgz", + "integrity": "sha512-616VqgDKumHmYIuxs3tnX1irEQmoDHgF/TlP4O5ICWwyHwLMErq+8iKVuzTkOdBqvYAVmObqThcDEAaaMJjAdg==", + "requires": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "@lezer/highlight": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.0.0.tgz", @@ -2122,6 +2337,34 @@ "@lezer/common": "^1.0.0" } }, + "@lezer/html": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@lezer/html/-/html-1.0.1.tgz", + "integrity": "sha512-sC00zEt3GBh3vVO6QaGX4YZCl41S9dHWN/WGBsDixy9G+sqOC7gsa4cxA/fmRVAiBvhqYkJk+5Ul4oul92CPVw==", + "requires": { + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "@lezer/javascript": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.0.2.tgz", + "integrity": "sha512-IjOVeIRhM8IuafWNnk+UzRz7p4/JSOKBNINLYLsdSGuJS9Ju7vFdc82AlTt0jgtV5D8eBZf4g0vK4d3ttBNz7A==", + "requires": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "@lezer/json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz", + "integrity": "sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==", + "requires": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "@lezer/lr": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.2.0.tgz", @@ -2130,6 +2373,24 @@ "@lezer/common": "^1.0.0" } }, + "@lezer/markdown": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.0.1.tgz", + "integrity": "sha512-LlpNWLqes3XQvd8TwpJTHf9ENl4fI6H32xQkMgltUITFMMdQpOASXQtDawWR03yS6hskh4bkhATQbgjdGMoUvA==", + "requires": { + "@lezer/common": "^1.0.0", + "@lezer/highlight": "^1.0.0" + } + }, + "@lezer/php": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/php/-/php-1.0.0.tgz", + "integrity": "sha512-kFQu/mk/vmjpA+fjQU87d9eimqKJ9PFCa8CZCPFWGEwNnm7Ahpw32N+HYEU/YAQ0XcfmOAnW/YJCEa8WpUOMMw==", + "requires": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", diff --git a/package.json b/package.json index 8407ffc77..4d2b70247 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,11 @@ }, "dependencies": { "@codemirror/commands": "^6.0.1", + "@codemirror/lang-html": "^6.1.0", + "@codemirror/lang-javascript": "^6.0.2", + "@codemirror/lang-json": "^6.0.0", + "@codemirror/lang-markdown": "^6.0.1", + "@codemirror/lang-php": "^6.0.0", "@codemirror/language": "^6.2.1", "@codemirror/legacy-modes": "^6.1.0", "@codemirror/state": "^6.1.0", diff --git a/resources/js/code/index.mjs b/resources/js/code/index.mjs index ff60cbff5..6ef659994 100644 --- a/resources/js/code/index.mjs +++ b/resources/js/code/index.mjs @@ -1,10 +1,9 @@ import {EditorView} from "@codemirror/view" -// import {EditorState} from "@codemirror/state" import Clipboard from "clipboard/dist/clipboard.min"; // Modes -import {modes, modeMap, modesAsStreamLanguages} from "./modes"; import {viewer} from "./setups.js"; +import {createView, updateViewLanguage} from "./views.js"; /** * Highlight pre elements on a page @@ -36,26 +35,24 @@ function highlightElem(elem) { elem.innerHTML = elem.innerHTML.replace(//gi ,'\n'); const content = elem.textContent.trimEnd(); - let mode = ''; + let langName = ''; if (innerCodeElem !== null) { - const langName = innerCodeElem.className.replace('language-', ''); - mode = getMode(langName, content); + langName = innerCodeElem.className.replace('language-', ''); } const wrapper = document.createElement('div'); elem.parentNode.insertBefore(wrapper, elem); - const cm = new EditorView({ + const ev = createView({ parent: wrapper, doc: content, extensions: viewer(), }); + setMode(ev, langName, content); elem.remove(); - // TODO - theme: getTheme(), - // TODO - mode, - addCopyIcon(cm); + addCopyIcon(ev); } /** @@ -84,28 +81,6 @@ function addCopyIcon(cmInstance) { // }); } -/** - * Search for a codemirror code based off a user suggestion - * @param {String} suggestion - * @param {String} content - * @returns {string} - */ -function getMode(suggestion, content) { - suggestion = suggestion.trim().replace(/^\./g, '').toLowerCase(); - - const modeMapType = typeof modeMap[suggestion]; - - if (modeMapType === 'undefined') { - return ''; - } - - if (modeMapType === 'function') { - return modeMap[suggestion](content); - } - - return modeMap[suggestion]; -} - /** * Ge the theme to use for CodeMirror instances. * @returns {*|string} @@ -172,12 +147,14 @@ export function inlineEditor(textArea, mode) { } /** - * Set the mode of a codemirror instance. - * @param cmInstance - * @param modeSuggestion + * Set the language mode of a codemirror EditorView. + * + * @param {EditorView} ev + * @param {string} modeSuggestion + * @param {string} content */ -export function setMode(cmInstance, modeSuggestion, content) { - cmInstance.setOption('mode', getMode(modeSuggestion, content)); +export function setMode(ev, modeSuggestion, content) { + updateViewLanguage(ev, modeSuggestion, content); } /** diff --git a/resources/js/code/languages.js b/resources/js/code/languages.js new file mode 100644 index 000000000..4b04bdb14 --- /dev/null +++ b/resources/js/code/languages.js @@ -0,0 +1,120 @@ +import {StreamLanguage} from "@codemirror/language" + +import {css} from '@codemirror/legacy-modes/mode/css'; +import {c, java, cpp, csharp, kotlin, scala} from '@codemirror/legacy-modes/mode/clike'; +import {diff} from '@codemirror/legacy-modes/mode/diff'; +import {fortran} from '@codemirror/legacy-modes/mode/fortran'; +import {go} from '@codemirror/legacy-modes/mode/go'; +import {haskell} from '@codemirror/legacy-modes/mode/haskell'; +import {html} from '@codemirror/lang-html'; +import {javascript} from '@codemirror/lang-javascript'; +import {json} from '@codemirror/lang-json'; +import {julia} from '@codemirror/legacy-modes/mode/julia'; +import {lua} from '@codemirror/legacy-modes/mode/lua'; +import {markdown} from '@codemirror/lang-markdown'; +import {oCaml, fSharp, sml} from '@codemirror/legacy-modes/mode/mllike'; +import {nginx} from '@codemirror/legacy-modes/mode/nginx'; +import {perl} from '@codemirror/legacy-modes/mode/perl'; +import {pascal} from '@codemirror/legacy-modes/mode/pascal'; +import {php} from '@codemirror/lang-php'; +import {powerShell} from '@codemirror/legacy-modes/mode/powershell'; +import {properties} from '@codemirror/legacy-modes/mode/properties'; +import {python} from '@codemirror/legacy-modes/mode/python'; +import {ruby} from '@codemirror/legacy-modes/mode/ruby'; +import {rust} from '@codemirror/legacy-modes/mode/rust'; +import {shell} from '@codemirror/legacy-modes/mode/shell'; +import {sql} from '@codemirror/legacy-modes/mode/sql'; +import {stex} from '@codemirror/legacy-modes/mode/stex'; +import {toml} from '@codemirror/legacy-modes/mode/toml'; +import {vb} from '@codemirror/legacy-modes/mode/vb'; +import {vbScript} from '@codemirror/legacy-modes/mode/vbscript'; +import {xml} from '@codemirror/legacy-modes/mode/xml'; +import {yaml} from '@codemirror/legacy-modes/mode/yaml'; + + +// Mapping of possible languages or formats from user input to their codemirror modes. +// Value can be a mode string or a function that will receive the code content & return the mode string. +// The function option is used in the event the exact mode could be dynamic depending on the code. +const modeMap = { + bash: () => StreamLanguage.define(shell), + css: () => StreamLanguage.define(css), + c: () => StreamLanguage.define(c), + java: () => StreamLanguage.define(java), + scala: () => StreamLanguage.define(scala), + kotlin: () => StreamLanguage.define(kotlin), + 'c++': () => StreamLanguage.define(cpp), + 'c#': () => StreamLanguage.define(csharp), + csharp: () => StreamLanguage.define(csharp), + diff: () => StreamLanguage.define(diff), + for: () => StreamLanguage.define(fortran), + fortran: () => StreamLanguage.define(fortran), + 'f#': () => StreamLanguage.define(fSharp), + fsharp: () => StreamLanguage.define(fSharp), + go: () => StreamLanguage.define(go), + haskell: () => StreamLanguage.define(haskell), + hs: () => StreamLanguage.define(haskell), + html: () => html(), + ini: () => StreamLanguage.define(properties), + javascript: () => javascript(), + json: () => json(), + js: () => javascript(), + jl: () => StreamLanguage.define(julia), + julia: () => StreamLanguage.define(julia), + latex: () => StreamLanguage.define(stex), + lua: () => StreamLanguage.define(lua), + md: () => StreamLanguage.define(markdown), + mdown: () => StreamLanguage.define(markdown), + markdown: () => StreamLanguage.define(markdown), + ml: () => StreamLanguage.define(sml), + nginx: () => StreamLanguage.define(nginx), + perl: () => StreamLanguage.define(perl), + pl: () => StreamLanguage.define(perl), + powershell: () => StreamLanguage.define(powerShell), + properties: () => StreamLanguage.define(properties), + ocaml: () => StreamLanguage.define(oCaml), + pascal: () => StreamLanguage.define(pascal), + pas: () => StreamLanguage.define(pascal), + php: (code) => { + const hasTags = code.includes(' StreamLanguage.define(python), + python: () => StreamLanguage.define(python), + ruby: () => StreamLanguage.define(ruby), + rust: () => StreamLanguage.define(rust), + rb: () => StreamLanguage.define(ruby), + rs: () => StreamLanguage.define(rust), + shell: () => StreamLanguage.define(shell), + sh: () => StreamLanguage.define(shell), + stext: () => StreamLanguage.define(stex), + toml: () => StreamLanguage.define(toml), + ts: () => javascript({typescript: true}), + typescript: () => javascript({typescript: true}), + sql: () => StreamLanguage.define(sql), + vbs: () => StreamLanguage.define(vbScript), + vbscript: () => StreamLanguage.define(vbScript), + 'vb.net': () => StreamLanguage.define(vb), + vbnet: () => StreamLanguage.define(vb), + xml: () => StreamLanguage.define(xml), + yaml: () => StreamLanguage.define(yaml), + yml: () => StreamLanguage.define(yaml), +}; + +/** + * Get the relevant codemirror language extension based upon the given language + * suggestion and content. + * @param {String} langSuggestion + * @param {String} content + * @returns {StreamLanguage} + */ +export function getLanguageExtension(langSuggestion, content) { + const suggestion = langSuggestion.trim().replace(/^\./g, '').toLowerCase(); + + const language = modeMap[suggestion]; + + if (typeof language === 'undefined') { + return undefined; + } + + return language(content); +} \ No newline at end of file diff --git a/resources/js/code/modes.js b/resources/js/code/modes.js deleted file mode 100644 index 5a89255a5..000000000 --- a/resources/js/code/modes.js +++ /dev/null @@ -1,134 +0,0 @@ -import {StreamLanguage} from "@codemirror/language" - -import {css as langCss} from '@codemirror/legacy-modes/mode/css'; -import {clike as langClike} from '@codemirror/legacy-modes/mode/clike'; -import {diff as langDiff} from '@codemirror/legacy-modes/mode/diff'; -import {fortran as langFortran} from '@codemirror/legacy-modes/mode/fortran'; -import {go as langGo} from '@codemirror/legacy-modes/mode/go'; -import {haskell as langHaskell} from '@codemirror/legacy-modes/mode/haskell'; -// import {htmlmixed as langHtmlmixed} from '@codemirror/legacy-modes/mode/htmlmixed'; -import {javascript as langJavascript} from '@codemirror/legacy-modes/mode/javascript'; -import {julia as langJulia} from '@codemirror/legacy-modes/mode/julia'; -import {lua as langLua} from '@codemirror/legacy-modes/mode/lua'; -// import {markdown as langMarkdown} from '@codemirror/legacy-modes/mode/markdown'; -import {oCaml as langMllike} from '@codemirror/legacy-modes/mode/mllike'; -import {nginx as langNginx} from '@codemirror/legacy-modes/mode/nginx'; -import {perl as langPerl} from '@codemirror/legacy-modes/mode/perl'; -import {pascal as langPascal} from '@codemirror/legacy-modes/mode/pascal'; -// import {php as langPhp} from '@codemirror/legacy-modes/mode/php'; -import {powerShell as langPowershell} from '@codemirror/legacy-modes/mode/powershell'; -import {properties as langProperties} from '@codemirror/legacy-modes/mode/properties'; -import {python as langPython} from '@codemirror/legacy-modes/mode/python'; -import {ruby as langRuby} from '@codemirror/legacy-modes/mode/ruby'; -import {rust as langRust} from '@codemirror/legacy-modes/mode/rust'; -import {shell as langShell} from '@codemirror/legacy-modes/mode/shell'; -import {sql as langSql} from '@codemirror/legacy-modes/mode/sql'; -import {stex as langStex} from '@codemirror/legacy-modes/mode/stex'; -import {toml as langToml} from '@codemirror/legacy-modes/mode/toml'; -import {vb as langVb} from '@codemirror/legacy-modes/mode/vb'; -import {vbScript as langVbscript} from '@codemirror/legacy-modes/mode/vbscript'; -import {xml as langXml} from '@codemirror/legacy-modes/mode/xml'; -import {yaml as langYaml} from '@codemirror/legacy-modes/mode/yaml'; - -export const modes = [ - langCss, - langClike, - langDiff, - langFortran, - langGo, - langHaskell, - // langHtmlmixed, - langJavascript, - langJulia, - langLua, - // langMarkdown, - langMllike, - langNginx, - langPerl, - langPascal, - // langPhp, - langPowershell, - langProperties, - langPython, - langRuby, - langRust, - langShell, - langSql, - langStex, - langToml, - langVb, - langVbscript, - langXml, - langYaml, -]; - -// Mapping of possible languages or formats from user input to their codemirror modes. -// Value can be a mode string or a function that will receive the code content & return the mode string. -// The function option is used in the event the exact mode could be dynamic depending on the code. -export const modeMap = { - bash: 'shell', - css: 'css', - c: 'text/x-csrc', - java: 'text/x-java', - scala: 'text/x-scala', - kotlin: 'text/x-kotlin', - 'c++': 'text/x-c++src', - 'c#': 'text/x-csharp', - csharp: 'text/x-csharp', - diff: 'diff', - for: 'fortran', - fortran: 'fortran', - 'f#': 'text/x-fsharp', - fsharp: 'text/x-fsharp', - go: 'go', - haskell: 'haskell', - hs: 'haskell', - html: 'htmlmixed', - ini: 'properties', - javascript: 'text/javascript', - json: 'application/json', - js: 'text/javascript', - jl: 'text/x-julia', - julia: 'text/x-julia', - latex: 'text/x-stex', - lua: 'lua', - md: 'markdown', - mdown: 'markdown', - markdown: 'markdown', - ml: 'mllike', - nginx: 'nginx', - perl: 'perl', - pl: 'perl', - powershell: 'powershell', - properties: 'properties', - ocaml: 'text/x-ocaml', - pascal: 'text/x-pascal', - pas: 'text/x-pascal', - php: (content) => { - return content.includes(' StreamLanguage.define(mode)); -} \ No newline at end of file diff --git a/resources/js/code/setups.js b/resources/js/code/setups.js index 768d3a35d..45cc9c317 100644 --- a/resources/js/code/setups.js +++ b/resources/js/code/setups.js @@ -6,9 +6,6 @@ import {defaultHighlightStyle, syntaxHighlighting, bracketMatching, import {defaultKeymap, history, historyKeymap} from "@codemirror/commands" import {EditorState} from "@codemirror/state" -import {modesAsStreamLanguages} from "./modes"; - - export function viewer() { return [ lineNumbers(), @@ -27,6 +24,5 @@ export function viewer() { ...foldKeymap, ]), EditorState.readOnly.of(true), - ...modesAsStreamLanguages(), ]; } \ No newline at end of file diff --git a/resources/js/code/views.js b/resources/js/code/views.js new file mode 100644 index 000000000..e87718939 --- /dev/null +++ b/resources/js/code/views.js @@ -0,0 +1,38 @@ +import {getLanguageExtension} from "./languages"; +import {Compartment} from "@codemirror/state" +import {EditorView} from "@codemirror/view" + +const viewLangCompartments = new WeakMap(); + +/** + * Create a new editor view. + * + * @param {Object} config + * @returns {EditorView} + */ +export function createView(config) { + const langCompartment = new Compartment(); + config.extensions.push(langCompartment.of([])); + + const ev = new EditorView(config); + + viewLangCompartments.set(ev, langCompartment); + + return ev; +} + +/** + * Set the language mode of an EditorView. + * + * @param {EditorView} ev + * @param {string} modeSuggestion + * @param {string} content + */ +export function updateViewLanguage(ev, modeSuggestion, content) { + const compartment = viewLangCompartments.get(ev); + const language = getLanguageExtension(modeSuggestion, content); + + ev.dispatch({ + effects: compartment.reconfigure(language ? language : []) + }) +} \ No newline at end of file From 4757ed9453c0cfd8dd229e34ee3a64f74dfe0f3a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 4 Aug 2022 13:33:51 +0100 Subject: [PATCH 03/22] Converted codemirror languges to new packages where available Does increase bundle size massively though, Will need to think about solutions for this. --- package-lock.json | 217 +++++++++++++++++++++++++++++++++ package.json | 7 ++ resources/js/code/languages.js | 56 +++++---- 3 files changed, 253 insertions(+), 27 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0eca777cb..a29be3324 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,11 +6,18 @@ "": { "dependencies": { "@codemirror/commands": "^6.0.1", + "@codemirror/lang-cpp": "^6.0.1", + "@codemirror/lang-css": "^6.0.0", "@codemirror/lang-html": "^6.1.0", + "@codemirror/lang-java": "^6.0.0", "@codemirror/lang-javascript": "^6.0.2", "@codemirror/lang-json": "^6.0.0", "@codemirror/lang-markdown": "^6.0.1", "@codemirror/lang-php": "^6.0.0", + "@codemirror/lang-python": "^6.0.1", + "@codemirror/lang-rust": "^6.0.0", + "@codemirror/lang-sql": "^6.0.0", + "@codemirror/lang-xml": "^6.0.0", "@codemirror/language": "^6.2.1", "@codemirror/legacy-modes": "^6.1.0", "@codemirror/state": "^6.1.0", @@ -60,6 +67,15 @@ "@lezer/common": "^1.0.0" } }, + "node_modules/@codemirror/lang-cpp": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.1.tgz", + "integrity": "sha512-46p3ohfhjzkLWJ3VwvzX0aqlXh8UkEqX1xo2Eds9l6Ql3uDoxI2IZEjR9cgJaGOZTXCkDzQuQH7sfYAxMvzLjA==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/cpp": "^1.0.0" + } + }, "node_modules/@codemirror/lang-css": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.0.0.tgz", @@ -85,6 +101,15 @@ "@lezer/html": "^1.0.0" } }, + "node_modules/@codemirror/lang-java": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-java/-/lang-java-6.0.0.tgz", + "integrity": "sha512-aeWq+ikUS6Eubk6RBbiMgxuBIT4Ih8Asb1qc2pSiMcstrwr4ODbazPXsBHbLBYg3aObvFyOm2bNQncbQJjZ3sQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/java": "^1.0.0" + } + }, "node_modules/@codemirror/lang-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.0.2.tgz", @@ -133,6 +158,48 @@ "@lezer/php": "^1.0.0" } }, + "node_modules/@codemirror/lang-python": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.0.1.tgz", + "integrity": "sha512-w2jTSY+LgXnK7iIBLgMxk6xtJhZHkcxcGGveuq9zYmncURmOTFXKnDvBaBClNIHKgjkHXZqGK8ZduCMK23hZPA==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/python": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-rust": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-rust/-/lang-rust-6.0.0.tgz", + "integrity": "sha512-VQql3Qk1BwoXb3SUkeWll/EEwhsgQWc1bpia7CFqqp2PhQBb5A6r4Vj2JCkU/nE6A7TDPSGHTOoqJSG5s/VXtQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/rust": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-sql": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.0.0.tgz", + "integrity": "sha512-mq4NwTDbbo7QZktfgPsS+ms0FmAceH4WM2jLbgf+N28FoKUy0JzGe3XJymgnTewXnNUwujKBxArQzibxSDdVyQ==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@codemirror/lang-xml": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.0.0.tgz", + "integrity": "sha512-M/HLWxIiP956xGjtrxkeHkCmDGVQGKu782x8pOH5CLJIMkWtiB1DWfDoDHqpFjdEE9dkfcqPWvYfVi6GbhuXEg==", + "dependencies": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/xml": "^1.0.0" + } + }, "node_modules/@codemirror/language": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz", @@ -194,6 +261,15 @@ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz", "integrity": "sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA==" }, + "node_modules/@lezer/cpp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.0.0.tgz", + "integrity": "sha512-Klk3/AIEKoptmm6cNm7xTulNXjdTKkD+hVOEcz/NeRg8tIestP5hsGHJeFDR/XtyDTxsjoPjKZRIGohht7zbKw==", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "node_modules/@lezer/css": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.0.0.tgz", @@ -221,6 +297,15 @@ "@lezer/lr": "^1.0.0" } }, + "node_modules/@lezer/java": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.0.0.tgz", + "integrity": "sha512-z2EA0JHq2WoiKfQy5uOOd4t17PJtq8guh58gPkSzOnNcQ7DNbkrU+Axak+jL8+Noinwyz2tRNOseQFj+Tg+P0A==", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "node_modules/@lezer/javascript": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.0.2.tgz", @@ -265,6 +350,33 @@ "@lezer/lr": "^1.0.0" } }, + "node_modules/@lezer/python": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.0.tgz", + "integrity": "sha512-FVPp2usfj3zZuc+2RidXAY94WAcsHQ3dbKDbXuZgoAwUungAcXwd3EWXiWQvwNqbae+ek51bWi8dwbiQqweWCg==", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/rust": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.0.tgz", + "integrity": "sha512-IpGAxIjNxYmX9ra6GfQTSPegdCAWNeq23WNmrsMMQI7YNSvKtYxO4TX5rgZUmbhEucWn0KTBMeDEPXg99YKtTA==", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "node_modules/@lezer/xml": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.0.tgz", + "integrity": "sha512-73iI9UK8iqSvWtLlOEl/g+50ivwQn8Ge6foHVN66AXUS1RccFnAoc7BYU8b3c8/rP6dfCOGqAGaWLxBzhj60MA==", + "dependencies": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "node_modules/ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", @@ -2186,6 +2298,15 @@ "@lezer/common": "^1.0.0" } }, + "@codemirror/lang-cpp": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.1.tgz", + "integrity": "sha512-46p3ohfhjzkLWJ3VwvzX0aqlXh8UkEqX1xo2Eds9l6Ql3uDoxI2IZEjR9cgJaGOZTXCkDzQuQH7sfYAxMvzLjA==", + "requires": { + "@codemirror/language": "^6.0.0", + "@lezer/cpp": "^1.0.0" + } + }, "@codemirror/lang-css": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.0.0.tgz", @@ -2211,6 +2332,15 @@ "@lezer/html": "^1.0.0" } }, + "@codemirror/lang-java": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-java/-/lang-java-6.0.0.tgz", + "integrity": "sha512-aeWq+ikUS6Eubk6RBbiMgxuBIT4Ih8Asb1qc2pSiMcstrwr4ODbazPXsBHbLBYg3aObvFyOm2bNQncbQJjZ3sQ==", + "requires": { + "@codemirror/language": "^6.0.0", + "@lezer/java": "^1.0.0" + } + }, "@codemirror/lang-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.0.2.tgz", @@ -2259,6 +2389,48 @@ "@lezer/php": "^1.0.0" } }, + "@codemirror/lang-python": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.0.1.tgz", + "integrity": "sha512-w2jTSY+LgXnK7iIBLgMxk6xtJhZHkcxcGGveuq9zYmncURmOTFXKnDvBaBClNIHKgjkHXZqGK8ZduCMK23hZPA==", + "requires": { + "@codemirror/language": "^6.0.0", + "@lezer/python": "^1.0.0" + } + }, + "@codemirror/lang-rust": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-rust/-/lang-rust-6.0.0.tgz", + "integrity": "sha512-VQql3Qk1BwoXb3SUkeWll/EEwhsgQWc1bpia7CFqqp2PhQBb5A6r4Vj2JCkU/nE6A7TDPSGHTOoqJSG5s/VXtQ==", + "requires": { + "@codemirror/language": "^6.0.0", + "@lezer/rust": "^1.0.0" + } + }, + "@codemirror/lang-sql": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.0.0.tgz", + "integrity": "sha512-mq4NwTDbbo7QZktfgPsS+ms0FmAceH4WM2jLbgf+N28FoKUy0JzGe3XJymgnTewXnNUwujKBxArQzibxSDdVyQ==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "@codemirror/lang-xml": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.0.0.tgz", + "integrity": "sha512-M/HLWxIiP956xGjtrxkeHkCmDGVQGKu782x8pOH5CLJIMkWtiB1DWfDoDHqpFjdEE9dkfcqPWvYfVi6GbhuXEg==", + "requires": { + "@codemirror/autocomplete": "^6.0.0", + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@lezer/common": "^1.0.0", + "@lezer/xml": "^1.0.0" + } + }, "@codemirror/language": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.2.1.tgz", @@ -2320,6 +2492,15 @@ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.0.tgz", "integrity": "sha512-ohydQe+Hb+w4oMDvXzs8uuJd2NoA3D8YDcLiuDsLqH+yflDTPEpgCsWI3/6rH5C3BAedtH1/R51dxENldQceEA==" }, + "@lezer/cpp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.0.0.tgz", + "integrity": "sha512-Klk3/AIEKoptmm6cNm7xTulNXjdTKkD+hVOEcz/NeRg8tIestP5hsGHJeFDR/XtyDTxsjoPjKZRIGohht7zbKw==", + "requires": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "@lezer/css": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.0.0.tgz", @@ -2347,6 +2528,15 @@ "@lezer/lr": "^1.0.0" } }, + "@lezer/java": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.0.0.tgz", + "integrity": "sha512-z2EA0JHq2WoiKfQy5uOOd4t17PJtq8guh58gPkSzOnNcQ7DNbkrU+Axak+jL8+Noinwyz2tRNOseQFj+Tg+P0A==", + "requires": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "@lezer/javascript": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.0.2.tgz", @@ -2391,6 +2581,33 @@ "@lezer/lr": "^1.0.0" } }, + "@lezer/python": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.0.tgz", + "integrity": "sha512-FVPp2usfj3zZuc+2RidXAY94WAcsHQ3dbKDbXuZgoAwUungAcXwd3EWXiWQvwNqbae+ek51bWi8dwbiQqweWCg==", + "requires": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "@lezer/rust": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.0.tgz", + "integrity": "sha512-IpGAxIjNxYmX9ra6GfQTSPegdCAWNeq23WNmrsMMQI7YNSvKtYxO4TX5rgZUmbhEucWn0KTBMeDEPXg99YKtTA==", + "requires": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, + "@lezer/xml": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.0.tgz", + "integrity": "sha512-73iI9UK8iqSvWtLlOEl/g+50ivwQn8Ge6foHVN66AXUS1RccFnAoc7BYU8b3c8/rP6dfCOGqAGaWLxBzhj60MA==", + "requires": { + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", diff --git a/package.json b/package.json index 4d2b70247..11e69962e 100644 --- a/package.json +++ b/package.json @@ -24,11 +24,18 @@ }, "dependencies": { "@codemirror/commands": "^6.0.1", + "@codemirror/lang-cpp": "^6.0.1", + "@codemirror/lang-css": "^6.0.0", "@codemirror/lang-html": "^6.1.0", + "@codemirror/lang-java": "^6.0.0", "@codemirror/lang-javascript": "^6.0.2", "@codemirror/lang-json": "^6.0.0", "@codemirror/lang-markdown": "^6.0.1", "@codemirror/lang-php": "^6.0.0", + "@codemirror/lang-python": "^6.0.1", + "@codemirror/lang-rust": "^6.0.0", + "@codemirror/lang-sql": "^6.0.0", + "@codemirror/lang-xml": "^6.0.0", "@codemirror/language": "^6.2.1", "@codemirror/legacy-modes": "^6.1.0", "@codemirror/state": "^6.1.0", diff --git a/resources/js/code/languages.js b/resources/js/code/languages.js index 4b04bdb14..b43b1c397 100644 --- a/resources/js/code/languages.js +++ b/resources/js/code/languages.js @@ -1,12 +1,14 @@ import {StreamLanguage} from "@codemirror/language" -import {css} from '@codemirror/legacy-modes/mode/css'; -import {c, java, cpp, csharp, kotlin, scala} from '@codemirror/legacy-modes/mode/clike'; +import {css} from '@codemirror/lang-css'; +import {c, csharp, kotlin, scala} from '@codemirror/legacy-modes/mode/clike'; +import {cpp} from '@codemirror/lang-cpp'; import {diff} from '@codemirror/legacy-modes/mode/diff'; import {fortran} from '@codemirror/legacy-modes/mode/fortran'; import {go} from '@codemirror/legacy-modes/mode/go'; import {haskell} from '@codemirror/legacy-modes/mode/haskell'; import {html} from '@codemirror/lang-html'; +import {java} from '@codemirror/lang-java'; import {javascript} from '@codemirror/lang-javascript'; import {json} from '@codemirror/lang-json'; import {julia} from '@codemirror/legacy-modes/mode/julia'; @@ -19,16 +21,16 @@ import {pascal} from '@codemirror/legacy-modes/mode/pascal'; import {php} from '@codemirror/lang-php'; import {powerShell} from '@codemirror/legacy-modes/mode/powershell'; import {properties} from '@codemirror/legacy-modes/mode/properties'; -import {python} from '@codemirror/legacy-modes/mode/python'; +import {python} from '@codemirror/lang-python'; import {ruby} from '@codemirror/legacy-modes/mode/ruby'; -import {rust} from '@codemirror/legacy-modes/mode/rust'; +import {rust} from '@codemirror/lang-rust'; import {shell} from '@codemirror/legacy-modes/mode/shell'; -import {sql} from '@codemirror/legacy-modes/mode/sql'; +import {sql} from '@codemirror/lang-sql'; import {stex} from '@codemirror/legacy-modes/mode/stex'; import {toml} from '@codemirror/legacy-modes/mode/toml'; import {vb} from '@codemirror/legacy-modes/mode/vb'; import {vbScript} from '@codemirror/legacy-modes/mode/vbscript'; -import {xml} from '@codemirror/legacy-modes/mode/xml'; +import {xml} from '@codemirror/lang-xml'; import {yaml} from '@codemirror/legacy-modes/mode/yaml'; @@ -37,12 +39,9 @@ import {yaml} from '@codemirror/legacy-modes/mode/yaml'; // The function option is used in the event the exact mode could be dynamic depending on the code. const modeMap = { bash: () => StreamLanguage.define(shell), - css: () => StreamLanguage.define(css), c: () => StreamLanguage.define(c), - java: () => StreamLanguage.define(java), - scala: () => StreamLanguage.define(scala), - kotlin: () => StreamLanguage.define(kotlin), - 'c++': () => StreamLanguage.define(cpp), + css: () => css(), + 'c++': () => cpp(), 'c#': () => StreamLanguage.define(csharp), csharp: () => StreamLanguage.define(csharp), diff: () => StreamLanguage.define(diff), @@ -55,47 +54,50 @@ const modeMap = { hs: () => StreamLanguage.define(haskell), html: () => html(), ini: () => StreamLanguage.define(properties), + java: () => java(), javascript: () => javascript(), json: () => json(), js: () => javascript(), jl: () => StreamLanguage.define(julia), julia: () => StreamLanguage.define(julia), + kotlin: () => StreamLanguage.define(kotlin), latex: () => StreamLanguage.define(stex), lua: () => StreamLanguage.define(lua), - md: () => StreamLanguage.define(markdown), - mdown: () => StreamLanguage.define(markdown), - markdown: () => StreamLanguage.define(markdown), + markdown: () => markdown(), + md: () => markdown(), + mdown: () => markdown(), ml: () => StreamLanguage.define(sml), nginx: () => StreamLanguage.define(nginx), - perl: () => StreamLanguage.define(perl), - pl: () => StreamLanguage.define(perl), - powershell: () => StreamLanguage.define(powerShell), - properties: () => StreamLanguage.define(properties), - ocaml: () => StreamLanguage.define(oCaml), - pascal: () => StreamLanguage.define(pascal), pas: () => StreamLanguage.define(pascal), + pascal: () => StreamLanguage.define(pascal), + perl: () => StreamLanguage.define(perl), php: (code) => { const hasTags = code.includes(' StreamLanguage.define(python), - python: () => StreamLanguage.define(python), - ruby: () => StreamLanguage.define(ruby), - rust: () => StreamLanguage.define(rust), + pl: () => StreamLanguage.define(perl), + powershell: () => StreamLanguage.define(powerShell), + properties: () => StreamLanguage.define(properties), + ocaml: () => StreamLanguage.define(oCaml), + py: () => python(), + python: () => python(), rb: () => StreamLanguage.define(ruby), - rs: () => StreamLanguage.define(rust), + rs: () => rust(), + ruby: () => StreamLanguage.define(ruby), + rust: () => rust(), + scala: () => StreamLanguage.define(scala), shell: () => StreamLanguage.define(shell), sh: () => StreamLanguage.define(shell), stext: () => StreamLanguage.define(stex), toml: () => StreamLanguage.define(toml), ts: () => javascript({typescript: true}), typescript: () => javascript({typescript: true}), - sql: () => StreamLanguage.define(sql), + sql: () => sql(), vbs: () => StreamLanguage.define(vbScript), vbscript: () => StreamLanguage.define(vbScript), 'vb.net': () => StreamLanguage.define(vb), vbnet: () => StreamLanguage.define(vb), - xml: () => StreamLanguage.define(xml), + xml: () => xml(), yaml: () => StreamLanguage.define(yaml), yml: () => StreamLanguage.define(yaml), }; From 9fd7a6abedaf69efc449c7ea00724eb890fc71f7 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 4 Aug 2022 14:19:04 +0100 Subject: [PATCH 04/22] Added dark theme handling --- package-lock.json | 23 +++++++++++++++++++++++ package.json | 1 + resources/js/code/views.js | 23 +++++++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index a29be3324..8327421b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@codemirror/language": "^6.2.1", "@codemirror/legacy-modes": "^6.1.0", "@codemirror/state": "^6.1.0", + "@codemirror/theme-one-dark": "^6.0.0", "@codemirror/view": "^6.1.2", "clipboard": "^2.0.11", "codemirror": "^6.0.1", @@ -246,6 +247,17 @@ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.1.0.tgz", "integrity": "sha512-qbUr94DZTe6/V1VS7LDLz11rM/1t/nJxR1El4I6UaxDEdc0aZZvq6JCLJWiRmUf95NRAnDH6fhXn+PWp9wGCIg==" }, + "node_modules/@codemirror/theme-one-dark": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.0.0.tgz", + "integrity": "sha512-jTCfi1I8QT++3m21Ui6sU8qwu3F/hLv161KLxfvkV1cYWSBwyUanmQFs89ChobQjBHi2x7s2k71wF9WYvE8fdw==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, "node_modules/@codemirror/view": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.1.2.tgz", @@ -2477,6 +2489,17 @@ "resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.1.0.tgz", "integrity": "sha512-qbUr94DZTe6/V1VS7LDLz11rM/1t/nJxR1El4I6UaxDEdc0aZZvq6JCLJWiRmUf95NRAnDH6fhXn+PWp9wGCIg==" }, + "@codemirror/theme-one-dark": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.0.0.tgz", + "integrity": "sha512-jTCfi1I8QT++3m21Ui6sU8qwu3F/hLv161KLxfvkV1cYWSBwyUanmQFs89ChobQjBHi2x7s2k71wF9WYvE8fdw==", + "requires": { + "@codemirror/language": "^6.0.0", + "@codemirror/state": "^6.0.0", + "@codemirror/view": "^6.0.0", + "@lezer/highlight": "^1.0.0" + } + }, "@codemirror/view": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.1.2.tgz", diff --git a/package.json b/package.json index 11e69962e..3a655c87a 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "@codemirror/language": "^6.2.1", "@codemirror/legacy-modes": "^6.1.0", "@codemirror/state": "^6.1.0", + "@codemirror/theme-one-dark": "^6.0.0", "@codemirror/view": "^6.1.2", "clipboard": "^2.0.11", "codemirror": "^6.0.1", diff --git a/resources/js/code/views.js b/resources/js/code/views.js index e87718939..cada9a1d6 100644 --- a/resources/js/code/views.js +++ b/resources/js/code/views.js @@ -1,18 +1,20 @@ -import {getLanguageExtension} from "./languages"; +import {getLanguageExtension} from "./languages" import {Compartment} from "@codemirror/state" import {EditorView} from "@codemirror/view" +import {oneDark} from "@codemirror/theme-one-dark" const viewLangCompartments = new WeakMap(); /** * Create a new editor view. * - * @param {Object} config + * @param {{parent: Element, doc: String, extensions: Array}} config * @returns {EditorView} */ export function createView(config) { const langCompartment = new Compartment(); config.extensions.push(langCompartment.of([])); + config.extensions.push(getTheme(config.parent)); const ev = new EditorView(config); @@ -21,6 +23,23 @@ export function createView(config) { return ev; } +/** + * Ge the theme extension to use for editor view instance. + * @returns {Extension} + */ +function getTheme(viewParentEl) { + const darkMode = document.documentElement.classList.contains('dark-mode'); + + const eventData = { + darkMode: darkMode, + theme: null, + }; + + window.$events.emitPublic(viewParentEl, 'library-cm6::configure-theme', eventData); + + return eventData.theme || (darkMode ? oneDark : []); +} + /** * Set the language mode of an EditorView. * From f51036b203936a3814286df37a03f6e200d9bb79 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 17 Feb 2023 22:14:34 +0000 Subject: [PATCH 05/22] Added newer languages where possible Cannot find existing option for twig/smarty, need to look other methods. --- package-lock.json | 134 --------------------------------- package.json | 10 --- resources/js/code.mjs | 0 resources/js/code/languages.js | 63 +++++++++------- 4 files changed, 37 insertions(+), 170 deletions(-) delete mode 100644 resources/js/code.mjs diff --git a/package-lock.json b/package-lock.json index 6cdb7e43b..e8cd4f6db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,18 +6,8 @@ "": { "dependencies": { "@codemirror/commands": "^6.0.1", - "@codemirror/lang-cpp": "^6.0.1", - "@codemirror/lang-css": "^6.0.0", - "@codemirror/lang-html": "^6.1.0", - "@codemirror/lang-java": "^6.0.0", - "@codemirror/lang-javascript": "^6.0.2", - "@codemirror/lang-json": "^6.0.0", "@codemirror/lang-markdown": "^6.0.1", "@codemirror/lang-php": "^6.0.0", - "@codemirror/lang-python": "^6.0.1", - "@codemirror/lang-rust": "^6.0.0", - "@codemirror/lang-sql": "^6.0.0", - "@codemirror/lang-xml": "^6.0.0", "@codemirror/language": "^6.2.1", "@codemirror/legacy-modes": "^6.1.0", "@codemirror/state": "^6.1.0", @@ -68,15 +58,6 @@ "@lezer/common": "^1.0.0" } }, - "node_modules/@codemirror/lang-cpp": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-cpp/-/lang-cpp-6.0.2.tgz", - "integrity": "sha512-6oYEYUKHvrnacXxWxYa6t4puTlbN3dgV662BDfSH8+MfjQjVmP697/KYTDOqpxgerkvoNm7q5wlFMBeX8ZMocg==", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@lezer/cpp": "^1.0.0" - } - }, "node_modules/@codemirror/lang-css": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@codemirror/lang-css/-/lang-css-6.0.2.tgz", @@ -104,15 +85,6 @@ "@lezer/html": "^1.3.0" } }, - "node_modules/@codemirror/lang-java": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@codemirror/lang-java/-/lang-java-6.0.1.tgz", - "integrity": "sha512-OOnmhH67h97jHzCuFaIEspbmsT98fNdhVhmA3zCxW0cn7l8rChDhZtwiwJ/JOKXgfm4J+ELxQihxaI7bj7mJRg==", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@lezer/java": "^1.0.0" - } - }, "node_modules/@codemirror/lang-javascript": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/@codemirror/lang-javascript/-/lang-javascript-6.1.4.tgz", @@ -127,15 +99,6 @@ "@lezer/javascript": "^1.0.0" } }, - "node_modules/@codemirror/lang-json": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz", - "integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@lezer/json": "^1.0.0" - } - }, "node_modules/@codemirror/lang-markdown": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@codemirror/lang-markdown/-/lang-markdown-6.1.0.tgz", @@ -161,49 +124,6 @@ "@lezer/php": "^1.0.0" } }, - "node_modules/@codemirror/lang-python": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.1.1.tgz", - "integrity": "sha512-AddGMIKUssUAqaDKoxKWA5GAzy/CVE0eSY7/ANgNzdS1GYBkp6N49XKEyMElkuN04UsZ+bTIQdj+tVV75NMwJw==", - "dependencies": { - "@codemirror/autocomplete": "^6.3.2", - "@codemirror/language": "^6.0.0", - "@lezer/python": "^1.0.0" - } - }, - "node_modules/@codemirror/lang-rust": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@codemirror/lang-rust/-/lang-rust-6.0.1.tgz", - "integrity": "sha512-344EMWFBzWArHWdZn/NcgkwMvZIWUR1GEBdwG8FEp++6o6vT6KL9V7vGs2ONsKxxFUPXKI0SPcWhyYyl2zPYxQ==", - "dependencies": { - "@codemirror/language": "^6.0.0", - "@lezer/rust": "^1.0.0" - } - }, - "node_modules/@codemirror/lang-sql": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/@codemirror/lang-sql/-/lang-sql-6.4.0.tgz", - "integrity": "sha512-UWGK1+zc9+JtkiT+XxHByp4N6VLgLvC2x0tIudrJG26gyNtn0hWOVoB0A8kh/NABPWkKl3tLWDYf2qOBJS9Zdw==", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/language": "^6.0.0", - "@codemirror/state": "^6.0.0", - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "node_modules/@codemirror/lang-xml": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@codemirror/lang-xml/-/lang-xml-6.0.2.tgz", - "integrity": "sha512-JQYZjHL2LAfpiZI2/qZ/qzDuSqmGKMwyApYmEUUCTxLM4MWS7sATUEfIguZQr9Zjx/7gcdnewb039smF6nC2zw==", - "dependencies": { - "@codemirror/autocomplete": "^6.0.0", - "@codemirror/language": "^6.4.0", - "@codemirror/state": "^6.0.0", - "@lezer/common": "^1.0.0", - "@lezer/xml": "^1.0.0" - } - }, "node_modules/@codemirror/language": { "version": "6.6.0", "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.6.0.tgz", @@ -628,15 +548,6 @@ "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz", "integrity": "sha512-SVgiGtMnMnW3ActR8SXgsDhw7a0w0ChHSYAyAUxxrOiJ1OqYWEKk/xJd84tTSPo1mo6DXLObAJALNnd0Hrv7Ng==" }, - "node_modules/@lezer/cpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@lezer/cpp/-/cpp-1.1.0.tgz", - "integrity": "sha512-zUHrjNFuY/DOZCkOBJ6qItQIkcopHM/Zv/QOE0a4XNG3HDNahxTNu5fQYl8dIuKCpxCqRdMl5cEwl5zekFc7BA==", - "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, "node_modules/@lezer/css": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@lezer/css/-/css-1.1.1.tgz", @@ -664,15 +575,6 @@ "@lezer/lr": "^1.0.0" } }, - "node_modules/@lezer/java": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@lezer/java/-/java-1.0.3.tgz", - "integrity": "sha512-kKN17wmgP1cgHb8juR4pwVSPMKkDMzY/lAPbBsZ1fpXwbk2sg3N1kIrf0q+LefxgrANaQb/eNO7+m2QPruTFng==", - "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, "node_modules/@lezer/javascript": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@lezer/javascript/-/javascript-1.4.1.tgz", @@ -682,15 +584,6 @@ "@lezer/lr": "^1.3.0" } }, - "node_modules/@lezer/json": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.0.tgz", - "integrity": "sha512-zbAuUY09RBzCoCA3lJ1+ypKw5WSNvLqGMtasdW6HvVOqZoCpPr8eWrsGnOVWGKGn8Rh21FnrKRVlJXrGAVUqRw==", - "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, "node_modules/@lezer/lr": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.3.3.tgz", @@ -717,33 +610,6 @@ "@lezer/lr": "^1.1.0" } }, - "node_modules/@lezer/python": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@lezer/python/-/python-1.1.2.tgz", - "integrity": "sha512-ukm4VhDasFX7/9BUYHTyUNXH0xQ5B7/QBlZD8P51+dh6GtXRSCQqNxloez5d+MxVb2Sg+31S8E/33qoFREfkpA==", - "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "node_modules/@lezer/rust": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@lezer/rust/-/rust-1.0.0.tgz", - "integrity": "sha512-IpGAxIjNxYmX9ra6GfQTSPegdCAWNeq23WNmrsMMQI7YNSvKtYxO4TX5rgZUmbhEucWn0KTBMeDEPXg99YKtTA==", - "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, - "node_modules/@lezer/xml": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@lezer/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-jMDXrV953sDAUEMI25VNrI9dz94Ai96FfeglytFINhhwQ867HKlCE2jt3AwZTCT7M528WxdDWv/Ty8e9wizwmQ==", - "dependencies": { - "@lezer/highlight": "^1.0.0", - "@lezer/lr": "^1.0.0" - } - }, "node_modules/ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", diff --git a/package.json b/package.json index 1ab0fe482..24f451a9c 100644 --- a/package.json +++ b/package.json @@ -24,18 +24,8 @@ }, "dependencies": { "@codemirror/commands": "^6.0.1", - "@codemirror/lang-cpp": "^6.0.1", - "@codemirror/lang-css": "^6.0.0", - "@codemirror/lang-html": "^6.1.0", - "@codemirror/lang-java": "^6.0.0", - "@codemirror/lang-javascript": "^6.0.2", - "@codemirror/lang-json": "^6.0.0", "@codemirror/lang-markdown": "^6.0.1", "@codemirror/lang-php": "^6.0.0", - "@codemirror/lang-python": "^6.0.1", - "@codemirror/lang-rust": "^6.0.0", - "@codemirror/lang-sql": "^6.0.0", - "@codemirror/lang-xml": "^6.0.0", "@codemirror/language": "^6.2.1", "@codemirror/legacy-modes": "^6.1.0", "@codemirror/state": "^6.1.0", diff --git a/resources/js/code.mjs b/resources/js/code.mjs deleted file mode 100644 index e69de29bb..000000000 diff --git a/resources/js/code/languages.js b/resources/js/code/languages.js index b43b1c397..61aaeeefe 100644 --- a/resources/js/code/languages.js +++ b/resources/js/code/languages.js @@ -1,37 +1,37 @@ import {StreamLanguage} from "@codemirror/language" -import {css} from '@codemirror/lang-css'; -import {c, csharp, kotlin, scala} from '@codemirror/legacy-modes/mode/clike'; -import {cpp} from '@codemirror/lang-cpp'; +import {css} from '@codemirror/legacy-modes/mode/css'; +import {c, cpp, csharp, java, kotlin, scala, dart} from '@codemirror/legacy-modes/mode/clike'; import {diff} from '@codemirror/legacy-modes/mode/diff'; import {fortran} from '@codemirror/legacy-modes/mode/fortran'; import {go} from '@codemirror/legacy-modes/mode/go'; import {haskell} from '@codemirror/legacy-modes/mode/haskell'; -import {html} from '@codemirror/lang-html'; -import {java} from '@codemirror/lang-java'; -import {javascript} from '@codemirror/lang-javascript'; -import {json} from '@codemirror/lang-json'; +import {javascript, json, typescript} from '@codemirror/legacy-modes/mode/javascript'; import {julia} from '@codemirror/legacy-modes/mode/julia'; import {lua} from '@codemirror/legacy-modes/mode/lua'; import {markdown} from '@codemirror/lang-markdown'; import {oCaml, fSharp, sml} from '@codemirror/legacy-modes/mode/mllike'; import {nginx} from '@codemirror/legacy-modes/mode/nginx'; +import {octave} from '@codemirror/legacy-modes/mode/octave'; import {perl} from '@codemirror/legacy-modes/mode/perl'; import {pascal} from '@codemirror/legacy-modes/mode/pascal'; import {php} from '@codemirror/lang-php'; import {powerShell} from '@codemirror/legacy-modes/mode/powershell'; import {properties} from '@codemirror/legacy-modes/mode/properties'; -import {python} from '@codemirror/lang-python'; +import {python} from '@codemirror/legacy-modes/mode/python'; import {ruby} from '@codemirror/legacy-modes/mode/ruby'; -import {rust} from '@codemirror/lang-rust'; +import {rust} from '@codemirror/legacy-modes/mode/rust'; +import {scheme} from '@codemirror/legacy-modes/mode/scheme'; import {shell} from '@codemirror/legacy-modes/mode/shell'; -import {sql} from '@codemirror/lang-sql'; +import {standardSQL, pgSQL, msSQL, mySQL, sqlite, plSQL} from '@codemirror/legacy-modes/mode/sql'; import {stex} from '@codemirror/legacy-modes/mode/stex'; import {toml} from '@codemirror/legacy-modes/mode/toml'; +// import {twig, smarty} from '@codemirror/legacy-modes/mode/php'; // TODO import {vb} from '@codemirror/legacy-modes/mode/vb'; import {vbScript} from '@codemirror/legacy-modes/mode/vbscript'; -import {xml} from '@codemirror/lang-xml'; +import {xml, html} from '@codemirror/legacy-modes/mode/xml'; import {yaml} from '@codemirror/legacy-modes/mode/yaml'; +import {swift} from "@codemirror/legacy-modes/mode/swift"; // Mapping of possible languages or formats from user input to their codemirror modes. @@ -40,10 +40,11 @@ import {yaml} from '@codemirror/legacy-modes/mode/yaml'; const modeMap = { bash: () => StreamLanguage.define(shell), c: () => StreamLanguage.define(c), - css: () => css(), - 'c++': () => cpp(), + css: () => StreamLanguage.define(css), + 'c++': () => StreamLanguage.define(cpp), 'c#': () => StreamLanguage.define(csharp), csharp: () => StreamLanguage.define(csharp), + dart: () => StreamLanguage.define(dart), diff: () => StreamLanguage.define(diff), for: () => StreamLanguage.define(fortran), fortran: () => StreamLanguage.define(fortran), @@ -52,52 +53,62 @@ const modeMap = { go: () => StreamLanguage.define(go), haskell: () => StreamLanguage.define(haskell), hs: () => StreamLanguage.define(haskell), - html: () => html(), + html: () => StreamLanguage.define(html), ini: () => StreamLanguage.define(properties), - java: () => java(), - javascript: () => javascript(), - json: () => json(), - js: () => javascript(), + java: () => StreamLanguage.define(java), + javascript: () => StreamLanguage.define(javascript), + json: () => StreamLanguage.define(json), + js: () => StreamLanguage.define(javascript), jl: () => StreamLanguage.define(julia), julia: () => StreamLanguage.define(julia), kotlin: () => StreamLanguage.define(kotlin), latex: () => StreamLanguage.define(stex), lua: () => StreamLanguage.define(lua), markdown: () => markdown(), + matlab: () => StreamLanguage.define(octave), md: () => markdown(), mdown: () => markdown(), ml: () => StreamLanguage.define(sml), + mssql: () => StreamLanguage.define(msSQL), + mysql: () => StreamLanguage.define(mySQL), nginx: () => StreamLanguage.define(nginx), + octave: () => StreamLanguage.define(octave), pas: () => StreamLanguage.define(pascal), pascal: () => StreamLanguage.define(pascal), perl: () => StreamLanguage.define(perl), + pgsql: () => StreamLanguage.define(pgSQL), php: (code) => { const hasTags = code.includes(' StreamLanguage.define(perl), + 'pl/sql': () => StreamLanguage.define(plSQL), + postgresql: () => StreamLanguage.define(pgSQL), powershell: () => StreamLanguage.define(powerShell), properties: () => StreamLanguage.define(properties), ocaml: () => StreamLanguage.define(oCaml), - py: () => python(), - python: () => python(), + py: () => StreamLanguage.define(python), + python: () => StreamLanguage.define(python), rb: () => StreamLanguage.define(ruby), - rs: () => rust(), + rs: () => StreamLanguage.define(rust), ruby: () => StreamLanguage.define(ruby), - rust: () => rust(), + rust: () => StreamLanguage.define(rust), scala: () => StreamLanguage.define(scala), + scheme: () => StreamLanguage.define(scheme), shell: () => StreamLanguage.define(shell), sh: () => StreamLanguage.define(shell), stext: () => StreamLanguage.define(stex), + swift: () => StreamLanguage.define(swift), toml: () => StreamLanguage.define(toml), - ts: () => javascript({typescript: true}), - typescript: () => javascript({typescript: true}), - sql: () => sql(), + ts: () => StreamLanguage.define(typescript), + typescript: () => StreamLanguage.define(typescript), + sql: () => StreamLanguage.define(standardSQL), + sqlite: () => StreamLanguage.define(sqlite), vbs: () => StreamLanguage.define(vbScript), vbscript: () => StreamLanguage.define(vbScript), 'vb.net': () => StreamLanguage.define(vb), vbnet: () => StreamLanguage.define(vb), - xml: () => xml(), + xml: () => StreamLanguage.define(xml), yaml: () => StreamLanguage.define(yaml), yml: () => StreamLanguage.define(yaml), }; From c148e2f3d96f3e62fef9ee63c0cd52943b3160ab Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 17 Feb 2023 22:37:13 +0000 Subject: [PATCH 06/22] Added esbuild bundle inspection metafile --- .gitignore | 4 +++- dev/build/esbuild.js | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 90b80e7b8..5f3aa6600 100644 --- a/.gitignore +++ b/.gitignore @@ -21,8 +21,10 @@ yarn.lock nbproject .buildpath .project +.nvmrc .settings/ webpack-stats.json .phpunit.result.cache .DS_Store -phpstan.neon \ No newline at end of file +phpstan.neon +esbuild-meta.json \ No newline at end of file diff --git a/dev/build/esbuild.js b/dev/build/esbuild.js index 57a224876..2ff7ac1f4 100644 --- a/dev/build/esbuild.js +++ b/dev/build/esbuild.js @@ -2,6 +2,7 @@ const esbuild = require('esbuild'); const path = require('path'); +const fs = require('fs'); // Check if we're building for production // (Set via passing `production` as first argument) @@ -19,6 +20,7 @@ const outdir = path.join(__dirname, '../../public/dist'); // Build via esbuild esbuild.build({ bundle: true, + metafile: true, entryPoints, outdir, sourcemap: true, @@ -27,4 +29,6 @@ esbuild.build({ format: 'esm', minify: isProd, logLevel: "info", +}).then(result => { + fs.writeFileSync('esbuild-meta.json', JSON.stringify(result.metafile)); }).catch(() => process.exit(1)); \ No newline at end of file From dce51234527d1a0075f04d81b619e3d00e14ed3a Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 21 Mar 2023 20:53:35 +0000 Subject: [PATCH 07/22] Added own twig/smarty packages for cm6 lang support --- package-lock.json | 31 +++++++++++++++++++++++ package.json | 3 +++ resources/js/code/languages.js | 7 ++++-- resources/js/code/setups.js | 4 ++- resources/js/code/themes.js | 46 ++++++++++++++++++++++++++++++++++ resources/js/code/views.js | 2 +- 6 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 resources/js/code/themes.js diff --git a/package-lock.json b/package-lock.json index e8cd4f6db..85489c970 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,8 @@ "@codemirror/state": "^6.1.0", "@codemirror/theme-one-dark": "^6.0.0", "@codemirror/view": "^6.1.2", + "@ssddanbrown/codemirror-lang-smarty": "^1.0.0", + "@ssddanbrown/codemirror-lang-twig": "^1.0.0", "clipboard": "^2.0.11", "codemirror": "^6.0.1", "dropzone": "^5.9.3", @@ -22,6 +24,7 @@ "sortablejs": "^1.15.0" }, "devDependencies": { + "@lezer/generator": "^1.2.2", "chokidar-cli": "^3.0", "esbuild": "^0.17.3", "livereload": "^0.9.3", @@ -557,6 +560,19 @@ "@lezer/lr": "^1.0.0" } }, + "node_modules/@lezer/generator": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@lezer/generator/-/generator-1.2.2.tgz", + "integrity": "sha512-O//eH9jTPM1GnbZruuD23xU68Pkuragonn1DEIom4Kt/eJN/QFt7Vzvp1YjV/XBmoUKC+2ySPgrA5fMF9FMM2g==", + "dev": true, + "dependencies": { + "@lezer/common": "^1.0.2", + "@lezer/lr": "^1.3.0" + }, + "bin": { + "lezer-generator": "dist/lezer-generator.cjs" + } + }, "node_modules/@lezer/highlight": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.1.3.tgz", @@ -610,6 +626,21 @@ "@lezer/lr": "^1.1.0" } }, + "node_modules/@ssddanbrown/codemirror-lang-smarty": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ssddanbrown/codemirror-lang-smarty/-/codemirror-lang-smarty-1.0.0.tgz", + "integrity": "sha512-F0ut1kmdbT3eORk3xVIKfQsGCZiQdh+6sLayBa0+FTex2gyIQlVQZRRA7bPSlchI3uZtWwNnqGNz5O/QLWRlFg==" + }, + "node_modules/@ssddanbrown/codemirror-lang-twig": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@ssddanbrown/codemirror-lang-twig/-/codemirror-lang-twig-1.0.0.tgz", + "integrity": "sha512-7WIMIh8Ssc54TooGCY57WU2rKEqZZrcV2tZSVRPtd0gKYsrDEKCSLWpQjUWEx7bdgh3NKHUjq1O4ugIzI/+dwQ==", + "dependencies": { + "@codemirror/language": "^6.0.0", + "@lezer/highlight": "^1.0.0", + "@lezer/lr": "^1.0.0" + } + }, "node_modules/ansi-regex": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", diff --git a/package.json b/package.json index 24f451a9c..6b6dbbe46 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "permissions": "chown -R $USER:$USER bootstrap/cache storage public/uploads" }, "devDependencies": { + "@lezer/generator": "^1.2.2", "chokidar-cli": "^3.0", "esbuild": "^0.17.3", "livereload": "^0.9.3", @@ -31,6 +32,8 @@ "@codemirror/state": "^6.1.0", "@codemirror/theme-one-dark": "^6.0.0", "@codemirror/view": "^6.1.2", + "@ssddanbrown/codemirror-lang-smarty": "^1.0.0", + "@ssddanbrown/codemirror-lang-twig": "^1.0.0", "clipboard": "^2.0.11", "codemirror": "^6.0.1", "dropzone": "^5.9.3", diff --git a/resources/js/code/languages.js b/resources/js/code/languages.js index 61aaeeefe..4a3591624 100644 --- a/resources/js/code/languages.js +++ b/resources/js/code/languages.js @@ -23,15 +23,16 @@ import {ruby} from '@codemirror/legacy-modes/mode/ruby'; import {rust} from '@codemirror/legacy-modes/mode/rust'; import {scheme} from '@codemirror/legacy-modes/mode/scheme'; import {shell} from '@codemirror/legacy-modes/mode/shell'; +import {smarty} from "@ssddanbrown/codemirror-lang-smarty"; import {standardSQL, pgSQL, msSQL, mySQL, sqlite, plSQL} from '@codemirror/legacy-modes/mode/sql'; import {stex} from '@codemirror/legacy-modes/mode/stex'; +import {swift} from "@codemirror/legacy-modes/mode/swift"; import {toml} from '@codemirror/legacy-modes/mode/toml'; -// import {twig, smarty} from '@codemirror/legacy-modes/mode/php'; // TODO +import {twig} from "@ssddanbrown/codemirror-lang-twig"; import {vb} from '@codemirror/legacy-modes/mode/vb'; import {vbScript} from '@codemirror/legacy-modes/mode/vbscript'; import {xml, html} from '@codemirror/legacy-modes/mode/xml'; import {yaml} from '@codemirror/legacy-modes/mode/yaml'; -import {swift} from "@codemirror/legacy-modes/mode/swift"; // Mapping of possible languages or formats from user input to their codemirror modes. @@ -97,10 +98,12 @@ const modeMap = { scheme: () => StreamLanguage.define(scheme), shell: () => StreamLanguage.define(shell), sh: () => StreamLanguage.define(shell), + smarty: () => StreamLanguage.define(smarty), stext: () => StreamLanguage.define(stex), swift: () => StreamLanguage.define(swift), toml: () => StreamLanguage.define(toml), ts: () => StreamLanguage.define(typescript), + twig: () => twig(), typescript: () => StreamLanguage.define(typescript), sql: () => StreamLanguage.define(standardSQL), sqlite: () => StreamLanguage.define(sqlite), diff --git a/resources/js/code/setups.js b/resources/js/code/setups.js index 45cc9c317..e1a150856 100644 --- a/resources/js/code/setups.js +++ b/resources/js/code/setups.js @@ -6,6 +6,8 @@ import {defaultHighlightStyle, syntaxHighlighting, bracketMatching, import {defaultKeymap, history, historyKeymap} from "@codemirror/commands" import {EditorState} from "@codemirror/state" +import {defaultLight} from "./themes"; + export function viewer() { return [ lineNumbers(), @@ -14,7 +16,7 @@ export function viewer() { history(), drawSelection(), dropCursor(), - syntaxHighlighting(defaultHighlightStyle, {fallback: true}), + syntaxHighlighting(defaultLight, {fallback: true}), bracketMatching(), rectangularSelection(), highlightActiveLine(), diff --git a/resources/js/code/themes.js b/resources/js/code/themes.js new file mode 100644 index 000000000..43feb2d53 --- /dev/null +++ b/resources/js/code/themes.js @@ -0,0 +1,46 @@ +import {tags} from "@lezer/highlight"; +import {HighlightStyle} from "@codemirror/language"; + +export const defaultLight = HighlightStyle.define([ + { tag: tags.meta, + color: "#388938" }, + { tag: tags.link, + textDecoration: "underline" }, + { tag: tags.heading, + textDecoration: "underline", + fontWeight: "bold" }, + { tag: tags.emphasis, + fontStyle: "italic" }, + { tag: tags.strong, + fontWeight: "bold" }, + { tag: tags.strikethrough, + textDecoration: "line-through" }, + { tag: tags.keyword, + color: "#708" }, + { tag: [tags.atom, tags.bool, tags.url, tags.contentSeparator, tags.labelName], + color: "#219" }, + { tag: [tags.literal, tags.inserted], + color: "#164" }, + { tag: [tags.string, tags.deleted], + color: "#a11" }, + { tag: [tags.regexp, tags.escape, tags.special(tags.string)], + color: "#e40" }, + { tag: tags.definition(tags.variableName), + color: "#00f" }, + { tag: tags.local(tags.variableName), + color: "#30a" }, + { tag: [tags.typeName, tags.namespace], + color: "#085" }, + { tag: tags.className, + color: "#167" }, + { tag: [tags.special(tags.variableName), tags.macroName], + color: "#256" }, + { tag: tags.definition(tags.propertyName), + color: "#00c" }, + { tag: tags.compareOperator, + color: "#708" }, + { tag: tags.comment, + color: "#940" }, + { tag: tags.invalid, + color: "#f00" } +]); \ No newline at end of file diff --git a/resources/js/code/views.js b/resources/js/code/views.js index cada9a1d6..8202551b3 100644 --- a/resources/js/code/views.js +++ b/resources/js/code/views.js @@ -24,7 +24,7 @@ export function createView(config) { } /** - * Ge the theme extension to use for editor view instance. + * Get the theme extension to use for editor view instance. * @returns {Extension} */ function getTheme(viewParentEl) { From 572037ef1fd1e778c33c609ef295c50de33a0652 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Mon, 10 Apr 2023 15:01:44 +0100 Subject: [PATCH 08/22] Got markdown editor barely functional Updated content sync and preview scoll sync to work. Many features commented out until they can be updated. --- package.json | 2 +- resources/js/code/index.mjs | 39 ++++---- resources/js/code/setups.js | 27 +++++- resources/js/components/markdown-editor.js | 13 ++- resources/js/markdown/actions.js | 12 +-- resources/js/markdown/codemirror.js | 103 +++++++++++---------- resources/sass/_forms.scss | 4 + 7 files changed, 121 insertions(+), 79 deletions(-) diff --git a/package.json b/package.json index 6b6dbbe46..9ee57afa5 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "build:css:watch": "sass ./resources/sass:./public/dist --watch --embed-sources", "build:css:production": "sass ./resources/sass:./public/dist -s compressed", "build:js:dev": "node dev/build/esbuild.js", - "build:js:watch": "chokidar --initial \"./resources/**/*.js\" -c \"npm run build:js:dev\"", + "build:js:watch": "chokidar --initial \"./resources/**/*.js\" \"./resources/**/*.mjs\" -c \"npm run build:js:dev\"", "build:js:production": "node dev/build/esbuild.js production", "build": "npm-run-all --parallel build:*:dev", "production": "npm-run-all --parallel build:*:production", diff --git a/resources/js/code/index.mjs b/resources/js/code/index.mjs index 6ef659994..6cad052f4 100644 --- a/resources/js/code/index.mjs +++ b/resources/js/code/index.mjs @@ -2,7 +2,7 @@ import {EditorView} from "@codemirror/view" import Clipboard from "clipboard/dist/clipboard.min"; // Modes -import {viewer} from "./setups.js"; +import {viewer, editor} from "./setups.js"; import {createView, updateViewLanguage} from "./views.js"; /** @@ -180,25 +180,31 @@ export function updateLayout(cmInstance) { /** * Get a CodeMirror instance to use for the markdown editor. * @param {HTMLElement} elem + * @param {function} onChange + * @param {object} domEventHandlers * @returns {*} */ -export function markdownEditor(elem) { +export function markdownEditor(elem, onChange, domEventHandlers) { const content = elem.textContent; - const config = { - value: content, - mode: "markdown", - lineNumbers: true, - lineWrapping: true, - theme: getTheme(), - scrollPastEnd: true, - }; - window.$events.emitPublic(elem, 'editor-markdown-cm::pre-init', {config}); + // TODO - Change to pass something else that's useful, probably extension array? + // window.$events.emitPublic(elem, 'editor-markdown-cm::pre-init', {config}); - return CodeMirror(function (elt) { - elem.parentNode.insertBefore(elt, elem); - elem.style.display = 'none'; - }, config); + const ev = createView({ + parent: elem.parentNode, + doc: content, + extensions: [ + ...editor('markdown'), + EditorView.updateListener.of((v) => { + onChange(v); + }), + EditorView.domEventHandlers(domEventHandlers), + ], + }); + + elem.style.display = 'none'; + + return ev; } /** @@ -206,6 +212,7 @@ export function markdownEditor(elem) { * @returns {string} */ export function getMetaKey() { - let mac = CodeMirror.keyMap["default"] == CodeMirror.keyMap.macDefault; + // TODO - Redo, Is needed? No CodeMirror instance to use. + const mac = CodeMirror.keyMap["default"] == CodeMirror.keyMap.macDefault; return mac ? "Cmd" : "Ctrl"; } \ No newline at end of file diff --git a/resources/js/code/setups.js b/resources/js/code/setups.js index e1a150856..00366ee5e 100644 --- a/resources/js/code/setups.js +++ b/resources/js/code/setups.js @@ -1,12 +1,12 @@ -import {keymap, highlightSpecialChars, drawSelection, highlightActiveLine, dropCursor, +import {EditorView, keymap, highlightSpecialChars, drawSelection, highlightActiveLine, dropCursor, rectangularSelection, lineNumbers, highlightActiveLineGutter} from "@codemirror/view" -import {defaultHighlightStyle, syntaxHighlighting, bracketMatching, - foldKeymap} from "@codemirror/language" +import {syntaxHighlighting, bracketMatching} from "@codemirror/language" import {defaultKeymap, history, historyKeymap} from "@codemirror/commands" import {EditorState} from "@codemirror/state" import {defaultLight} from "./themes"; +import {getLanguageExtension} from "./languages"; export function viewer() { return [ @@ -23,8 +23,27 @@ export function viewer() { keymap.of([ ...defaultKeymap, ...historyKeymap, - ...foldKeymap, ]), EditorState.readOnly.of(true), ]; +} + +export function editor(language) { + return [ + lineNumbers(), + highlightActiveLineGutter(), + highlightSpecialChars(), + history(), + drawSelection(), + dropCursor(), + syntaxHighlighting(defaultLight, {fallback: true}), + bracketMatching(), + rectangularSelection(), + highlightActiveLine(), + keymap.of([ + ...defaultKeymap, + ...historyKeymap, + ]), + getLanguageExtension(language, ''), + ]; } \ No newline at end of file diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js index 5cd92cae2..6b4682d1e 100644 --- a/resources/js/components/markdown-editor.js +++ b/resources/js/components/markdown-editor.js @@ -45,7 +45,8 @@ export class MarkdownEditor extends Component { window.$events.emitPublic(this.elem, 'editor-markdown::setup', { markdownIt: this.editor.markdown.getRenderer(), displayEl: this.display, - codeMirrorInstance: this.editor.cm, + // TODO + // codeMirrorInstance: this.editor.cm, }); } @@ -81,9 +82,10 @@ export class MarkdownEditor extends Component { }); // Refresh CodeMirror on container resize - const resizeDebounced = debounce(() => this.editor.cm.refresh(), 100, false); - const observer = new ResizeObserver(resizeDebounced); - observer.observe(this.elem); + // TODO + // const resizeDebounced = debounce(() => this.editor.cm.refresh(), 100, false); + // const observer = new ResizeObserver(resizeDebounced); + // observer.observe(this.elem); this.handleDividerDrag(); } @@ -102,7 +104,8 @@ export class MarkdownEditor extends Component { window.removeEventListener('pointerup', upListener); this.display.style.pointerEvents = null; document.body.style.userSelect = null; - this.editor.cm.refresh(); + // TODO + // this.editor.cm.refresh(); }; this.display.style.pointerEvents = 'none'; diff --git a/resources/js/markdown/actions.js b/resources/js/markdown/actions.js index 9faf43de3..666998723 100644 --- a/resources/js/markdown/actions.js +++ b/resources/js/markdown/actions.js @@ -13,7 +13,7 @@ export class Actions { } updateAndRender() { - const content = this.editor.cm.getValue(); + const content = this.editor.cm.state.doc.toString(); this.editor.config.inputEl.value = content; const html = this.editor.markdown.render(content); @@ -411,17 +411,17 @@ export class Actions { }); } - syncDisplayPosition() { + syncDisplayPosition(event) { // Thanks to http://liuhao.im/english/2015/11/10/the-sync-scroll-of-markdown-editor-in-javascript.html - const scroll = this.editor.cm.getScrollInfo(); - const atEnd = scroll.top + scroll.clientHeight === scroll.height; + const scrollEl = event.target; + const atEnd = Math.abs(scrollEl.scrollHeight - scrollEl.clientHeight - scrollEl.scrollTop) < 1; if (atEnd) { this.editor.display.scrollToIndex(-1); return; } - const lineNum = this.editor.cm.lineAtHeight(scroll.top, 'local'); - const range = this.editor.cm.getRange({line: 0, ch: null}, {line: lineNum, ch: null}); + const blockInfo = this.editor.cm.lineBlockAtHeight(scrollEl.scrollTop); + const range = this.editor.cm.state.sliceDoc(0, blockInfo.from); const parser = new DOMParser(); const doc = parser.parseFromString(this.editor.markdown.render(range), 'text/html'); const totalLines = doc.documentElement.querySelectorAll('body > *'); diff --git a/resources/js/markdown/codemirror.js b/resources/js/markdown/codemirror.js index 8724a23c8..dad999e7a 100644 --- a/resources/js/markdown/codemirror.js +++ b/resources/js/markdown/codemirror.js @@ -9,62 +9,71 @@ import Clipboard from "../services/clipboard"; */ export async function init(editor) { const Code = await window.importVersioned('code'); - const cm = Code.markdownEditor(editor.config.inputEl); - // Will force to remain as ltr for now due to issues when HTML is in editor. - cm.setOption('direction', 'ltr'); - // Register shortcuts - cm.setOption('extraKeys', provideShortcuts(editor, Code.getMetaKey())); + /** + * @param {ViewUpdate} v + */ + function onViewUpdate(v) { + if (v.docChanged) { + editor.actions.updateAndRender(); + } + } - - // Register codemirror events - - // Update data on content change - cm.on('change', (instance, changeObj) => editor.actions.updateAndRender()); - - // Handle scroll to sync display view const onScrollDebounced = debounce(editor.actions.syncDisplayPosition.bind(editor.actions), 100, false); let syncActive = editor.settings.get('scrollSync'); editor.settings.onChange('scrollSync', val => syncActive = val); - cm.on('scroll', instance => { - if (syncActive) { - onScrollDebounced(instance); - } - }); + + const domEventHandlers = { + // Handle scroll to sync display view + scroll: (event) => syncActive && onScrollDebounced(event) + } + + const cm = Code.markdownEditor(editor.config.inputEl, onViewUpdate, domEventHandlers); + window.cm = cm; + + // Will force to remain as ltr for now due to issues when HTML is in editor. + // TODO + // cm.setOption('direction', 'ltr'); + // Register shortcuts + // TODO + // cm.setOption('extraKeys', provideShortcuts(editor, Code.getMetaKey())); + // Handle image paste - cm.on('paste', (cm, event) => { - const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); - - // Don't handle the event ourselves if no items exist of contains table-looking data - if (!clipboard.hasItems() || clipboard.containsTabularData()) { - return; - } - - const images = clipboard.getImages(); - for (const image of images) { - editor.actions.uploadImage(image); - } - }); + // TODO + // cm.on('paste', (cm, event) => { + // const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); + // + // // Don't handle the event ourselves if no items exist of contains table-looking data + // if (!clipboard.hasItems() || clipboard.containsTabularData()) { + // return; + // } + // + // const images = clipboard.getImages(); + // for (const image of images) { + // editor.actions.uploadImage(image); + // } + // }); // Handle image & content drag n drop - cm.on('drop', (cm, event) => { - - const templateId = event.dataTransfer.getData('bookstack/template'); - if (templateId) { - event.preventDefault(); - editor.actions.insertTemplate(templateId, event.pageX, event.pageY); - } - - const clipboard = new Clipboard(event.dataTransfer); - const clipboardImages = clipboard.getImages(); - if (clipboardImages.length > 0) { - event.stopPropagation(); - event.preventDefault(); - editor.actions.insertClipboardImages(clipboardImages); - } - - }); + // TODO + // cm.on('drop', (cm, event) => { + // + // const templateId = event.dataTransfer.getData('bookstack/template'); + // if (templateId) { + // event.preventDefault(); + // editor.actions.insertTemplate(templateId, event.pageX, event.pageY); + // } + // + // const clipboard = new Clipboard(event.dataTransfer); + // const clipboardImages = clipboard.getImages(); + // if (clipboardImages.length > 0) { + // event.stopPropagation(); + // event.preventDefault(); + // editor.actions.insertClipboardImages(clipboardImages); + // } + // + // }); return cm; } \ No newline at end of file diff --git a/resources/sass/_forms.scss b/resources/sass/_forms.scss index b7fc52f7d..b7b1b6d4d 100644 --- a/resources/sass/_forms.scss +++ b/resources/sass/_forms.scss @@ -82,6 +82,10 @@ flex-grow: 0; } +.markdown-editor-wrap .cm-editor { + flex: 1; +} + .markdown-panel-divider { width: 2px; @include lightDark(background-color, #ddd, #000); From da3e4f5f75d2012bc4e0eaac358a196d99ab3fbb Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 11 Apr 2023 11:48:58 +0100 Subject: [PATCH 09/22] Got md shortcuts working, marked actions for update --- resources/js/code/index.mjs | 16 ++---- resources/js/components/markdown-editor.js | 4 +- resources/js/markdown/actions.js | 35 +++++++++++- resources/js/markdown/codemirror.js | 12 ++-- resources/js/markdown/shortcuts.js | 65 ++++++++++++---------- 5 files changed, 84 insertions(+), 48 deletions(-) diff --git a/resources/js/code/index.mjs b/resources/js/code/index.mjs index 6cad052f4..3fe4a6d86 100644 --- a/resources/js/code/index.mjs +++ b/resources/js/code/index.mjs @@ -1,4 +1,4 @@ -import {EditorView} from "@codemirror/view" +import {EditorView, keymap} from "@codemirror/view" import Clipboard from "clipboard/dist/clipboard.min"; // Modes @@ -182,9 +182,10 @@ export function updateLayout(cmInstance) { * @param {HTMLElement} elem * @param {function} onChange * @param {object} domEventHandlers + * @param {Array} keyBindings * @returns {*} */ -export function markdownEditor(elem, onChange, domEventHandlers) { +export function markdownEditor(elem, onChange, domEventHandlers, keyBindings) { const content = elem.textContent; // TODO - Change to pass something else that's useful, probably extension array? @@ -199,20 +200,11 @@ export function markdownEditor(elem, onChange, domEventHandlers) { onChange(v); }), EditorView.domEventHandlers(domEventHandlers), + keymap.of(keyBindings), ], }); elem.style.display = 'none'; return ev; -} - -/** - * Get the 'meta' key dependent on the user's system. - * @returns {string} - */ -export function getMetaKey() { - // TODO - Redo, Is needed? No CodeMirror instance to use. - const mac = CodeMirror.keyMap["default"] == CodeMirror.keyMap.macDefault; - return mac ? "Cmd" : "Ctrl"; } \ No newline at end of file diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js index 6b4682d1e..922916701 100644 --- a/resources/js/components/markdown-editor.js +++ b/resources/js/components/markdown-editor.js @@ -45,7 +45,7 @@ export class MarkdownEditor extends Component { window.$events.emitPublic(this.elem, 'editor-markdown::setup', { markdownIt: this.editor.markdown.getRenderer(), displayEl: this.display, - // TODO + // TODO - change to codeMirrorView? // codeMirrorInstance: this.editor.cm, }); } @@ -58,7 +58,7 @@ export class MarkdownEditor extends Component { if (button === null) return; const action = button.getAttribute('data-action'); - if (action === 'insertImage') this.editor.actions.insertImage(); + if (action === 'insertImage') this.editor.actions.showImageInsert(); if (action === 'insertLink') this.editor.actions.showLinkSelector(); if (action === 'insertDrawing' && (event.ctrlKey || event.metaKey)) { this.editor.actions.showImageManager(); diff --git a/resources/js/markdown/actions.js b/resources/js/markdown/actions.js index 666998723..dfbe89c5a 100644 --- a/resources/js/markdown/actions.js +++ b/resources/js/markdown/actions.js @@ -28,7 +28,8 @@ export class Actions { return this.lastContent; } - insertImage() { + showImageInsert() { + // TODO const cursorPos = this.editor.cm.getCursor('from'); /** @type {ImageManager} **/ const imageManager = window.$components.first('image-manager'); @@ -42,7 +43,17 @@ export class Actions { }, 'gallery'); } + insertImage() { + // TODO + const selectedText = this.editor.cm.getSelection(); + const newText = `![${selectedText}](http://)`; + const cursorPos = this.editor.cm.getCursor('from'); + this.editor.cm.replaceSelection(newText); + this.editor.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length -1); + } + insertLink() { + // TODO const cursorPos = this.editor.cm.getCursor('from'); const selectedText = this.editor.cm.getSelection() || ''; const newText = `[${selectedText}]()`; @@ -53,6 +64,7 @@ export class Actions { } showImageManager() { + // TODO const cursorPos = this.editor.cm.getCursor('from'); /** @type {ImageManager} **/ const imageManager = window.$components.first('image-manager'); @@ -63,6 +75,7 @@ export class Actions { // Show the popup link selector and insert a link when finished showLinkSelector() { + // TODO const cursorPos = this.editor.cm.getCursor('from'); /** @type {EntitySelectorPopup} **/ const selector = window.$components.first('entity-selector-popup'); @@ -77,6 +90,7 @@ export class Actions { // Show draw.io if enabled and handle save. startDrawing() { + // TODO const url = this.editor.config.drawioUrl; if (!url) return; @@ -101,6 +115,7 @@ export class Actions { } insertDrawing(image, originalCursor) { + // TODO const newText = `
`; this.editor.cm.focus(); this.editor.cm.replaceSelection(newText); @@ -109,6 +124,7 @@ export class Actions { // Show draw.io if enabled and handle save. editDrawing(imgContainer) { + // TODO const drawioUrl = this.editor.config.drawioUrl; if (!drawioUrl) { return; @@ -145,6 +161,7 @@ export class Actions { } handleDrawingUploadError(error) { + // TODO if (error.status === 413) { window.$events.emit('error', this.editor.config.text.serverUploadLimit); } else { @@ -155,6 +172,7 @@ export class Actions { // Make the editor full screen fullScreen() { + // TODO const container = this.editor.config.container; const alreadyFullscreen = container.classList.contains('fullscreen'); container.classList.toggle('fullscreen', !alreadyFullscreen); @@ -163,6 +181,7 @@ export class Actions { // Scroll to a specified text scrollToText(searchText) { + // TODO if (!searchText) { return; } @@ -189,6 +208,7 @@ export class Actions { } focus() { + // TODO this.editor.cm.focus(); } @@ -197,6 +217,7 @@ export class Actions { * @param {String} content */ insertContent(content) { + // TODO this.editor.cm.replaceSelection(content); } @@ -205,6 +226,7 @@ export class Actions { * @param {String} content */ prependContent(content) { + // TODO const cursorPos = this.editor.cm.getCursor('from'); const newContent = content + '\n' + this.editor.cm.getValue(); this.editor.cm.setValue(newContent); @@ -217,6 +239,7 @@ export class Actions { * @param {String} content */ appendContent(content) { + // TODO const cursorPos = this.editor.cm.getCursor('from'); const newContent = this.editor.cm.getValue() + '\n' + content; this.editor.cm.setValue(newContent); @@ -228,6 +251,7 @@ export class Actions { * @param {String} content */ replaceContent(content) { + // TODO this.editor.cm.setValue(content); } @@ -236,6 +260,7 @@ export class Actions { * @param {String} replace */ findAndReplaceContent(search, replace) { + // TODO const text = this.editor.cm.getValue(); const cursor = this.editor.cm.listSelections(); this.editor.cm.setValue(text.replace(search, replace)); @@ -247,6 +272,7 @@ export class Actions { * @param {String} newStart */ replaceLineStart(newStart) { + // TODO const cursor = this.editor.cm.getCursor(); let lineContent = this.editor.cm.getLine(cursor.line); const lineLen = lineContent.length; @@ -279,6 +305,7 @@ export class Actions { * @param {String} end */ wrapLine(start, end) { + // TODO const cursor = this.editor.cm.getCursor(); const lineContent = this.editor.cm.getLine(cursor.line); const lineLen = lineContent.length; @@ -300,6 +327,7 @@ export class Actions { * @param {String} end */ wrapSelection(start, end) { + // TODO const selection = this.editor.cm.getSelection(); if (selection === '') return this.wrapLine(start, end); @@ -324,6 +352,7 @@ export class Actions { } replaceLineStartForOrderedList() { + // TODO const cursor = this.editor.cm.getCursor(); const prevLineContent = this.editor.cm.getLine(cursor.line - 1) || ''; const listMatch = prevLineContent.match(/^(\s*)(\d)([).])\s/) || []; @@ -341,6 +370,7 @@ export class Actions { * Creates a callout block if none existing, and removes it if cycling past the danger type. */ cycleCalloutTypeAtSelection() { + // TODO const selectionRange = this.editor.cm.listSelections()[0]; const lineContent = this.editor.cm.getLine(selectionRange.anchor.line); const lineLength = lineContent.length; @@ -379,6 +409,7 @@ export class Actions { * @param {File} file */ uploadImage(file) { + // TODO if (file === null || file.type.indexOf('image') !== 0) return; let ext = 'png'; @@ -436,6 +467,7 @@ export class Actions { * @param {Number} posY */ insertTemplate(templateId, posX, posY) { + // TODO const cursorPos = this.editor.cm.coordsChar({left: posX, top: posY}); this.editor.cm.setCursor(cursorPos); window.$http.get(`/templates/${templateId}`).then(resp => { @@ -449,6 +481,7 @@ export class Actions { * @param {File[]} images */ insertClipboardImages(images) { + // TODO const cursorPos = this.editor.cm.coordsChar({left: event.pageX, top: event.pageY}); this.editor.cm.setCursor(cursorPos); for (const image of images) { diff --git a/resources/js/markdown/codemirror.js b/resources/js/markdown/codemirror.js index dad999e7a..cd620137d 100644 --- a/resources/js/markdown/codemirror.js +++ b/resources/js/markdown/codemirror.js @@ -1,4 +1,4 @@ -import {provide as provideShortcuts} from "./shortcuts"; +import {provideKeyBindings} from "./shortcuts"; import {debounce} from "../services/util"; import Clipboard from "../services/clipboard"; @@ -28,15 +28,17 @@ export async function init(editor) { scroll: (event) => syncActive && onScrollDebounced(event) } - const cm = Code.markdownEditor(editor.config.inputEl, onViewUpdate, domEventHandlers); + const cm = Code.markdownEditor( + editor.config.inputEl, + onViewUpdate, + domEventHandlers, + provideKeyBindings(editor), + ); window.cm = cm; // Will force to remain as ltr for now due to issues when HTML is in editor. // TODO // cm.setOption('direction', 'ltr'); - // Register shortcuts - // TODO - // cm.setOption('extraKeys', provideShortcuts(editor, Code.getMetaKey())); // Handle image paste diff --git a/resources/js/markdown/shortcuts.js b/resources/js/markdown/shortcuts.js index 17ffe2fb3..08841e6c2 100644 --- a/resources/js/markdown/shortcuts.js +++ b/resources/js/markdown/shortcuts.js @@ -1,48 +1,57 @@ /** - * Provide shortcuts for the given codemirror instance. + * Provide shortcuts for the editor instance. * @param {MarkdownEditor} editor - * @param {String} metaKey * @returns {Object} */ -export function provide(editor, metaKey) { +function provide(editor) { const shortcuts = {}; // Insert Image shortcut - shortcuts[`${metaKey}-Alt-I`] = function(cm) { - const selectedText = cm.getSelection(); - const newText = `![${selectedText}](http://)`; - const cursorPos = cm.getCursor('from'); - cm.replaceSelection(newText); - cm.setCursor(cursorPos.line, cursorPos.ch + newText.length -1); - }; + shortcuts['Mod-Alt-i'] = () => editor.actions.insertImage(); // Save draft - shortcuts[`${metaKey}-S`] = cm => window.$events.emit('editor-save-draft'); + shortcuts['Mod-s'] = cm => window.$events.emit('editor-save-draft'); // Save page - shortcuts[`${metaKey}-Enter`] = cm => window.$events.emit('editor-save-page'); + shortcuts['Mod-Enter'] = cm => window.$events.emit('editor-save-page'); // Show link selector - shortcuts[`Shift-${metaKey}-K`] = cm => editor.actions.showLinkSelector(); + shortcuts['Shift-Mod-k'] = cm => editor.actions.showLinkSelector(); // Insert Link - shortcuts[`${metaKey}-K`] = cm => editor.actions.insertLink(); + shortcuts['Mod-k'] = cm => editor.actions.insertLink(); // FormatShortcuts - shortcuts[`${metaKey}-1`] = cm => editor.actions.replaceLineStart('##'); - shortcuts[`${metaKey}-2`] = cm => editor.actions.replaceLineStart('###'); - shortcuts[`${metaKey}-3`] = cm => editor.actions.replaceLineStart('####'); - shortcuts[`${metaKey}-4`] = cm => editor.actions.replaceLineStart('#####'); - shortcuts[`${metaKey}-5`] = cm => editor.actions.replaceLineStart(''); - shortcuts[`${metaKey}-D`] = cm => editor.actions.replaceLineStart(''); - shortcuts[`${metaKey}-6`] = cm => editor.actions.replaceLineStart('>'); - shortcuts[`${metaKey}-Q`] = cm => editor.actions.replaceLineStart('>'); - shortcuts[`${metaKey}-7`] = cm => editor.actions.wrapSelection('\n```\n', '\n```'); - shortcuts[`${metaKey}-8`] = cm => editor.actions.wrapSelection('`', '`'); - shortcuts[`Shift-${metaKey}-E`] = cm => editor.actions.wrapSelection('`', '`'); - shortcuts[`${metaKey}-9`] = cm => editor.actions.cycleCalloutTypeAtSelection(); - shortcuts[`${metaKey}-P`] = cm => editor.actions.replaceLineStart('-') - shortcuts[`${metaKey}-O`] = cm => editor.actions.replaceLineStartForOrderedList() + shortcuts['Mod-1'] = cm => editor.actions.replaceLineStart('##'); + shortcuts['Mod-2'] = cm => editor.actions.replaceLineStart('###'); + shortcuts['Mod-3'] = cm => editor.actions.replaceLineStart('####'); + shortcuts['Mod-4'] = cm => editor.actions.replaceLineStart('#####'); + shortcuts['Mod-5'] = cm => editor.actions.replaceLineStart(''); + shortcuts['Mod-d'] = cm => editor.actions.replaceLineStart(''); + shortcuts['Mod-6'] = cm => editor.actions.replaceLineStart('>'); + shortcuts['Mod-q'] = cm => editor.actions.replaceLineStart('>'); + shortcuts['Mod-7'] = cm => editor.actions.wrapSelection('\n```\n', '\n```'); + shortcuts['Mod-8'] = cm => editor.actions.wrapSelection('`', '`'); + shortcuts['Shift-Mod-e'] = cm => editor.actions.wrapSelection('`', '`'); + shortcuts['Mod-9'] = cm => editor.actions.cycleCalloutTypeAtSelection(); + shortcuts['Mod-p'] = cm => editor.actions.replaceLineStart('-') + shortcuts['Mod-o'] = cm => editor.actions.replaceLineStartForOrderedList() return shortcuts; +} + +/** + * Get the editor shortcuts in CodeMirror keybinding format. + * @param {MarkdownEditor} editor + * @return {{key: String, run: function, preventDefault: boolean}[]} + */ +export function provideKeyBindings(editor) { + const shortcuts= provide(editor); + const keyBindings = []; + + for (const [shortcut, action] of Object.entries(shortcuts)) { + keyBindings.push({key: shortcut, run: action, preventDefault: true}); + } + + return keyBindings; } \ No newline at end of file From 9813c9472098453ff04352b9a454c5e923e695e3 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Tue, 11 Apr 2023 13:16:04 +0100 Subject: [PATCH 10/22] Made a start on updating editor actions --- resources/js/markdown/actions.js | 209 +++++++++++++++-------------- resources/js/markdown/editor.js | 2 +- resources/js/markdown/shortcuts.js | 2 +- resources/sass/_codemirror.scss | 5 + 4 files changed, 118 insertions(+), 100 deletions(-) diff --git a/resources/js/markdown/actions.js b/resources/js/markdown/actions.js index dfbe89c5a..15f1c1e7f 100644 --- a/resources/js/markdown/actions.js +++ b/resources/js/markdown/actions.js @@ -29,72 +29,57 @@ export class Actions { } showImageInsert() { - // TODO - const cursorPos = this.editor.cm.getCursor('from'); /** @type {ImageManager} **/ const imageManager = window.$components.first('image-manager'); + imageManager.show(image => { const imageUrl = image.thumbs.display || image.url; - let selectedText = this.editor.cm.getSelection(); - let newText = "[![" + (selectedText || image.name) + "](" + imageUrl + ")](" + image.url + ")"; - this.editor.cm.focus(); - this.editor.cm.replaceSelection(newText); - this.editor.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length); + const selectedText = this.#getSelectionText(); + const newText = "[![" + (selectedText || image.name) + "](" + imageUrl + ")](" + image.url + ")"; + this.#replaceSelection(newText, newText.length); }, 'gallery'); } insertImage() { - // TODO - const selectedText = this.editor.cm.getSelection(); - const newText = `![${selectedText}](http://)`; - const cursorPos = this.editor.cm.getCursor('from'); - this.editor.cm.replaceSelection(newText); - this.editor.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length -1); + const newText = `![${this.#getSelectionText()}](http://)`; + this.#replaceSelection(newText, newText.length - 1); } insertLink() { - // TODO - const cursorPos = this.editor.cm.getCursor('from'); - const selectedText = this.editor.cm.getSelection() || ''; + const selectedText = this.#getSelectionText(); const newText = `[${selectedText}]()`; - this.editor.cm.focus(); - this.editor.cm.replaceSelection(newText); const cursorPosDiff = (selectedText === '') ? -3 : -1; - this.editor.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length+cursorPosDiff); + this.#replaceSelection(newText, newText.length+cursorPosDiff); } showImageManager() { - // TODO - const cursorPos = this.editor.cm.getCursor('from'); + const selectionRange = this.#getSelectionRange(); /** @type {ImageManager} **/ const imageManager = window.$components.first('image-manager'); imageManager.show(image => { - this.insertDrawing(image, cursorPos); + this.#insertDrawing(image, selectionRange); }, 'drawio'); } // Show the popup link selector and insert a link when finished showLinkSelector() { - // TODO - const cursorPos = this.editor.cm.getCursor('from'); + const selectionRange = this.#getSelectionRange(); + /** @type {EntitySelectorPopup} **/ const selector = window.$components.first('entity-selector-popup'); selector.show(entity => { - let selectedText = this.editor.cm.getSelection() || entity.name; - let newText = `[${selectedText}](${entity.link})`; - this.editor.cm.focus(); - this.editor.cm.replaceSelection(newText); - this.editor.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length); + const selectedText = this.#getSelectionText(selectionRange) || entity.name; + const newText = `[${selectedText}](${entity.link})`; + this.#replaceSelection(newText, newText.length, selectionRange); }); } // Show draw.io if enabled and handle save. startDrawing() { - // TODO const url = this.editor.config.drawioUrl; if (!url) return; - const cursorPos = this.editor.cm.getCursor('from'); + const selectionRange = this.#getSelectionRange(); DrawIO.show(url,() => { return Promise.resolve(''); @@ -106,7 +91,7 @@ export class Actions { }; window.$http.post("/images/drawio", data).then(resp => { - this.insertDrawing(resp.data, cursorPos); + this.#insertDrawing(resp.data, selectionRange); DrawIO.close(); }).catch(err => { this.handleDrawingUploadError(err); @@ -114,12 +99,9 @@ export class Actions { }); } - insertDrawing(image, originalCursor) { - // TODO + #insertDrawing(image, originalSelectionRange) { const newText = `
`; - this.editor.cm.focus(); - this.editor.cm.replaceSelection(newText); - this.editor.cm.setCursor(originalCursor.line, originalCursor.ch + newText.length); + this.#replaceSelection(newText, newText.length, originalSelectionRange); } // Show draw.io if enabled and handle save. @@ -161,7 +143,6 @@ export class Actions { } handleDrawingUploadError(error) { - // TODO if (error.status === 413) { window.$events.emit('error', this.editor.config.text.serverUploadLimit); } else { @@ -172,7 +153,6 @@ export class Actions { // Make the editor full screen fullScreen() { - // TODO const container = this.editor.config.container; const alreadyFullscreen = container.classList.contains('fullscreen'); container.classList.toggle('fullscreen', !alreadyFullscreen); @@ -181,35 +161,37 @@ export class Actions { // Scroll to a specified text scrollToText(searchText) { - // TODO if (!searchText) { return; } - const content = this.editor.cm.getValue(); - const lines = content.split(/\r?\n/); - let lineNumber = lines.findIndex(line => { - return line && line.indexOf(searchText) !== -1; - }); + const text = this.editor.cm.state.doc; + let lineCount = 1; + let scrollToLine = -1; + for (const line of text.iterLines()) { + if (line.includes(searchText)) { + scrollToLine = lineCount; + break; + } + lineCount++; + } - if (lineNumber === -1) { + if (scrollToLine === -1) { return; } - this.editor.cm.scrollIntoView({ - line: lineNumber, - }, 200); - this.editor.cm.focus(); - // set the cursor location. - this.editor.cm.setCursor({ - line: lineNumber, - char: lines[lineNumber].length - }) + const line = text.line(scrollToLine); + this.editor.cm.dispatch({ + selection: {anchor: line.from, head: line.to}, + scrollIntoView: true, + }); + this.focus(); } focus() { - // TODO - this.editor.cm.focus(); + if (!this.editor.cm.hasFocus) { + this.editor.cm.focus(); + } } /** @@ -217,8 +199,7 @@ export class Actions { * @param {String} content */ insertContent(content) { - // TODO - this.editor.cm.replaceSelection(content); + this.#replaceSelection(content, content.length); } /** @@ -404,44 +385,6 @@ export class Actions { } } - /** - * Handle image upload and add image into markdown content - * @param {File} file - */ - uploadImage(file) { - // TODO - if (file === null || file.type.indexOf('image') !== 0) return; - let ext = 'png'; - - if (file.name) { - let fileNameMatches = file.name.match(/\.(.+)$/); - if (fileNameMatches.length > 1) ext = fileNameMatches[1]; - } - - // Insert image into markdown - const id = "image-" + Math.random().toString(16).slice(2); - const placeholderImage = window.baseUrl(`/loading.gif#upload${id}`); - const selectedText = this.editor.cm.getSelection(); - const placeHolderText = `![${selectedText}](${placeholderImage})`; - const cursor = this.editor.cm.getCursor(); - this.editor.cm.replaceSelection(placeHolderText); - this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch + selectedText.length + 3}); - - const remoteFilename = "image-" + Date.now() + "." + ext; - const formData = new FormData(); - formData.append('file', file, remoteFilename); - formData.append('uploaded_to', this.editor.config.pageId); - - window.$http.post('/images/gallery', formData).then(resp => { - const newContent = `[![${selectedText}](${resp.data.thumbs.display})](${resp.data.url})`; - this.findAndReplaceContent(placeHolderText, newContent); - }).catch(err => { - window.$events.emit('error', this.editor.config.text.imageUploadError); - this.findAndReplaceContent(placeHolderText, selectedText); - console.log(err); - }); - } - syncDisplayPosition(event) { // Thanks to http://liuhao.im/english/2015/11/10/the-sync-scroll-of-markdown-editor-in-javascript.html const scrollEl = event.target; @@ -485,7 +428,77 @@ export class Actions { const cursorPos = this.editor.cm.coordsChar({left: event.pageX, top: event.pageY}); this.editor.cm.setCursor(cursorPos); for (const image of images) { - this.uploadImage(image); + this.#uploadImage(image); } } + + /** + * Handle image upload and add image into markdown content + * @param {File} file + */ + #uploadImage(file) { + // TODO + if (file === null || file.type.indexOf('image') !== 0) return; + let ext = 'png'; + + if (file.name) { + let fileNameMatches = file.name.match(/\.(.+)$/); + if (fileNameMatches.length > 1) ext = fileNameMatches[1]; + } + + // Insert image into markdown + const id = "image-" + Math.random().toString(16).slice(2); + const placeholderImage = window.baseUrl(`/loading.gif#upload${id}`); + const selectedText = this.editor.cm.getSelection(); + const placeHolderText = `![${selectedText}](${placeholderImage})`; + const cursor = this.editor.cm.getCursor(); + this.editor.cm.replaceSelection(placeHolderText); + this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch + selectedText.length + 3}); + + const remoteFilename = "image-" + Date.now() + "." + ext; + const formData = new FormData(); + formData.append('file', file, remoteFilename); + formData.append('uploaded_to', this.editor.config.pageId); + + window.$http.post('/images/gallery', formData).then(resp => { + const newContent = `[![${selectedText}](${resp.data.thumbs.display})](${resp.data.url})`; + this.findAndReplaceContent(placeHolderText, newContent); + }).catch(err => { + window.$events.emit('error', this.editor.config.text.imageUploadError); + this.findAndReplaceContent(placeHolderText, selectedText); + console.log(err); + }); + } + + /** + * Replace the current selection and focus the editor. + * Takes an offset for the cursor, after the change, relative to the start of the provided string. + * Can be provided a selection range to use instead of the current selection range. + * @param {String} newContent + * @param {Number} cursorOffset + * @param {?SelectionRange} selectionRange + */ + #replaceSelection(newContent, cursorOffset = 0, selectionRange = null) { + selectionRange = selectionRange || this.editor.cm.state.selection.main; + this.editor.cm.dispatch({ + changes: {from: selectionRange.from, to: selectionRange.to, insert: newContent}, + selection: {anchor: selectionRange.from + cursorOffset}, + }); + + this.focus(); + } + + /** + * Get the text content of the main current selection. + * @param {SelectionRange} selectionRange + * @return {string} + */ + #getSelectionText(selectionRange = null) { + selectionRange = selectionRange || this.#getSelectionRange(); + return this.editor.cm.state.sliceDoc(selectionRange.from, selectionRange.to); + } + + #getSelectionRange() { + return this.editor.cm.state.selection.main; + } } \ No newline at end of file diff --git a/resources/js/markdown/editor.js b/resources/js/markdown/editor.js index 1cf4cef2b..cb5bf7d1a 100644 --- a/resources/js/markdown/editor.js +++ b/resources/js/markdown/editor.js @@ -49,6 +49,6 @@ export async function init(config) { * @property {Display} display * @property {Markdown} markdown * @property {Actions} actions - * @property {CodeMirror} cm + * @property {EditorView} cm * @property {Settings} settings */ \ No newline at end of file diff --git a/resources/js/markdown/shortcuts.js b/resources/js/markdown/shortcuts.js index 08841e6c2..336b276d1 100644 --- a/resources/js/markdown/shortcuts.js +++ b/resources/js/markdown/shortcuts.js @@ -7,7 +7,7 @@ function provide(editor) { const shortcuts = {}; // Insert Image shortcut - shortcuts['Mod-Alt-i'] = () => editor.actions.insertImage(); + shortcuts['Mod-Alt-i'] = cm => editor.actions.insertImage(); // Save draft shortcuts['Mod-s'] = cm => window.$events.emit('editor-save-draft'); diff --git a/resources/sass/_codemirror.scss b/resources/sass/_codemirror.scss index 330923d4f..1dee39cd2 100644 --- a/resources/sass/_codemirror.scss +++ b/resources/sass/_codemirror.scss @@ -412,6 +412,11 @@ span.CodeMirror-selectedtext { background: none; } /** * Custom BookStack overrides */ +.cm-editor { + @include lightDark(background-color, #FFF, #000); +} + +// TODO - All below are old .CodeMirror, .CodeMirror pre { font-size: 12px; } From 32c765d0c3ef0be89e10f9e38b13e4f82b3fd6c3 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 13 Apr 2023 12:51:52 +0100 Subject: [PATCH 11/22] Updated another range of actions for cm6 --- resources/js/markdown/actions.js | 212 ++++++++++++++++++------------- resources/sass/_forms.scss | 2 + 2 files changed, 126 insertions(+), 88 deletions(-) diff --git a/resources/js/markdown/actions.js b/resources/js/markdown/actions.js index 15f1c1e7f..d140bb284 100644 --- a/resources/js/markdown/actions.js +++ b/resources/js/markdown/actions.js @@ -13,7 +13,7 @@ export class Actions { } updateAndRender() { - const content = this.editor.cm.state.doc.toString(); + const content = this.#getText(); this.editor.config.inputEl.value = content; const html = this.editor.markdown.render(content); @@ -106,13 +106,12 @@ export class Actions { // Show draw.io if enabled and handle save. editDrawing(imgContainer) { - // TODO const drawioUrl = this.editor.config.drawioUrl; if (!drawioUrl) { return; } - const cursorPos = this.editor.cm.getCursor('from'); + const selectionRange = this.#getSelectionRange(); const drawingId = imgContainer.getAttribute('drawio-diagram'); DrawIO.show(drawioUrl, () => { @@ -126,15 +125,13 @@ export class Actions { window.$http.post("/images/drawio", data).then(resp => { const newText = `
`; - const newContent = this.editor.cm.getValue().split('\n').map(line => { + const newContent = this.#getText().split('\n').map(line => { if (line.indexOf(`drawio-diagram="${drawingId}"`) !== -1) { return newText; } return line; }).join('\n'); - this.editor.cm.setValue(newContent); - this.editor.cm.setCursor(cursorPos); - this.editor.cm.focus(); + this.#setText(newContent, selectionRange); DrawIO.close(); }).catch(err => { this.handleDrawingUploadError(err); @@ -207,12 +204,13 @@ export class Actions { * @param {String} content */ prependContent(content) { - // TODO - const cursorPos = this.editor.cm.getCursor('from'); - const newContent = content + '\n' + this.editor.cm.getValue(); - this.editor.cm.setValue(newContent); - const prependLineCount = content.split('\n').length; - this.editor.cm.setCursor(cursorPos.line + prependLineCount, cursorPos.ch); + content = this.#cleanTextForEditor(content); + const selectionRange = this.#getSelectionRange(); + this.editor.cm.dispatch({ + changes: {from: 0, to: 0, insert: content + '\n'}, + selection: {anchor: selectionRange.from + content.length + 1} + }); + this.focus(); } /** @@ -220,11 +218,11 @@ export class Actions { * @param {String} content */ appendContent(content) { - // TODO - const cursorPos = this.editor.cm.getCursor('from'); - const newContent = this.editor.cm.getValue() + '\n' + content; - this.editor.cm.setValue(newContent); - this.editor.cm.setCursor(cursorPos.line, cursorPos.ch); + content = this.#cleanTextForEditor(content); + this.editor.cm.dispatch({ + changes: {from: this.editor.cm.state.doc.length, insert: '\n' + content}, + }); + this.focus(); } /** @@ -232,20 +230,7 @@ export class Actions { * @param {String} content */ replaceContent(content) { - // TODO - this.editor.cm.setValue(content); - } - - /** - * @param {String|RegExp} search - * @param {String} replace - */ - findAndReplaceContent(search, replace) { - // TODO - const text = this.editor.cm.getValue(); - const cursor = this.editor.cm.listSelections(); - this.editor.cm.setValue(text.replace(search, replace)); - this.editor.cm.setSelections(cursor); + this.#setText(content) } /** @@ -253,53 +238,34 @@ export class Actions { * @param {String} newStart */ replaceLineStart(newStart) { - // TODO - const cursor = this.editor.cm.getCursor(); - let lineContent = this.editor.cm.getLine(cursor.line); - const lineLen = lineContent.length; + const selectionRange = this.#getSelectionRange(); + const line = this.editor.cm.state.doc.lineAt(selectionRange.from); + + const lineContent = line.text; const lineStart = lineContent.split(' ')[0]; // Remove symbol if already set if (lineStart === newStart) { - lineContent = lineContent.replace(`${newStart} `, ''); - this.editor.cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen}); - this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch - (newStart.length + 1)}); + const newLineContent = lineContent.replace(`${newStart} `, ''); + this.editor.cm.dispatch({ + changes: {from: line.from, to: line.to, insert: newLineContent}, + selection: {anchor: selectionRange.from + (newLineContent.length - lineContent.length)} + }); return; } - const alreadySymbol = /^[#>`]/.test(lineStart); - let posDif = 0; - if (alreadySymbol) { - posDif = newStart.length - lineStart.length; - lineContent = lineContent.replace(lineStart, newStart).trim(); - } else if (newStart !== '') { - posDif = newStart.length + 1; - lineContent = newStart + ' ' + lineContent; - } - this.editor.cm.replaceRange(lineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen}); - this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch + posDif}); - } - - /** - * Wrap the line in the given start and end contents. - * @param {String} start - * @param {String} end - */ - wrapLine(start, end) { - // TODO - const cursor = this.editor.cm.getCursor(); - const lineContent = this.editor.cm.getLine(cursor.line); - const lineLen = lineContent.length; let newLineContent = lineContent; - - if (lineContent.indexOf(start) === 0 && lineContent.slice(-end.length) === end) { - newLineContent = lineContent.slice(start.length, lineContent.length - end.length); - } else { - newLineContent = `${start}${lineContent}${end}`; + const alreadySymbol = /^[#>`]/.test(lineStart); + if (alreadySymbol) { + newLineContent = lineContent.replace(lineStart, newStart).trim(); + } else if (newStart !== '') { + newLineContent = newStart + ' ' + lineContent; } - this.editor.cm.replaceRange(newLineContent, {line: cursor.line, ch: 0}, {line: cursor.line, ch: lineLen}); - this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch + start.length}); + this.editor.cm.dispatch({ + changes: {from: line.from, to: line.to, insert: newLineContent}, + selection: {anchor: selectionRange.from + (newLineContent.length - lineContent.length)} + }); } /** @@ -308,28 +274,25 @@ export class Actions { * @param {String} end */ wrapSelection(start, end) { - // TODO - const selection = this.editor.cm.getSelection(); - if (selection === '') return this.wrapLine(start, end); + const selectionRange = this.#getSelectionRange(); + const selectionText = this.#getSelectionText(selectionRange); + if (!selectionText) return this.#wrapLine(start, end); - let newSelection = selection; - const frontDiff = 0; - let endDiff; + let newSelectionText = selectionText; + let newRange; - if (selection.indexOf(start) === 0 && selection.slice(-end.length) === end) { - newSelection = selection.slice(start.length, selection.length - end.length); - endDiff = -(end.length + start.length); + if (selectionText.startsWith(start) && selectionText.endsWith(end)) { + newSelectionText = selectionText.slice(start.length, selectionText.length - end.length); + newRange = selectionRange.extend(selectionRange.from, selectionRange.to - (start.length + end.length)); } else { - newSelection = `${start}${selection}${end}`; - endDiff = start.length + end.length; + newSelectionText = `${start}${selectionText}${end}`; + newRange = selectionRange.extend(selectionRange.from, selectionRange.to + (start.length + end.length)); } - const selections = this.editor.cm.listSelections()[0]; - this.editor.cm.replaceSelection(newSelection); - const headFirst = selections.head.ch <= selections.anchor.ch; - selections.head.ch += headFirst ? frontDiff : endDiff; - selections.anchor.ch += headFirst ? endDiff : frontDiff; - this.editor.cm.setSelections([selections]); + this.editor.cm.dispatch({ + changes: {from: selectionRange.from, to: selectionRange.to, insert: newSelectionText}, + selection: {anchor: newRange.anchor, head: newRange.head}, + }); } replaceLineStartForOrderedList() { @@ -462,14 +425,37 @@ export class Actions { window.$http.post('/images/gallery', formData).then(resp => { const newContent = `[![${selectedText}](${resp.data.thumbs.display})](${resp.data.url})`; - this.findAndReplaceContent(placeHolderText, newContent); + this.#findAndReplaceContent(placeHolderText, newContent); }).catch(err => { window.$events.emit('error', this.editor.config.text.imageUploadError); - this.findAndReplaceContent(placeHolderText, selectedText); + this.#findAndReplaceContent(placeHolderText, selectedText); console.log(err); }); } + /** + * Get the current text of the editor instance. + * @return {string} + */ + #getText() { + return this.editor.cm.state.doc.toString(); + } + + /** + * Set the text of the current editor instance. + * @param {String} text + * @param {?SelectionRange} selectionRange + */ + #setText(text, selectionRange = null) { + selectionRange = selectionRange || this.#getSelectionRange(); + this.editor.cm.dispatch({ + changes: {from: 0, to: this.editor.cm.state.doc.length, insert: text}, + selection: {anchor: selectionRange.from}, + }); + + this.focus(); + } + /** * Replace the current selection and focus the editor. * Takes an offset for the cursor, after the change, relative to the start of the provided string. @@ -498,7 +484,57 @@ export class Actions { return this.editor.cm.state.sliceDoc(selectionRange.from, selectionRange.to); } + /** + * Get the range of the current main selection. + * @return {SelectionRange} + */ #getSelectionRange() { return this.editor.cm.state.selection.main; } + + /** + * Cleans the given text to work with the editor. + * Standardises line endings to what's expected. + * @param {String} text + * @return {String} + */ + #cleanTextForEditor(text) { + return text.replace(/\r\n|\r/g, "\n"); + } + + /** + * Find and replace the first occurrence of [search] with [replace] + * @param {String} search + * @param {String} replace + */ + #findAndReplaceContent(search, replace) { + const newText = this.#getText().replace(search, replace); + this.#setText(newText); + } + + /** + * Wrap the line in the given start and end contents. + * @param {String} start + * @param {String} end + */ + #wrapLine(start, end) { + const selectionRange = this.#getSelectionRange(); + const line = this.editor.cm.state.doc.lineAt(selectionRange.from); + const lineContent = line.text; + let newLineContent; + let lineOffset = 0; + + if (lineContent.startsWith(start) && lineContent.endsWith(end)) { + newLineContent = lineContent.slice(start.length, lineContent.length - end.length); + lineOffset = -(start.length); + } else { + newLineContent = `${start}${lineContent}${end}`; + lineOffset = start.length; + } + + this.editor.cm.dispatch({ + changes: {from: line.from, to: line.to, insert: newLineContent}, + selection: {anchor: selectionRange.from + lineOffset} + }); + } } \ No newline at end of file diff --git a/resources/sass/_forms.scss b/resources/sass/_forms.scss index b7b1b6d4d..84825ddc6 100644 --- a/resources/sass/_forms.scss +++ b/resources/sass/_forms.scss @@ -75,6 +75,7 @@ @include lightDark(border-color, #ddd, #000); position: relative; flex: 1; + min-width: 0; } .markdown-editor-wrap + .markdown-editor-wrap { flex-basis: 50%; @@ -84,6 +85,7 @@ .markdown-editor-wrap .cm-editor { flex: 1; + max-width: 100%; } .markdown-panel-divider { From 6f45d34bf8cba306477d5ab34ba2fdd8fbbe0d87 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 13 Apr 2023 17:18:32 +0100 Subject: [PATCH 12/22] Finished update pass of all md editor actions to cm6 --- resources/js/markdown/actions.js | 96 ++++++++++++++--------------- resources/js/markdown/codemirror.js | 69 ++++++++++----------- 2 files changed, 78 insertions(+), 87 deletions(-) diff --git a/resources/js/markdown/actions.js b/resources/js/markdown/actions.js index d140bb284..3aa6b5e81 100644 --- a/resources/js/markdown/actions.js +++ b/resources/js/markdown/actions.js @@ -296,10 +296,11 @@ export class Actions { } replaceLineStartForOrderedList() { - // TODO - const cursor = this.editor.cm.getCursor(); - const prevLineContent = this.editor.cm.getLine(cursor.line - 1) || ''; - const listMatch = prevLineContent.match(/^(\s*)(\d)([).])\s/) || []; + const selectionRange = this.#getSelectionRange(); + const line = this.editor.cm.state.doc.lineAt(selectionRange.from); + const prevLine = this.editor.cm.state.doc.line(line.number - 1); + + const listMatch = prevLine.text.match(/^(\s*)(\d)([).])\s/) || []; const number = (Number(listMatch[2]) || 0) + 1; const whiteSpace = listMatch[1] || ''; @@ -314,37 +315,28 @@ export class Actions { * Creates a callout block if none existing, and removes it if cycling past the danger type. */ cycleCalloutTypeAtSelection() { - // TODO - const selectionRange = this.editor.cm.listSelections()[0]; - const lineContent = this.editor.cm.getLine(selectionRange.anchor.line); - const lineLength = lineContent.length; - const contentRange = { - anchor: {line: selectionRange.anchor.line, ch: 0}, - head: {line: selectionRange.anchor.line, ch: lineLength}, - }; + const selectionRange = this.#getSelectionRange(); + const line = this.editor.cm.state.doc.lineAt(selectionRange.from); const formats = ['info', 'success', 'warning', 'danger']; const joint = formats.join('|'); const regex = new RegExp(`class="((${joint})\\s+callout|callout\\s+(${joint}))"`, 'i'); - const matches = regex.exec(lineContent); + const matches = regex.exec(line.text); const format = (matches ? (matches[2] || matches[3]) : '').toLowerCase(); if (format === formats[formats.length - 1]) { - this.wrapLine(`

`, '

'); + this.#wrapLine(`

`, '

'); } else if (format === '') { - this.wrapLine('

', '

'); + this.#wrapLine('

', '

'); } else { const newFormatIndex = formats.indexOf(format) + 1; const newFormat = formats[newFormatIndex]; - const newContent = lineContent.replace(matches[0], matches[0].replace(format, newFormat)); - this.editor.cm.replaceRange(newContent, contentRange.anchor, contentRange.head); - - const chDiff = newContent.length - lineContent.length; - selectionRange.anchor.ch += chDiff; - if (selectionRange.anchor !== selectionRange.head) { - selectionRange.head.ch += chDiff; - } - this.editor.cm.setSelection(selectionRange.anchor, selectionRange.head); + const newContent = line.text.replace(matches[0], matches[0].replace(format, newFormat)); + const lineDiff = newContent.length - line.text.length; + this.editor.cm.dispatch({ + changes: {from: line.from, to: line.to, insert: newContent}, + selection: {anchor: selectionRange.anchor + lineDiff, head: selectionRange.head + lineDiff}, + }); } } @@ -372,38 +364,43 @@ export class Actions { * @param {Number} posX * @param {Number} posY */ - insertTemplate(templateId, posX, posY) { - // TODO - const cursorPos = this.editor.cm.coordsChar({left: posX, top: posY}); - this.editor.cm.setCursor(cursorPos); - window.$http.get(`/templates/${templateId}`).then(resp => { - const content = resp.data.markdown || resp.data.html; - this.editor.cm.replaceSelection(content); + async insertTemplate(templateId, posX, posY) { + const cursorPos = this.editor.cm.posAtCoords({x: posX, y: posY}, false); + const {data} = await window.$http.get(`/templates/${templateId}`); + const content = data.markdown || data.html; + this.editor.cm.dispatch({ + changes: {from: cursorPos, to: cursorPos, insert: content}, + selection: {anchor: cursorPos}, }); } /** - * Insert multiple images from the clipboard. + * Insert multiple images from the clipboard from an event at the provided + * screen coordinates (Typically form a paste event). * @param {File[]} images + * @param {Number} posX + * @param {Number} posY */ - insertClipboardImages(images) { - // TODO - const cursorPos = this.editor.cm.coordsChar({left: event.pageX, top: event.pageY}); - this.editor.cm.setCursor(cursorPos); + insertClipboardImages(images, posX, posY) { + const cursorPos = this.editor.cm.posAtCoords({x: posX, y: posY}, false); for (const image of images) { - this.#uploadImage(image); + this.uploadImage(image, cursorPos); } } /** * Handle image upload and add image into markdown content * @param {File} file + * @param {?Number} position */ - #uploadImage(file) { - // TODO + async uploadImage(file, position= null) { if (file === null || file.type.indexOf('image') !== 0) return; let ext = 'png'; + if (position === null) { + position = this.#getSelectionRange().from; + } + if (file.name) { let fileNameMatches = file.name.match(/\.(.+)$/); if (fileNameMatches.length > 1) ext = fileNameMatches[1]; @@ -412,25 +409,26 @@ export class Actions { // Insert image into markdown const id = "image-" + Math.random().toString(16).slice(2); const placeholderImage = window.baseUrl(`/loading.gif#upload${id}`); - const selectedText = this.editor.cm.getSelection(); - const placeHolderText = `![${selectedText}](${placeholderImage})`; - const cursor = this.editor.cm.getCursor(); - this.editor.cm.replaceSelection(placeHolderText); - this.editor.cm.setCursor({line: cursor.line, ch: cursor.ch + selectedText.length + 3}); + const placeHolderText = `![](${placeholderImage})`; + this.editor.cm.dispatch({ + changes: {from: position, to: position, insert: placeHolderText}, + selection: {anchor: position}, + }); const remoteFilename = "image-" + Date.now() + "." + ext; const formData = new FormData(); formData.append('file', file, remoteFilename); formData.append('uploaded_to', this.editor.config.pageId); - window.$http.post('/images/gallery', formData).then(resp => { - const newContent = `[![${selectedText}](${resp.data.thumbs.display})](${resp.data.url})`; + try { + const {data} = await window.$http.post('/images/gallery', formData); + const newContent = `[![](${data.thumbs.display})](${data.url})`; this.#findAndReplaceContent(placeHolderText, newContent); - }).catch(err => { + } catch (err) { window.$events.emit('error', this.editor.config.text.imageUploadError); - this.#findAndReplaceContent(placeHolderText, selectedText); + this.#findAndReplaceContent(placeHolderText, ''); console.log(err); - }); + } } /** diff --git a/resources/js/markdown/codemirror.js b/resources/js/markdown/codemirror.js index cd620137d..dbf1925c0 100644 --- a/resources/js/markdown/codemirror.js +++ b/resources/js/markdown/codemirror.js @@ -25,7 +25,37 @@ export async function init(editor) { const domEventHandlers = { // Handle scroll to sync display view - scroll: (event) => syncActive && onScrollDebounced(event) + scroll: (event) => syncActive && onScrollDebounced(event), + // Handle image & content drag n drop + drop: (event) => { + const templateId = event.dataTransfer.getData('bookstack/template'); + if (templateId) { + event.preventDefault(); + editor.actions.insertTemplate(templateId, event.pageX, event.pageY); + } + + const clipboard = new Clipboard(event.dataTransfer); + const clipboardImages = clipboard.getImages(); + if (clipboardImages.length > 0) { + event.stopPropagation(); + event.preventDefault(); + editor.actions.insertClipboardImages(clipboardImages, event.pageX, event.pageY); + } + }, + // Handle image paste + paste: (event) => { + const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); + + // Don't handle the event ourselves if no items exist of contains table-looking data + if (!clipboard.hasItems() || clipboard.containsTabularData()) { + return; + } + + const images = clipboard.getImages(); + for (const image of images) { + editor.actions.uploadImage(image); + } + } } const cm = Code.markdownEditor( @@ -40,42 +70,5 @@ export async function init(editor) { // TODO // cm.setOption('direction', 'ltr'); - - // Handle image paste - // TODO - // cm.on('paste', (cm, event) => { - // const clipboard = new Clipboard(event.clipboardData || event.dataTransfer); - // - // // Don't handle the event ourselves if no items exist of contains table-looking data - // if (!clipboard.hasItems() || clipboard.containsTabularData()) { - // return; - // } - // - // const images = clipboard.getImages(); - // for (const image of images) { - // editor.actions.uploadImage(image); - // } - // }); - - // Handle image & content drag n drop - // TODO - // cm.on('drop', (cm, event) => { - // - // const templateId = event.dataTransfer.getData('bookstack/template'); - // if (templateId) { - // event.preventDefault(); - // editor.actions.insertTemplate(templateId, event.pageX, event.pageY); - // } - // - // const clipboard = new Clipboard(event.dataTransfer); - // const clipboardImages = clipboard.getImages(); - // if (clipboardImages.length > 0) { - // event.stopPropagation(); - // event.preventDefault(); - // editor.actions.insertClipboardImages(clipboardImages); - // } - // - // }); - return cm; } \ No newline at end of file From fdda813d5f623100378d29f8169b0067fe3f2dd9 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Thu, 13 Apr 2023 17:38:11 +0100 Subject: [PATCH 13/22] Cleaned up change handling in cm6 editor action handling --- resources/js/markdown/actions.js | 92 ++++++++++++++++---------------- 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/resources/js/markdown/actions.js b/resources/js/markdown/actions.js index 3aa6b5e81..a73cddd30 100644 --- a/resources/js/markdown/actions.js +++ b/resources/js/markdown/actions.js @@ -178,10 +178,7 @@ export class Actions { } const line = text.line(scrollToLine); - this.editor.cm.dispatch({ - selection: {anchor: line.from, head: line.to}, - scrollIntoView: true, - }); + this.#setSelection(line.from, line.to, true); this.focus(); } @@ -206,10 +203,8 @@ export class Actions { prependContent(content) { content = this.#cleanTextForEditor(content); const selectionRange = this.#getSelectionRange(); - this.editor.cm.dispatch({ - changes: {from: 0, to: 0, insert: content + '\n'}, - selection: {anchor: selectionRange.from + content.length + 1} - }); + const selectFrom = selectionRange.from + content.length + 1; + this.#dispatchChange(0, 0, content + '\n', selectFrom); this.focus(); } @@ -219,9 +214,7 @@ export class Actions { */ appendContent(content) { content = this.#cleanTextForEditor(content); - this.editor.cm.dispatch({ - changes: {from: this.editor.cm.state.doc.length, insert: '\n' + content}, - }); + this.#dispatchChange(this.editor.cm.state.doc.length, '\n' + content); this.focus(); } @@ -247,10 +240,8 @@ export class Actions { // Remove symbol if already set if (lineStart === newStart) { const newLineContent = lineContent.replace(`${newStart} `, ''); - this.editor.cm.dispatch({ - changes: {from: line.from, to: line.to, insert: newLineContent}, - selection: {anchor: selectionRange.from + (newLineContent.length - lineContent.length)} - }); + const selectFrom = selectionRange.from + (newLineContent.length - lineContent.length); + this.#dispatchChange(line.from, line.to, newLineContent, selectFrom); return; } @@ -262,10 +253,8 @@ export class Actions { newLineContent = newStart + ' ' + lineContent; } - this.editor.cm.dispatch({ - changes: {from: line.from, to: line.to, insert: newLineContent}, - selection: {anchor: selectionRange.from + (newLineContent.length - lineContent.length)} - }); + const selectFrom = selectionRange.from + (newLineContent.length - lineContent.length); + this.#dispatchChange(line.from, line.to, newLineContent, selectFrom); } /** @@ -289,10 +278,7 @@ export class Actions { newRange = selectionRange.extend(selectionRange.from, selectionRange.to + (start.length + end.length)); } - this.editor.cm.dispatch({ - changes: {from: selectionRange.from, to: selectionRange.to, insert: newSelectionText}, - selection: {anchor: newRange.anchor, head: newRange.head}, - }); + this.#dispatchChange(selectionRange.from, selectionRange.to, newSelectionText, newRange.anchor, newRange.head); } replaceLineStartForOrderedList() { @@ -333,10 +319,7 @@ export class Actions { const newFormat = formats[newFormatIndex]; const newContent = line.text.replace(matches[0], matches[0].replace(format, newFormat)); const lineDiff = newContent.length - line.text.length; - this.editor.cm.dispatch({ - changes: {from: line.from, to: line.to, insert: newContent}, - selection: {anchor: selectionRange.anchor + lineDiff, head: selectionRange.head + lineDiff}, - }); + this.#dispatchChange(line.from, line.to, newContent, selectionRange.anchor + lineDiff, selectionRange.head + lineDiff); } } @@ -368,10 +351,7 @@ export class Actions { const cursorPos = this.editor.cm.posAtCoords({x: posX, y: posY}, false); const {data} = await window.$http.get(`/templates/${templateId}`); const content = data.markdown || data.html; - this.editor.cm.dispatch({ - changes: {from: cursorPos, to: cursorPos, insert: content}, - selection: {anchor: cursorPos}, - }); + this.#dispatchChange(cursorPos, cursorPos, content, cursorPos); } /** @@ -410,10 +390,7 @@ export class Actions { const id = "image-" + Math.random().toString(16).slice(2); const placeholderImage = window.baseUrl(`/loading.gif#upload${id}`); const placeHolderText = `![](${placeholderImage})`; - this.editor.cm.dispatch({ - changes: {from: position, to: position, insert: placeHolderText}, - selection: {anchor: position}, - }); + this.#dispatchChange(position, position, placeHolderText, position); const remoteFilename = "image-" + Date.now() + "." + ext; const formData = new FormData(); @@ -446,11 +423,7 @@ export class Actions { */ #setText(text, selectionRange = null) { selectionRange = selectionRange || this.#getSelectionRange(); - this.editor.cm.dispatch({ - changes: {from: 0, to: this.editor.cm.state.doc.length, insert: text}, - selection: {anchor: selectionRange.from}, - }); - + this.#dispatchChange(0, this.editor.cm.state.doc.length, text, selectionRange.from); this.focus(); } @@ -464,11 +437,7 @@ export class Actions { */ #replaceSelection(newContent, cursorOffset = 0, selectionRange = null) { selectionRange = selectionRange || this.editor.cm.state.selection.main; - this.editor.cm.dispatch({ - changes: {from: selectionRange.from, to: selectionRange.to, insert: newContent}, - selection: {anchor: selectionRange.from + cursorOffset}, - }); - + this.#dispatchChange(selectionRange.from, selectionRange.to, newContent, selectionRange.from + cursorOffset); this.focus(); } @@ -530,9 +499,38 @@ export class Actions { lineOffset = start.length; } + this.#dispatchChange(line.from, line.to, newLineContent, selectionRange.from + lineOffset); + } + + /** + * Dispatch changes to the editor. + * @param {Number} from + * @param {?Number} to + * @param {?String} text + * @param {?Number} selectFrom + * @param {?Number} selectTo + */ + #dispatchChange(from, to = null, text = null, selectFrom = null, selectTo = null) { + const tr = {changes: {from, to: to, insert: text}}; + + if (selectFrom) { + tr.selection = {anchor: selectFrom}; + } + + this.editor.cm.dispatch(tr); + } + + /** + * Set the current selection range. + * Optionally will scroll the new range into view. + * @param {Number} from + * @param {Number} to + * @param {Boolean} scrollIntoView + */ + #setSelection(from, to, scrollIntoView = false) { this.editor.cm.dispatch({ - changes: {from: line.from, to: line.to, insert: newLineContent}, - selection: {anchor: selectionRange.from + lineOffset} + selection: {anchor: from, head: to}, + scrollIntoView, }); } } \ No newline at end of file From 257a7038788d7ce6183c946cf37ab2d27d114100 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Fri, 14 Apr 2023 14:08:40 +0100 Subject: [PATCH 14/22] Addressed existing cm6 todos - Updated clipboard handling - Removed old clipboard package for browser-native API. - Updated codemirror editor events to use new props for new data types. --- package-lock.json | 34 ------------ package.json | 1 - readme.md | 1 - resources/js/code/index.mjs | 54 +++++++++---------- resources/js/code/setups.js | 1 + resources/js/components/markdown-editor.js | 12 +---- resources/js/components/pointer.js | 18 ++++--- resources/js/markdown/codemirror.js | 7 ++- resources/js/services/clipboard.js | 6 ++- resources/sass/_codemirror.scss | 4 +- .../pages/parts/markdown-editor.blade.php | 2 +- resources/views/pages/parts/pointer.blade.php | 4 +- 12 files changed, 51 insertions(+), 93 deletions(-) diff --git a/package-lock.json b/package-lock.json index 85489c970..241e5392f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,7 +15,6 @@ "@codemirror/view": "^6.1.2", "@ssddanbrown/codemirror-lang-smarty": "^1.0.0", "@ssddanbrown/codemirror-lang-twig": "^1.0.0", - "clipboard": "^2.0.11", "codemirror": "^6.0.1", "dropzone": "^5.9.3", "markdown-it": "^13.0.1", @@ -810,16 +809,6 @@ "node": ">= 8.10.0" } }, - "node_modules/clipboard": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", - "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", - "dependencies": { - "good-listener": "^1.2.2", - "select": "^1.1.2", - "tiny-emitter": "^2.0.0" - } - }, "node_modules/cliui": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", @@ -912,11 +901,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/delegate": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", - "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" - }, "node_modules/dropzone": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/dropzone/-/dropzone-5.9.3.tgz", @@ -1218,14 +1202,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/good-listener": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", - "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", - "dependencies": { - "delegate": "^3.1.2" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -2062,11 +2038,6 @@ "node": ">=12.0.0" } }, - "node_modules/select": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", - "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==" - }, "node_modules/semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -2289,11 +2260,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", diff --git a/package.json b/package.json index 9ee57afa5..3579b2d25 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,6 @@ "@codemirror/view": "^6.1.2", "@ssddanbrown/codemirror-lang-smarty": "^1.0.0", "@ssddanbrown/codemirror-lang-twig": "^1.0.0", - "clipboard": "^2.0.11", "codemirror": "^6.0.1", "dropzone": "^5.9.3", "markdown-it": "^13.0.1", diff --git a/readme.md b/readme.md index 28822dd8e..f56b2c2bd 100644 --- a/readme.md +++ b/readme.md @@ -134,7 +134,6 @@ Note: This is not an exhaustive list of all libraries and projects that would be * [Sortable](https://github.com/SortableJS/Sortable) - _[MIT](https://github.com/SortableJS/Sortable/blob/master/LICENSE)_ * [Google Material Icons](https://github.com/google/material-design-icons) - _[Apache-2.0](https://github.com/google/material-design-icons/blob/master/LICENSE)_ * [Dropzone.js](http://www.dropzonejs.com/) - _[MIT](https://github.com/dropzone/dropzone/blob/main/LICENSE)_ -* [clipboard.js](https://clipboardjs.com/) - _[MIT](https://github.com/zenorocha/clipboard.js/blob/master/LICENSE)_ * [markdown-it](https://github.com/markdown-it/markdown-it) and [markdown-it-task-lists](https://github.com/revin/markdown-it-task-lists) - _[MIT](https://github.com/markdown-it/markdown-it/blob/master/LICENSE) and [ISC](https://github.com/revin/markdown-it-task-lists/blob/master/LICENSE)_ * [Dompdf](https://github.com/dompdf/dompdf) - _[LGPL v2.1](https://github.com/dompdf/dompdf/blob/master/LICENSE.LGPL)_ * [BarryVD/Dompdf](https://github.com/barryvdh/laravel-dompdf) - _[MIT](https://github.com/barryvdh/laravel-dompdf/blob/master/LICENSE)_ diff --git a/resources/js/code/index.mjs b/resources/js/code/index.mjs index 3fe4a6d86..dbed1c1e6 100644 --- a/resources/js/code/index.mjs +++ b/resources/js/code/index.mjs @@ -1,5 +1,5 @@ -import {EditorView, keymap} from "@codemirror/view" -import Clipboard from "clipboard/dist/clipboard.min"; +import {EditorView, keymap} from "@codemirror/view"; +import {copyTextToClipboard} from "../services/clipboard.js" // Modes import {viewer, editor} from "./setups.js"; @@ -57,28 +57,23 @@ function highlightElem(elem) { /** * Add a button to a CodeMirror instance which copies the contents to the clipboard upon click. - * @param cmInstance + * @param {EditorView} editorView */ -function addCopyIcon(cmInstance) { - // TODO - // const copyIcon = ``; - // const copyButton = document.createElement('div'); - // copyButton.classList.add('CodeMirror-copy'); - // copyButton.innerHTML = copyIcon; - // cmInstance.display.wrapper.appendChild(copyButton); - // - // const clipboard = new Clipboard(copyButton, { - // text: function(trigger) { - // return cmInstance.getValue() - // } - // }); - // - // clipboard.on('success', event => { - // copyButton.classList.add('success'); - // setTimeout(() => { - // copyButton.classList.remove('success'); - // }, 240); - // }); +function addCopyIcon(editorView) { + const copyIcon = ``; + const copyButton = document.createElement('button'); + copyButton.setAttribute('type', 'button') + copyButton.classList.add('cm-copy-button'); + copyButton.innerHTML = copyIcon; + editorView.dom.appendChild(copyButton); + + copyButton.addEventListener('click', event => { + copyTextToClipboard(editorView.state.doc.toString()); + copyButton.classList.add('success'); + setTimeout(() => { + copyButton.classList.remove('success'); + }, 240); + }); } /** @@ -187,11 +182,7 @@ export function updateLayout(cmInstance) { */ export function markdownEditor(elem, onChange, domEventHandlers, keyBindings) { const content = elem.textContent; - - // TODO - Change to pass something else that's useful, probably extension array? - // window.$events.emitPublic(elem, 'editor-markdown-cm::pre-init', {config}); - - const ev = createView({ + const config = { parent: elem.parentNode, doc: content, extensions: [ @@ -202,8 +193,13 @@ export function markdownEditor(elem, onChange, domEventHandlers, keyBindings) { EditorView.domEventHandlers(domEventHandlers), keymap.of(keyBindings), ], - }); + }; + // Emit a pre-event public event to allow tweaking of the configure before view creation. + window.$events.emitPublic(elem, 'editor-markdown-cm::pre-init', {cmEditorViewConfig: config}); + + // Create editor view, hide original input + const ev = createView(config); elem.style.display = 'none'; return ev; diff --git a/resources/js/code/setups.js b/resources/js/code/setups.js index 00366ee5e..b061bb3fe 100644 --- a/resources/js/code/setups.js +++ b/resources/js/code/setups.js @@ -45,5 +45,6 @@ export function editor(language) { ...historyKeymap, ]), getLanguageExtension(language, ''), + EditorView.lineWrapping, ]; } \ No newline at end of file diff --git a/resources/js/components/markdown-editor.js b/resources/js/components/markdown-editor.js index 922916701..9d687c83c 100644 --- a/resources/js/components/markdown-editor.js +++ b/resources/js/components/markdown-editor.js @@ -1,4 +1,3 @@ -import {debounce} from "../services/util"; import {Component} from "./component"; import {init as initEditor} from "../markdown/editor"; @@ -45,8 +44,7 @@ export class MarkdownEditor extends Component { window.$events.emitPublic(this.elem, 'editor-markdown::setup', { markdownIt: this.editor.markdown.getRenderer(), displayEl: this.display, - // TODO - change to codeMirrorView? - // codeMirrorInstance: this.editor.cm, + cmEditorView: this.editor.cm, }); } @@ -81,12 +79,6 @@ export class MarkdownEditor extends Component { toolbarLabel.closest('.markdown-editor-wrap').classList.add('active'); }); - // Refresh CodeMirror on container resize - // TODO - // const resizeDebounced = debounce(() => this.editor.cm.refresh(), 100, false); - // const observer = new ResizeObserver(resizeDebounced); - // observer.observe(this.elem); - this.handleDividerDrag(); } @@ -104,8 +96,6 @@ export class MarkdownEditor extends Component { window.removeEventListener('pointerup', upListener); this.display.style.pointerEvents = null; document.body.style.userSelect = null; - // TODO - // this.editor.cm.refresh(); }; this.display.style.pointerEvents = 'none'; diff --git a/resources/js/components/pointer.js b/resources/js/components/pointer.js index d884dc721..a60525cb4 100644 --- a/resources/js/components/pointer.js +++ b/resources/js/components/pointer.js @@ -1,12 +1,14 @@ import * as DOM from "../services/dom"; -import Clipboard from "clipboard/dist/clipboard.min"; import {Component} from "./component"; +import {copyTextToClipboard} from "../services/clipboard"; export class Pointer extends Component { setup() { this.container = this.$el; + this.input = this.$refs.input; + this.button = this.$refs.button; this.pageId = this.$opts.pageId; // Instance variables @@ -16,15 +18,17 @@ export class Pointer extends Component { this.pointerSectionId = ''; this.setupListeners(); - - // Set up clipboard - new Clipboard(this.container.querySelector('button')); } setupListeners() { + // Copy on copy button click + this.button.addEventListener('click', event => { + copyTextToClipboard(this.input.value); + }); + // Select all contents on input click - DOM.onChildEvent(this.container, 'input', 'click', (event, input) => { - input.select(); + this.input.addEventListener('click', event => { + this.input.select(); event.stopPropagation(); }); @@ -112,7 +116,7 @@ export class Pointer extends Component { inputText = window.location.protocol + "//" + window.location.host + inputText; } - this.container.querySelector('input').value = inputText; + this.input.value = inputText; // Update anchor if present const editAnchor = this.container.querySelector('#pointer-edit'); diff --git a/resources/js/markdown/codemirror.js b/resources/js/markdown/codemirror.js index dbf1925c0..55ea485e3 100644 --- a/resources/js/markdown/codemirror.js +++ b/resources/js/markdown/codemirror.js @@ -64,11 +64,10 @@ export async function init(editor) { domEventHandlers, provideKeyBindings(editor), ); - window.cm = cm; - // Will force to remain as ltr for now due to issues when HTML is in editor. - // TODO - // cm.setOption('direction', 'ltr'); + // Add editor view to window for easy access/debugging. + // Not part of official API/Docs + window.mdEditorView = cm; return cm; } \ No newline at end of file diff --git a/resources/js/services/clipboard.js b/resources/js/services/clipboard.js index da921e515..6e59270a9 100644 --- a/resources/js/services/clipboard.js +++ b/resources/js/services/clipboard.js @@ -1,5 +1,5 @@ -class Clipboard { +export class Clipboard { /** * Constructor @@ -51,4 +51,8 @@ class Clipboard { } } +export function copyTextToClipboard(text) { + return navigator.clipboard.writeText(text); +} + export default Clipboard; \ No newline at end of file diff --git a/resources/sass/_codemirror.scss b/resources/sass/_codemirror.scss index 1dee39cd2..aa3729606 100644 --- a/resources/sass/_codemirror.scss +++ b/resources/sass/_codemirror.scss @@ -450,7 +450,7 @@ html.dark-mode .CodeMirror pre { /** * Custom Copy Button */ -.CodeMirror-copy { +.cm-copy-button { position: absolute; top: -1px; right: -1px; @@ -478,7 +478,7 @@ html.dark-mode .CodeMirror pre { } } } -.CodeMirror:hover .CodeMirror-copy { +.cm-editor:hover .cm-copy-button { user-select: all; opacity: 1; pointer-events: all; diff --git a/resources/views/pages/parts/markdown-editor.blade.php b/resources/views/pages/parts/markdown-editor.blade.php index fd8a20a04..c488f0e11 100644 --- a/resources/views/pages/parts/markdown-editor.blade.php +++ b/resources/views/pages/parts/markdown-editor.blade.php @@ -30,7 +30,7 @@ -
+