Skip to content

Commit f63b9e8

Browse files
committed
update
1 parent 46fac05 commit f63b9e8

File tree

3 files changed

+90
-98
lines changed

3 files changed

+90
-98
lines changed

docs-obsidian.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,22 @@ Fragments are parts of you page that pop up one after another, step by step, whe
7979
You may mark single lines as Fragments. Those lines are denoted by having a `#fragment` in the line above them.
8080
A single line is defined as from the start of a line to the next `newline`, so that may as well span more than a single line when line-breaks are inserted by the browser in order to fit that single line on the screen.
8181
#### Single Fragment Example
82-
![[Pasted image 20250523183945.png]]
83-
### Fragment Blocks
84-
For blocks you may also have a `#fragment-start` followed by a `#fragment-end`.
85-
Everything between those tags will be treated as a fragment.
86-
That allows you to fade-in more than one line at a time.
87-
88-
It is important to note that all those flags must be on their own line.
89-
90-
This then will become a fragment in the presentation-view.
91-
All of this will be completely invisible in the normal view.
92-
#### Fragment Block Example
93-
![[Pasted image 20250523184030.png]]
82+
```bash
83+
This text displays already.
84+
##fragment
85+
Fragmented Text comes in after that.
86+
- ##fragment one
87+
- ##fragment two
88+
```
89+
Another example that fades in two blocks one after another would look like this:
90+
```bash
91+
This text is already on the page.
92+
##fragment
93+
- Then this
94+
- fades in
95+
##fragment
96+
- and then
97+
- these three
98+
- lines
99+
```
100+
So you may see the `##fragment` tag as some kind of a `stop here and wait for me to press space` tag.

md/test-md-file.md

Lines changed: 19 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -115,63 +115,37 @@ Example:
115115
- two
116116
- three
117117

118-
+ one
119-
+ two
120-
+ three
118+
>+ one
119+
>+ two
120+
>+ three
121121
122122
* one
123123
* two
124124
* three
125125

126-
1. one
127-
2. two
128-
3. three
126+
>1. one
127+
>2. two
128+
>3. three
129129
### Fragments
130-
#fragment
130+
##fragment
131131
Fragmented Text.
132-
#fragment
132+
##fragment
133133
- one
134-
#fragment
135-
- two
136-
#fragment
134+
- ##fragment two
137135
![global-image|100x300](https://raw.githubusercontent.com/UnterrainerInformatik/java-http-server/master/docs/standard-request-response-process.png)
138136

139-
#fragment
137+
##fragment
140138
another text
141139

142-
#fragment-start
143-
- Fragment 1
144-
- Fragment 2
145-
- Fragment 3
146-
#fragment-end
147-
148-
#fragment
149-
- one
150-
#fragment
151-
- two
152-
#fragment
153-
- three
154-
155-
#fragment
156-
+ one
157-
#fragment
158-
+ two
159-
#fragment
160-
+ three
161-
162-
#fragment
163-
* one
164-
#fragment
165-
* two
166-
#fragment
167-
* three
140+
## Second Fragment Test
141+
Text
142+
##fragment
143+
>- one ##fragment
144+
>- two ##fragment
145+
>- three ##fragment
168146
169-
#fragment
170-
1. one
171-
#fragment
172-
2. two
173-
#fragment
174-
3. three
147+
>+ one ##fragment
148+
>+ two ##fragment
149+
>+ three ##fragment
175150
176-
#fragment
177151
Done.

obsidian.js

Lines changed: 52 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,7 @@ const internalSubstitutions = {
2626
regexp: /@#@##@@--@code@--@@##@#@/gms,
2727
},
2828
fragment_single: {
29-
string: "<!-- __fragment-single__ -->"
30-
},
31-
fragment_start: {
32-
string: "<!-- __fragment-start__ -->"
33-
},
34-
fragment_end: {
35-
string: "<!-- __fragment-end__ -->"
29+
string: "<!-- __fragment-marker__ -->"
3630
}
3731
};
3832
let codeList = [];
@@ -458,46 +452,63 @@ function getFollowingQuotedLines(md, index) {
458452
}
459453

