pict-section-content 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,50 @@
1
+ # Contributing to Retold
2
+
3
+ We welcome contributions to Retold and its modules. This guide covers the expectations and process for contributing.
4
+
5
+ ## Code of Conduct
6
+
7
+ The Retold community values **empathy**, **equity**, **kindness**, and **thoughtfulness**. We expect all participants to treat each other with respect, assume good intent, and engage constructively. These values apply to all interactions: pull requests, issues, discussions, and code review.
8
+
9
+ ## How to Contribute
10
+
11
+ ### Pull Requests
12
+
13
+ Pull requests are the preferred method for contributing changes. To submit one:
14
+
15
+ 1. Fork the module repository you want to change
16
+ 2. Create a branch for your work
17
+ 3. Make your changes, following the code style of the module you are editing
18
+ 4. Ensure your changes have test coverage (see below)
19
+ 5. Open a pull request against the module's main branch
20
+
21
+ **Submitting a pull request does not guarantee it will be accepted.** Maintainers review contributions for fit, quality, and alignment with the project's direction. A PR may be declined, or you may be asked to revise it. This is normal and not a reflection on the quality of your effort.
22
+
23
+ ### Reporting Issues
24
+
25
+ If you find a bug or have a feature suggestion, open an issue on the relevant module's repository. Include enough detail to reproduce the problem or understand the proposal.
26
+
27
+ ## Test Coverage
28
+
29
+ Every commit must include test coverage for the changes it introduces. Retold modules use Mocha in TDD style. Before submitting:
30
+
31
+ - **Write tests** for any new functionality or bug fixes
32
+ - **Run the existing test suite** with `npm test` and confirm all tests pass
33
+ - **Check coverage** with `npm run coverage` if the module supports it
34
+
35
+ Pull requests that break existing tests or lack coverage for new code will not be merged.
36
+
37
+ ## Code Style
38
+
39
+ Follow the conventions of the module you are working in. The general Retold style is:
40
+
41
+ - **Tabs** for indentation, never spaces
42
+ - **Plain JavaScript** only (no TypeScript)
43
+ - **Allman-style braces** (opening brace on its own line)
44
+ - **Variable naming:** `pVariable` for parameters, `tmpVariable` for temporaries, `libSomething` for imports
45
+
46
+ When in doubt, match what the surrounding code does.
47
+
48
+ ## Repository Structure
49
+
50
+ Each module is its own git repository. The [retold](https://github.com/stevenvelozo/retold) repository tracks module organization but does not contain module source code. Direct your pull request to the specific module repository where your change belongs.
package/README.md CHANGED
@@ -129,10 +129,16 @@ npm test
129
129
  npm run coverage
130
130
  ```
131
131
 
132
+ ## Related Packages
133
+
134
+ - [pict](https://github.com/stevenvelozo/pict) - MVC application framework
135
+ - [pict-view](https://github.com/stevenvelozo/pict-view) - View base class
136
+ - [pict-provider](https://github.com/stevenvelozo/pict-provider) - Data provider base class
137
+
132
138
  ## License
133
139
 
134
- MIT - See [LICENSE](LICENSE) for details.
140
+ MIT
135
141
 
136
- ## Author
142
+ ## Contributing
137
143
 
138
- Steven Velozo - [steven@velozo.com](mailto:steven@velozo.com)
144
+ Pull requests are welcome. For details on our code of conduct, contribution process, and testing requirements, see the [Retold Contributing Guide](https://github.com/stevenvelozo/retold/blob/main/docs/contributing.md).
package/docs/.nojekyll ADDED
File without changes
@@ -0,0 +1,73 @@
1
+ /* ============================================================================
2
+ Pict Docuserve - Base Styles
3
+ ============================================================================ */
4
+
5
+ /* Reset and base */
6
+ *, *::before, *::after {
7
+ box-sizing: border-box;
8
+ }
9
+
10
+ html, body {
11
+ margin: 0;
12
+ padding: 0;
13
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
14
+ font-size: 16px;
15
+ line-height: 1.5;
16
+ color: #423D37;
17
+ background-color: #fff;
18
+ -webkit-font-smoothing: antialiased;
19
+ -moz-osx-font-smoothing: grayscale;
20
+ }
21
+
22
+ /* Typography */
23
+ h1, h2, h3, h4, h5, h6 {
24
+ margin-top: 0;
25
+ line-height: 1.3;
26
+ }
27
+
28
+ a {
29
+ color: #2E7D74;
30
+ text-decoration: none;
31
+ }
32
+
33
+ a:hover {
34
+ color: #256861;
35
+ }
36
+
37
+ /* Application container */
38
+ #Docuserve-Application-Container {
39
+ min-height: 100vh;
40
+ }
41
+
42
+ /* Utility: scrollbar styling */
43
+ ::-webkit-scrollbar {
44
+ width: 8px;
45
+ }
46
+
47
+ ::-webkit-scrollbar-track {
48
+ background: #F5F0E8;
49
+ }
50
+
51
+ ::-webkit-scrollbar-thumb {
52
+ background: #D4CCBE;
53
+ border-radius: 4px;
54
+ }
55
+
56
+ ::-webkit-scrollbar-thumb:hover {
57
+ background: #B5AA9A;
58
+ }
59
+
60
+ /* Responsive adjustments */
61
+ @media (max-width: 768px) {
62
+ html {
63
+ font-size: 14px;
64
+ }
65
+
66
+ #Docuserve-Sidebar-Container {
67
+ display: none;
68
+ }
69
+
70
+ .docuserve-body {
71
+ flex-direction: column;
72
+ }
73
+ }
@@ -0,0 +1,39 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7
+ <meta name="description" content="Documentation powered by pict-docuserve">
8
+
9
+ <title>Documentation</title>
10
+
11
+ <!-- Application Stylesheet -->
12
+ <link href="css/docuserve.css" rel="stylesheet">
13
+ <!-- KaTeX stylesheet for LaTeX equation rendering -->
14
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
15
+ <!-- PICT Dynamic View CSS Container -->
16
+ <style id="PICT-CSS"></style>
17
+
18
+ <!-- Load the PICT library from jsDelivr CDN -->
19
+ <script src="https://cdn.jsdelivr.net/npm/pict@1/dist/pict.min.js" type="text/javascript"></script>
20
+ <!-- Bootstrap the Application -->
21
+ <script type="text/javascript">
22
+ //<![CDATA[
23
+ Pict.safeOnDocumentReady(() => { Pict.safeLoadPictApplication(PictDocuserve, 2)});
24
+ //]]>
25
+ </script>
26
+ </head>
27
+ <body>
28
+ <!-- The root container for the Pict application -->
29
+ <div id="Docuserve-Application-Container"></div>
30
+
31
+ <!-- Mermaid diagram rendering -->
32
+ <script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
33
+ <script>mermaid.initialize({ startOnLoad: false, theme: 'default' });</script>
34
+ <!-- KaTeX for LaTeX equation rendering -->
35
+ <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"></script>
36
+ <!-- Load the Docuserve PICT Application Bundle from jsDelivr CDN -->
37
+ <script src="https://cdn.jsdelivr.net/npm/pict-docuserve@0/dist/pict-docuserve.min.js" type="text/javascript"></script>
38
+ </body>
39
+ </html>
@@ -0,0 +1,70 @@
1
+ {
2
+ "Generated": "2026-02-18T05:42:00.270Z",
3
+ "GitHubOrg": "stevenvelozo",
4
+ "DefaultBranch": "master",
5
+ "Groups": [
6
+ {
7
+ "Name": "Dist",
8
+ "Key": "dist",
9
+ "Description": "",
10
+ "Modules": [
11
+ {
12
+ "Name": "indoctrinate_content_staging",
13
+ "Repo": "indoctrinate_content_staging",
14
+ "Group": "dist",
15
+ "Branch": "master",
16
+ "HasDocs": false,
17
+ "HasCover": false,
18
+ "Sidebar": [],
19
+ "DocFiles": []
20
+ }
21
+ ]
22
+ },
23
+ {
24
+ "Name": "Docs",
25
+ "Key": "docs",
26
+ "Description": "",
27
+ "Modules": [
28
+ {
29
+ "Name": "css",
30
+ "Repo": "css",
31
+ "Group": "docs",
32
+ "Branch": "master",
33
+ "HasDocs": true,
34
+ "HasCover": false,
35
+ "Sidebar": [],
36
+ "DocFiles": [
37
+ "css/docuserve.css"
38
+ ]
39
+ }
40
+ ]
41
+ },
42
+ {
43
+ "Name": "Source",
44
+ "Key": "source",
45
+ "Description": "",
46
+ "Modules": [
47
+ {
48
+ "Name": "providers",
49
+ "Repo": "providers",
50
+ "Group": "source",
51
+ "Branch": "master",
52
+ "HasDocs": false,
53
+ "HasCover": false,
54
+ "Sidebar": [],
55
+ "DocFiles": []
56
+ },
57
+ {
58
+ "Name": "views",
59
+ "Repo": "views",
60
+ "Group": "source",
61
+ "Branch": "master",
62
+ "HasDocs": false,
63
+ "HasCover": false,
64
+ "Sidebar": [],
65
+ "DocFiles": []
66
+ }
67
+ ]
68
+ }
69
+ ]
70
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "Generated": "2026-02-18T05:42:00.361Z",
3
+ "DocumentCount": 0,
4
+ "LunrIndex": {
5
+ "version": "2.3.9",
6
+ "fields": [
7
+ "title",
8
+ "module",
9
+ "group",
10
+ "body"
11
+ ],
12
+ "fieldVectors": [],
13
+ "invertedIndex": [],
14
+ "pipeline": [
15
+ "stemmer"
16
+ ]
17
+ },
18
+ "Documents": {}
19
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pict-section-content",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "Pict content rendering section - markdown parsing, Mermaid diagrams, and KaTeX equations",
5
5
  "main": "source/Pict-Section-Content.js",
6
6
  "scripts": {
@@ -21,14 +21,14 @@
21
21
  },
22
22
  "homepage": "https://github.com/stevenvelozo/pict-section-content#readme",
23
23
  "dependencies": {
24
- "pict-provider": "^1.0.7",
25
- "pict-view": "^1.0.64"
24
+ "pict-provider": "^1.0.10",
25
+ "pict-view": "^1.0.66"
26
26
  },
27
27
  "devDependencies": {
28
28
  "chai": "^6.2.2",
29
29
  "mocha": "^11.7.5",
30
- "pict": "^1.0.343",
31
- "quackage": "^1.0.47"
30
+ "pict": "^1.0.348",
31
+ "quackage": "^1.0.51"
32
32
  },
33
33
  "mocha": {
34
34
  "diff": true,
@@ -46,6 +46,17 @@ class PictContentProvider extends libPictProvider
46
46
  let tmpBlockquoteLines = [];
47
47
  let tmpInMathBlock = false;
48
48
  let tmpMathLines = [];
49
+ let tmpParagraphLines = [];
50
+
51
+ // Helper to flush accumulated paragraph lines into a single <p> tag
52
+ let fFlushParagraph = () =>
53
+ {
54
+ if (tmpParagraphLines.length > 0)
55
+ {
56
+ tmpHTML.push('<p>' + tmpParagraphLines.map((pLine) => { return this.parseInline(pLine, pLinkResolver); }).join(' ') + '</p>');
57
+ tmpParagraphLines = [];
58
+ }
59
+ };
49
60
 
50
61
  for (let i = 0; i < tmpLines.length; i++)
51
62
  {
@@ -63,6 +74,8 @@ class PictContentProvider extends libPictProvider
63
74
  }
64
75
  else
65
76
  {
77
+ // Flush any pending paragraph
78
+ fFlushParagraph();
66
79
  // Close any open list or blockquote
67
80
  if (tmpInList)
68
81
  {
@@ -122,6 +135,8 @@ class PictContentProvider extends libPictProvider
122
135
  }
123
136
  else
124
137
  {
138
+ // Flush any pending paragraph
139
+ fFlushParagraph();
125
140
  // Close any open list or blockquote
126
141
  if (tmpInList)
127
142
  {
@@ -153,6 +168,8 @@ class PictContentProvider extends libPictProvider
153
168
  {
154
169
  if (!tmpInBlockquote)
155
170
  {
171
+ // Flush any pending paragraph
172
+ fFlushParagraph();
156
173
  // Close any open list
157
174
  if (tmpInList)
158
175
  {
@@ -175,6 +192,7 @@ class PictContentProvider extends libPictProvider
175
192
  // Horizontal rule
176
193
  if (tmpLine.match(/^(-{3,}|\*{3,}|_{3,})\s*$/))
177
194
  {
195
+ fFlushParagraph();
178
196
  if (tmpInList)
179
197
  {
180
198
  tmpHTML.push(tmpListType === 'ul' ? '</ul>' : '</ol>');
@@ -188,6 +206,7 @@ class PictContentProvider extends libPictProvider
188
206
  let tmpHeadingMatch = tmpLine.match(/^(#{1,6})\s+(.+)/);
189
207
  if (tmpHeadingMatch)
190
208
  {
209
+ fFlushParagraph();
191
210
  if (tmpInList)
192
211
  {
193
212
  tmpHTML.push(tmpListType === 'ul' ? '</ul>' : '</ol>');
@@ -204,6 +223,7 @@ class PictContentProvider extends libPictProvider
204
223
  let tmpULMatch = tmpLine.match(/^(\s*)[-*+]\s+(.*)/);
205
224
  if (tmpULMatch)
206
225
  {
226
+ fFlushParagraph();
207
227
  if (!tmpInList || tmpListType !== 'ul')
208
228
  {
209
229
  if (tmpInList)
@@ -222,6 +242,7 @@ class PictContentProvider extends libPictProvider
222
242
  let tmpOLMatch = tmpLine.match(/^(\s*)\d+\.\s+(.*)/);
223
243
  if (tmpOLMatch)
224
244
  {
245
+ fFlushParagraph();
225
246
  if (!tmpInList || tmpListType !== 'ol')
226
247
  {
227
248
  if (tmpInList)
@@ -243,15 +264,17 @@ class PictContentProvider extends libPictProvider
243
264
  tmpInList = false;
244
265
  }
245
266
 
246
- // Empty line
267
+ // Empty line — flush any accumulated paragraph
247
268
  if (tmpLine.trim() === '')
248
269
  {
270
+ fFlushParagraph();
249
271
  continue;
250
272
  }
251
273
 
252
274
  // Table detection
253
275
  if (tmpLine.match(/^\|/) && i + 1 < tmpLines.length && tmpLines[i + 1].match(/^\|[\s-:|]+\|/))
254
276
  {
277
+ fFlushParagraph();
255
278
  // Close any open list
256
279
  if (tmpInList)
257
280
  {
@@ -291,10 +314,14 @@ class PictContentProvider extends libPictProvider
291
314
  continue;
292
315
  }
293
316
 
294
- // Regular paragraph
295
- tmpHTML.push('<p>' + this.parseInline(tmpLine, pLinkResolver) + '</p>');
317
+ // Accumulate paragraph lines — consecutive non-blank text lines
318
+ // will be joined into a single <p> tag when flushed
319
+ tmpParagraphLines.push(tmpLine);
296
320
  }
297
321
 
322
+ // Flush any remaining accumulated paragraph
323
+ fFlushParagraph();
324
+
298
325
  // Close any trailing open elements
299
326
  if (tmpInList)
300
327
  {
@@ -255,6 +255,146 @@ suite
255
255
  }
256
256
  );
257
257
 
258
+ suite
259
+ (
260
+ 'Multi-line Paragraph Handling',
261
+ function()
262
+ {
263
+ test
264
+ (
265
+ 'parseMarkdown should join consecutive lines into a single paragraph.',
266
+ (fDone) =>
267
+ {
268
+ var tmpProvider = createProvider();
269
+ var tmpResult = tmpProvider.parseMarkdown('This is the first line\nof a single paragraph\nthat spans three lines.');
270
+ // All three lines should be in one <p> tag
271
+ Expect(tmpResult).to.contain('<p>This is the first line of a single paragraph that spans three lines.</p>');
272
+ fDone();
273
+ }
274
+ );
275
+ test
276
+ (
277
+ 'parseMarkdown should separate paragraphs on blank lines.',
278
+ (fDone) =>
279
+ {
280
+ var tmpProvider = createProvider();
281
+ var tmpResult = tmpProvider.parseMarkdown('First paragraph line one\nfirst paragraph line two.\n\nSecond paragraph line one\nsecond paragraph line two.');
282
+ Expect(tmpResult).to.contain('<p>First paragraph line one first paragraph line two.</p>');
283
+ Expect(tmpResult).to.contain('<p>Second paragraph line one second paragraph line two.</p>');
284
+ // Should produce exactly two <p> tags
285
+ var tmpParagraphCount = (tmpResult.match(/<p>/g) || []).length;
286
+ Expect(tmpParagraphCount).to.equal(2);
287
+ fDone();
288
+ }
289
+ );
290
+ test
291
+ (
292
+ 'parseMarkdown should flush paragraph before a heading.',
293
+ (fDone) =>
294
+ {
295
+ var tmpProvider = createProvider();
296
+ var tmpResult = tmpProvider.parseMarkdown('Some introductory text\nthat spans two lines.\n## A Heading');
297
+ Expect(tmpResult).to.contain('<p>Some introductory text that spans two lines.</p>');
298
+ Expect(tmpResult).to.contain('<h2');
299
+ Expect(tmpResult).to.contain('A Heading');
300
+ fDone();
301
+ }
302
+ );
303
+ test
304
+ (
305
+ 'parseMarkdown should flush paragraph before a list.',
306
+ (fDone) =>
307
+ {
308
+ var tmpProvider = createProvider();
309
+ var tmpResult = tmpProvider.parseMarkdown('Here is a paragraph\nbefore a list.\n- Item 1\n- Item 2');
310
+ Expect(tmpResult).to.contain('<p>Here is a paragraph before a list.</p>');
311
+ Expect(tmpResult).to.contain('<ul>');
312
+ Expect(tmpResult).to.contain('<li>Item 1</li>');
313
+ fDone();
314
+ }
315
+ );
316
+ test
317
+ (
318
+ 'parseMarkdown should flush paragraph before a code block.',
319
+ (fDone) =>
320
+ {
321
+ var tmpProvider = createProvider();
322
+ var tmpResult = tmpProvider.parseMarkdown('Some text before code\nstill the same paragraph.\n```\ncode here\n```');
323
+ Expect(tmpResult).to.contain('<p>Some text before code still the same paragraph.</p>');
324
+ Expect(tmpResult).to.contain('<pre>');
325
+ Expect(tmpResult).to.contain('code here');
326
+ fDone();
327
+ }
328
+ );
329
+ test
330
+ (
331
+ 'parseMarkdown should flush paragraph before a blockquote.',
332
+ (fDone) =>
333
+ {
334
+ var tmpProvider = createProvider();
335
+ var tmpResult = tmpProvider.parseMarkdown('A multi-line\nparagraph here.\n> A blockquote');
336
+ Expect(tmpResult).to.contain('<p>A multi-line paragraph here.</p>');
337
+ Expect(tmpResult).to.contain('<blockquote>');
338
+ Expect(tmpResult).to.contain('A blockquote');
339
+ fDone();
340
+ }
341
+ );
342
+ test
343
+ (
344
+ 'parseMarkdown should handle a paragraph after a code block.',
345
+ (fDone) =>
346
+ {
347
+ var tmpProvider = createProvider();
348
+ var tmpResult = tmpProvider.parseMarkdown('```\ncode\n```\nA paragraph that\nfollows the code block.');
349
+ Expect(tmpResult).to.contain('<pre>');
350
+ Expect(tmpResult).to.contain('<p>A paragraph that follows the code block.</p>');
351
+ fDone();
352
+ }
353
+ );
354
+ test
355
+ (
356
+ 'parseMarkdown should handle inline formatting within multi-line paragraphs.',
357
+ (fDone) =>
358
+ {
359
+ var tmpProvider = createProvider();
360
+ var tmpResult = tmpProvider.parseMarkdown('This paragraph has **bold** on the first line\nand *italic* on the second line.');
361
+ Expect(tmpResult).to.contain('<strong>bold</strong>');
362
+ Expect(tmpResult).to.contain('<em>italic</em>');
363
+ // Should be a single paragraph
364
+ var tmpParagraphCount = (tmpResult.match(/<p>/g) || []).length;
365
+ Expect(tmpParagraphCount).to.equal(1);
366
+ fDone();
367
+ }
368
+ );
369
+ test
370
+ (
371
+ 'parseMarkdown should handle hand-wrapped README-style paragraphs.',
372
+ (fDone) =>
373
+ {
374
+ var tmpProvider = createProvider();
375
+ var tmpInput = 'Ultravisor is a process supervisor and service\n'
376
+ + 'orchestrator built on the Fable ecosystem.\n'
377
+ + 'It manages the lifecycle of multiple child\n'
378
+ + 'processes from a single configuration.\n'
379
+ + '\n'
380
+ + 'Designed for development and production\n'
381
+ + 'environments alike, it provides log\n'
382
+ + 'aggregation and automatic restarts.';
383
+ var tmpResult = tmpProvider.parseMarkdown(tmpInput);
384
+ var tmpParagraphCount = (tmpResult.match(/<p>/g) || []).length;
385
+ Expect(tmpParagraphCount).to.equal(2, 'Should produce exactly two paragraphs.');
386
+ // First paragraph should contain all four lines joined
387
+ Expect(tmpResult).to.contain('Ultravisor is a process supervisor and service');
388
+ Expect(tmpResult).to.contain('orchestrator built on the Fable ecosystem.');
389
+ // Second paragraph should contain all three lines joined
390
+ Expect(tmpResult).to.contain('Designed for development and production');
391
+ Expect(tmpResult).to.contain('aggregation and automatic restarts.');
392
+ fDone();
393
+ }
394
+ );
395
+ }
396
+ );
397
+
258
398
  suite
259
399
  (
260
400
  'Inline Markdown Parsing',