support bare image paths in css url() properties
Hunter
Tuesday, December 23rd, 2025 at 12:28 AM
6
7 ## Usage
8
-1. Open `index.html` in your web browser (or <a href="https://hunterirving.github.io/web_workshop/">click here</a>)
9 +1. Open `index.html` in your web browser (<a href="https://hunterirving.github.io/web_workshop/">click here</a>)
10 2. Start typing HTML in the editor pane
11 - The preview pane will rerender when you're done typing
- - Your work is automatically saved and restored when you reload the page
-3. Press `⌘ + S` to export your work as an HTML file (`⌘ + O` to reopen exported files)
12 + - Your work is automatically saved, and restored when you reload the page
13 +3. Press `⌘ + S` to export your work as an HTML file (`⌘ + O` to open an existing file)
14
15 ### Options
16 - to toggle <b>line numbers</b>, press <kbd>F1</kbd> (disabled by default)
17 - to toggle <b>line wrapping</b>, press <kbd>F2</kbd> (enabled by default)
18
19 ### Stock Images
-A library of retro images is included. To browse them, type the magic tag `<images>` anywhere in the editor. You can use them in your pages like so: `<img src="coffee.gif">`.
20 +A library of stock images is included for your convenience. To browse them, type `<img src="?">` anywhere in the editor. You can use them in your pages like so: `<img src="coffee.gif">`.
21
22 <br>
23 <img src="images/hint.gif" width=60px>
18
19 // Rewrite bare image filenames to use images/ prefix (case-insensitive, uses correct case)
20 function rewriteBareImageSrcs(html) {
- return html.replace(/(<img\s[^>]*\bsrc\s*=\s*["'])([^"'/:]+\.(gif|png|jpg|jpeg|svg|webp))(["'])/gi,
21 + // Rewrite <img src="filename.ext">
22 + html = html.replace(/(<img\s[^>]*\bsrc\s*=\s*["'])([^"'/:]+\.(gif|png|jpg|jpeg|svg|webp))(["'])/gi,
23 (match, before, filename, ext, after) => {
24 const original = stockImages.get(filename.toLowerCase());
25 if (original) {
27 }
28 return match;
29 });
30 + // Rewrite url(filename.ext) in CSS
31 + html = html.replace(/(url\(\s*["']?)([^"')/:]+\.(gif|png|jpg|jpeg|svg|webp))(["']?\s*\))/gi,
32 + (match, before, filename, ext, after) => {
33 + const original = stockImages.get(filename.toLowerCase());
34 + if (original) {
35 + return before + 'images/' + original + after;
36 + }
37 + return match;
38 + });
39 + return html;
40 }
41
-// Expand <images> tags into gallery table
42 +// Expand <img src="?"> tags into gallery table
43 function expandImagesTag(html) {
- return html.replace(/<images\s*\/?>/gi, () => {
44 + return html.replace(/<img\s+src\s*=\s*["']?\?["']?\s*\/?>/gi, () => {
45 const images = Array.from(stockImages.values()).sort();
46 if (images.length === 0) return '<p>No images available</p>';
47 const rows = images.map(filename =>
2 // Build script to bundle CodeMirror for offline use
3 //
4 // Usage:
-// cd vendor
-// npm install
-// npm run build
5 +// cd vendor
6 +// npm install
7 +// npm run build
8 //
9 // This will regenerate ../codemirror-bundle.js
10
15 const __dirname = dirname(fileURLToPath(import.meta.url));
16
17 await esbuild.build({
- stdin: {
- contents: `
- export {EditorView, keymap, placeholder, lineNumbers, Decoration} from "@codemirror/view";
- export {EditorState, Compartment} from "@codemirror/state";
- export {defaultKeymap, indentWithTab, undo, redo, undoDepth, redoDepth, history, historyKeymap} from "@codemirror/commands";
- export {closeBrackets, closeBracketsKeymap} from "@codemirror/autocomplete";
- export {html} from "@codemirror/lang-html";
- export {githubDark} from "@fsegurai/codemirror-theme-github-dark";
- export {indentUnit} from "@codemirror/language";
- export {search, searchKeymap, closeSearchPanel, openSearchPanel} from "@codemirror/search";
- `,
- resolveDir: __dirname,
- loader: 'js',
- },
- bundle: true,
- format: 'esm',
- outfile: join(__dirname, '..', 'codemirror-bundle.js'),
- minify: true,
- target: ['es2020'],
18 + stdin: {
19 + contents: `
20 + export {EditorView, keymap, placeholder, lineNumbers, Decoration} from "@codemirror/view";
21 + export {EditorState, Compartment} from "@codemirror/state";
22 + export {defaultKeymap, indentWithTab, undo, redo, undoDepth, redoDepth, history, historyKeymap} from "@codemirror/commands";
23 + export {closeBrackets, closeBracketsKeymap} from "@codemirror/autocomplete";
24 + export {html} from "@codemirror/lang-html";
25 + export {githubDark} from "@fsegurai/codemirror-theme-github-dark";
26 + export {indentUnit} from "@codemirror/language";
27 + export {search, searchKeymap, closeSearchPanel, openSearchPanel} from "@codemirror/search";
28 + `,
29 + resolveDir: __dirname,
30 + loader: 'js',
31 + },
32 + bundle: true,
33 + format: 'esm',
34 + outfile: join(__dirname, '..', 'codemirror-bundle.js'),
35 + minify: true,
36 + target: ['es2020'],
37 });
38
39 console.log('✓ CodeMirror bundle created: ../codemirror-bundle.js');
1 {
- "name": "codemirror-bundle",
- "private": true,
- "type": "module",
- "scripts": {
- "build": "node build.mjs"
- },
- "dependencies": {
- "@codemirror/autocomplete": "^6",
- "@codemirror/commands": "^6",
- "@codemirror/lang-html": "^6",
- "@codemirror/language": "^6",
- "@codemirror/search": "^6",
- "@codemirror/state": "^6",
- "@codemirror/view": "^6",
- "@fsegurai/codemirror-theme-github-dark": "^6",
- "esbuild": "^0.24"
- }
2 + "name": "codemirror-bundle",
3 + "private": true,
4 + "type": "module",
5 + "scripts": {
6 + "build": "node build.mjs"
7 + },
8 + "dependencies": {
9 + "@codemirror/autocomplete": "^6",
10 + "@codemirror/commands": "^6",
11 + "@codemirror/lang-html": "^6",
12 + "@codemirror/language": "^6",
13 + "@codemirror/search": "^6",
14 + "@codemirror/state": "^6",
15 + "@codemirror/view": "^6",
16 + "@fsegurai/codemirror-theme-github-dark": "^6",
17 + "esbuild": "^0.24"
18 + }
19 }