460454
function preprocessFragments(md) {
461-
return md
462-
.replace(/^[ \t]*#fragment-start[ \t]*$/gm, internalSubstitutions.fragment_start.string)
463-
.replace(/^[ \t]*#fragment-end[ \t]*$/gm, internalSubstitutions.fragment_end.string)
464-
465-
.replace(/^[ \t]*#fragment[ \t]*\n([^\n]+)/gm, (_, nextLine) => {
466-
if (/^\s*[-*+1.]\s/.test(nextLine)) {
467-
return nextLine.replace(/^(\s*[-*+1.]\s*)(.+)/, (_, prefix, content) => {
468-
return `${prefix}%%LI_FRAGMENT%% ${content}`;
469-
});
470-
}
471-
return `<span class="fragment">${nextLine.trim()}</span>`;
472-
});
455+
const marker = internalSubstitutions.fragment_single.string;
456+
const r = md.replace(/##fragment(?=\s|$)/g, marker)
457+
return r;
473458
}
474459

475460
function postprocessFragments(html) {
476-
const { fragment_start, fragment_end } = internalSubstitutions;
477-
478-
// Block fragments
479-
html = html.replace(
480-
new RegExp(`${fragment_start.string}([\\s\\S]*?)${fragment_end.string}([\\s\\S]*?</li>)`, 'g'),
481-
(fullMatch, content, trailingLi) => {
482-
let fixed = (content + trailingLi).trim();
483-
484-
// Remove <p> inside <li>
485-
fixed = fixed.replace(
486-
/<li>\s*\n?\s*<p>([\s\S]*?)<\/p>\s*\n?\s*<\/li>/gm,
487-
(_, inner) => `<li>${inner.trim()}</li>`
488-
);
461+
const { fragment_single } = internalSubstitutions;
462+
const markerValue = fragment_single.string.replace(/<!--|-->/g, "").trim();
489463

490-
return `<div class="fragment">\n${fixed}\n</div>\n\n`;
491-
}
492-
);
464+
const dom = new JSDOM(html);
465+
const document = dom.window.document;
493466

494-
// Inline fragment: list item
495-
html = html.replace(
496-
/<li[^>]*>\s*(?:<p>)?%%LI_FRAGMENT%%\s*(.*?)(?:<\/p>)?\s*<\/li>/g,
497-
(_, content) => `<li class="fragment">${content.trim()}</li>`
498-
);
467+
let fragmentIndex = -1;
468+
let started = false;
499469

500-
return html;
470+
function walk(node) {
471+
if (!node) return;
472+
473+
const childNodes = Array.from(node.childNodes);
474+
for (let child of childNodes) {
475+
// Marker detection
476+
if (child.nodeType === 8 && child.nodeValue.trim() === markerValue) {
477+
fragmentIndex++;
478+
started = true;
479+
child.remove();
480+
continue;
481+
}
482+
483+
// Skip before first marker
484+
if (!started) {
485+
if (child.nodeType === 1) {
486+
walk(child); // still traverse deeper
487+
}
488+
continue;
489+
}
490+
491+
// Text node
492+
if (child.nodeType === 3 && child.textContent.trim() !== "") {
493+
const span = document.createElement("span");
494+
span.classList.add("fragment");
495+
span.setAttribute("data-fragment-index", fragmentIndex);
496+
span.textContent = child.textContent;
497+
child.replaceWith(span);
498+
continue;
499+
}
500+
501+
// Element node
502+
if (child.nodeType === 1) {
503+
child.classList.add("fragment");
504+
child.setAttribute("data-fragment-index", fragmentIndex);
505+
walk(child); // recurse
506+
}
507+
}
508+
}
509+
510+
walk(document.body);
511+
return document.body.innerHTML;
501512
}
502513

503514
function preReplaceObsidianFileLinks(html, req) {

0 commit comments

Comments
 (0)