mirror of
https://github.com/PR0M3TH3AN/Artstr-Studio.git
synced 2026-10-27 08:40:39 +00:00
book(C.5.1): vendor marked + Add chapter button + markdown editor
Reflowable chapters take their first step. The Pages overview now has a "+ Add chapter" button next to "+ Add page" / "+ Add 10 pages". Clicking it appends a `type: 'reflow'` entry to the manifest, opens a fresh markdown editor pane, and seeds it with "# Chapter N\\n\\nWrite your chapter here." - Vendored `[email protected]` (~36 KB minified, MIT) as src/vendor/marked.min.js. Loaded as a regular <script> next to polygon-clipping and pdf-lib's future home. - Reflow entries store `chapterMarkdown` locally; the `textRef` / `textPinnedEventId` fields stay null until D1 maps each chapter to a real NIP-23 article event. masterId defaults to spec.defaultMasterId. - New `#bookChapterEditor` two-pane view: textarea on the left (autosaves to entry.chapterMarkdown via pushHistoryDebounced), rendered HTML preview on the right via `marked.parse`. Mangling + header-id auto-generation off; <script> tags get belt-and-braces stripped from the parse output. - Body class `editing-book-chapter` flips the view: bookView and the canvas chrome (sheet, palette, tools, layers panel) all hide so the user sees only the editor. Shared editing-book-page CSS already handled hiding canvas chrome via the :not(.editing-book-page) selector, which I widened to also :not(.editing-book-chapter) for #bookView. - Toolbar: chapter title input (writes back to entry.chapterTitle on input), "← Back to Pages" button (clears editingChapterId, returns to the grid), and a pages-readout placeholder showing "Pagination preview lands in Phase C.5.2". - Clicking a reflow tile in the overview now opens the chapter editor (was a no-op toast in B2). Esc returns to the overview same as the page editor / master editor paths. - syncBookChapterEditor() runs from render() so autosave restore lands the user on the right pane without losing typed input (textarea/title skip syncing when focused). Phase C.5.2 wires the pagination engine and replaces the textarea preview with a paginated stack of master-themed pages.
This commit is contained in:
1 parent
4e75db99b8
commit
f41e72e942
2 files changed
+223
-7
No files matched your search
+217
-7
@@ -1502,9 +1502,68 @@
|
||||
body.template-book .jewelSpineGuide,
|
||||
body.template-book .spineText { display: none !important; }
|
||||
|
||||
/* Markdown chapter editor — shown when a reflow entry is open
|
||||
on the book canvas. Two-pane layout: textarea on the left,
|
||||
paginated preview on the right. */
|
||||
#bookChapterEditor { display: none; }
|
||||
body.template-book.editing-book-chapter #bookChapterEditor {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%; gap: 10px;
|
||||
padding: 14px 18px;
|
||||
box-sizing: border-box;
|
||||
min-height: calc(100vh - 160px);
|
||||
}
|
||||
.bookChapterEditorToolbar {
|
||||
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
|
||||
padding-bottom: 8px; border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.bookChapterEditorToolbar input[type="text"] {
|
||||
flex: 1; min-width: 160px;
|
||||
font-size: 1rem; font-weight: 600;
|
||||
padding: 4px 8px;
|
||||
border: 1px solid var(--line);
|
||||
}
|
||||
.bookChapterEditorPages {
|
||||
font-size: .78rem; color: var(--muted); white-space: nowrap;
|
||||
}
|
||||
.bookChapterEditorBody {
|
||||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 10px;
|
||||
min-height: 0;
|
||||
}
|
||||
#bookChapterEditorTextarea {
|
||||
width: 100%; height: 100%;
|
||||
padding: 12px;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
font-size: 13px; line-height: 1.55;
|
||||
border: 1px solid var(--line); background: #fff;
|
||||
resize: none;
|
||||
}
|
||||
.bookChapterEditorPreviewWrap {
|
||||
border: 1px solid var(--line); background: #fff;
|
||||
overflow: auto;
|
||||
padding: 16px 20px;
|
||||
}
|
||||
#bookChapterEditorPreview { font-family: Georgia, serif; line-height: 1.6; }
|
||||
#bookChapterEditorPreview h1 { font-family: Helvetica, Arial, sans-serif; font-size: 2rem; margin: 0 0 .6em; }
|
||||
#bookChapterEditorPreview h2 { font-family: Helvetica, Arial, sans-serif; font-size: 1.5rem; margin: 1.2em 0 .4em; }
|
||||
#bookChapterEditorPreview h3 { font-family: Helvetica, Arial, sans-serif; font-size: 1.2rem; margin: 1em 0 .4em; }
|
||||
#bookChapterEditorPreview p { margin: 0 0 .8em; }
|
||||
#bookChapterEditorPreview blockquote { margin: .8em 1.2em; font-style: italic; color: #4b5563; }
|
||||
#bookChapterEditorPreview code { background: #f5f5f5; padding: 1px 5px; font-size: .92em; }
|
||||
#bookChapterEditorPreview pre { background: #f5f5f5; padding: 10px 12px; overflow-x: auto; }
|
||||
#bookChapterEditorPreview pre code { background: none; padding: 0; }
|
||||
#bookChapterEditorPreview a { color: #0066cc; }
|
||||
#bookChapterEditorPreview hr { border: 0; border-top: 1px solid #cccccc; margin: 1.2em 0; }
|
||||
#bookChapterEditorPreview ul, #bookChapterEditorPreview ol { padding-left: 1.4em; margin: 0 0 .8em; }
|
||||
#bookChapterEditorPreview img { max-width: 100%; }
|
||||
|
||||
/* Book view shell — mirrors the deck-sorter layout pattern. */
|
||||
#bookView { display: none; }
|
||||
body.template-book:not(.editing-book-page) #bookView {
|
||||
body.template-book:not(.editing-book-page):not(.editing-book-chapter) #bookView {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
@@ -4259,6 +4318,21 @@
|
||||
<div class="deckSlideGrid" id="deckSlideGrid"></div>
|
||||
</div>
|
||||
|
||||
<div id="bookChapterEditor">
|
||||
<div class="bookChapterEditorToolbar">
|
||||
<button type="button" id="bookChapterEditorBack">← Back to Pages</button>
|
||||
<input type="text" id="bookChapterEditorTitle" placeholder="Chapter title" />
|
||||
<span class="bookChapterEditorPages" id="bookChapterEditorPages"></span>
|
||||
<span class="bookViewSpacer"></span>
|
||||
<span class="hint" id="bookChapterEditorHint">Markdown autosaves to this book. Phase D1 publishes as a NIP-23 article.</span>
|
||||
</div>
|
||||
<div class="bookChapterEditorBody">
|
||||
<textarea id="bookChapterEditorTextarea" placeholder="# Chapter 1 Write your chapter here…"></textarea>
|
||||
<div class="bookChapterEditorPreviewWrap">
|
||||
<div id="bookChapterEditorPreview"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bookView">
|
||||
<div class="bookViewToggleBar">
|
||||
<button type="button" id="bookViewTogglePages" class="bookViewToggle active">Pages</button>
|
||||
@@ -4271,10 +4345,11 @@
|
||||
<div class="buttonRow">
|
||||
<button type="button" id="bookAddPageBtn" class="primary">+ Add page</button>
|
||||
<button type="button" id="bookAddTenBtn">+ Add 10 pages</button>
|
||||
<button type="button" id="bookAddChapterBtn">+ Add chapter</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="deckSlideGrid" id="bookPagesGrid"></div>
|
||||
<p class="hint" id="bookPagesHint" style="margin:8px 0 0">Phase A4 skeleton: tiles are placeholders. Click a tile in Phase B to edit the page. Reflow / NIP-23 chapters arrive in Phase C.5; per-page Nostr publish in Phase D1.</p>
|
||||
<p class="hint" id="bookPagesHint" style="margin:8px 0 0">Click a designed-page tile to edit it on the canvas. Click a chapter tile to edit its markdown. Per-page Nostr publish (per-event sidecars + manifest) lands in Phase D1.</p>
|
||||
</div>
|
||||
<div id="bookCoverView" style="display:none">
|
||||
<div class="bookCoverSummary" id="bookCoverSummary"></div>
|
||||
@@ -5363,6 +5438,7 @@
|
||||
|
||||
<script src="vendor/qrcode.min.js"></script>
|
||||
<script src="vendor/polygon-clipping.min.js"></script>
|
||||
<script src="vendor/marked.min.js"></script>
|
||||
<script>
|
||||
const $ = (id) => document.getElementById(id);
|
||||
const safe$ = (id) => { try { return $(id); } catch { return null; } };
|
||||
@@ -8561,6 +8637,39 @@
|
||||
syncInputs();
|
||||
render();
|
||||
}
|
||||
// Add a fresh reflow chapter entry. Phase C.5 stores the
|
||||
// markdown locally on the entry; Phase D1 will publish it as a
|
||||
// NIP-23 article (kind-30023) and replace `chapterMarkdown`
|
||||
// with a real `textRef`. The default master is required for the
|
||||
// chapter to paginate, and the picker in C.5.x will let users
|
||||
// pick a different one.
|
||||
function addBookChapter() {
|
||||
const book = ensureBookState();
|
||||
pushHistory('book: add chapter');
|
||||
const num = (book.pages.filter(p => p.type === 'reflow').length || 0) + 1;
|
||||
const entry = {
|
||||
id: makeBookEntryId(),
|
||||
type: 'reflow',
|
||||
textRef: null,
|
||||
textPinnedEventId: null,
|
||||
chapterMarkdown: `# Chapter ${num}\n\nWrite your chapter here.`,
|
||||
masterId: book.spec?.defaultMasterId || null,
|
||||
masterRef: null,
|
||||
chapterTitle: `Chapter ${num}`,
|
||||
chapterNumber: num,
|
||||
startsOnPage: 'any',
|
||||
skipNumberOnFirstPage: false,
|
||||
styleOverrides: null,
|
||||
gating: null,
|
||||
};
|
||||
book.pages.push(entry);
|
||||
renderBookPagesGrid();
|
||||
syncInputs();
|
||||
render();
|
||||
// Drop straight into the editor so the user can start writing.
|
||||
openBookChapter(entry.id);
|
||||
}
|
||||
|
||||
function addBookTenPages() {
|
||||
const book = ensureBookState();
|
||||
pushHistory('book: add 10 pages');
|
||||
@@ -8815,15 +8924,18 @@
|
||||
const idx = book.pages.findIndex(p => p.id === entryId);
|
||||
if (idx < 0) return;
|
||||
const entry = book.pages[idx];
|
||||
// Phase B2 supports designed pages only; reflow segments open
|
||||
// in the chapter / markdown editor in C.5.
|
||||
if (entry.type !== 'design') {
|
||||
toastError?.('Reflow chapter editor lands in Phase C.5.');
|
||||
// Reflow segments route to the markdown editor instead of the
|
||||
// canvas editor.
|
||||
if (entry.type === 'reflow') {
|
||||
openBookChapter(entryId);
|
||||
return;
|
||||
}
|
||||
if (entry.type !== 'design') return;
|
||||
book.editingEntryId = entryId;
|
||||
book.editingMasterId = null; // only one editor open at a time
|
||||
book.editingChapterId = null;
|
||||
document.body.classList.add('editing-book-page');
|
||||
document.body.classList.remove('editing-book-chapter');
|
||||
clearLayerSelection?.();
|
||||
try { setEditorTool('select'); } catch {}
|
||||
syncBookPageEditBar();
|
||||
@@ -8839,6 +8951,91 @@
|
||||
syncInputs();
|
||||
render();
|
||||
}
|
||||
// Chapter editor (Phase C.5). Reflow entries open a two-pane
|
||||
// textarea + live preview instead of the canvas. The book stays
|
||||
// in 'book' template mode; an `editingChapterId` field tracks
|
||||
// which entry is active and a body class flips the view.
|
||||
function openBookChapter(entryId) {
|
||||
const book = ensureBookState();
|
||||
const entry = book.pages.find(p => p.id === entryId);
|
||||
if (!entry || entry.type !== 'reflow') return;
|
||||
book.editingChapterId = entryId;
|
||||
book.editingEntryId = null;
|
||||
book.editingMasterId = null;
|
||||
document.body.classList.add('editing-book-chapter');
|
||||
syncBookChapterEditor();
|
||||
syncInputs();
|
||||
render();
|
||||
}
|
||||
function closeBookChapter() {
|
||||
const book = state.book;
|
||||
if (book) book.editingChapterId = null;
|
||||
document.body.classList.remove('editing-book-chapter');
|
||||
syncInputs();
|
||||
render();
|
||||
}
|
||||
// Push entry fields into the editor inputs + render the
|
||||
// markdown preview. Skips the textarea when it currently has
|
||||
// focus so live typing isn't blown away by re-renders.
|
||||
function syncBookChapterEditor() {
|
||||
const book = state.book;
|
||||
const id = book?.editingChapterId;
|
||||
if (!id) return;
|
||||
const entry = book.pages.find(p => p.id === id);
|
||||
if (!entry) return;
|
||||
const titleEl = document.getElementById('bookChapterEditorTitle');
|
||||
const ta = document.getElementById('bookChapterEditorTextarea');
|
||||
const preview = document.getElementById('bookChapterEditorPreview');
|
||||
const pagesEl = document.getElementById('bookChapterEditorPages');
|
||||
if (titleEl && titleEl !== document.activeElement) titleEl.value = entry.chapterTitle || '';
|
||||
if (ta && ta !== document.activeElement) ta.value = entry.chapterMarkdown || '';
|
||||
if (preview) preview.innerHTML = markdownToSafeHtml(entry.chapterMarkdown || '');
|
||||
if (pagesEl) pagesEl.textContent = 'Pagination preview lands in Phase C.5.2';
|
||||
}
|
||||
// Minimal HTML escape + marked render. Sanitizes by routing
|
||||
// through marked.parse with `mangle:false, headerIds:false`
|
||||
// and post-strips any `<script>` tags as belt-and-braces.
|
||||
function markdownToSafeHtml(src) {
|
||||
if (typeof window.marked === 'undefined' || !window.marked.parse) {
|
||||
return '<p>(marked library failed to load)</p>';
|
||||
}
|
||||
try {
|
||||
const html = window.marked.parse(String(src || ''), {
|
||||
mangle: false,
|
||||
headerIds: false,
|
||||
breaks: false,
|
||||
gfm: false,
|
||||
});
|
||||
// Belt-and-braces: drop any embedded <script> just in case.
|
||||
return String(html).replace(/<script[\s\S]*?<\/script>/gi, '');
|
||||
} catch (err) {
|
||||
console.warn('marked parse failed', err);
|
||||
return '<p>(markdown parse error)</p>';
|
||||
}
|
||||
}
|
||||
function updateBookChapterMarkdown(value) {
|
||||
const book = state.book;
|
||||
const id = book?.editingChapterId;
|
||||
if (!id) return;
|
||||
const entry = book.pages.find(p => p.id === id);
|
||||
if (!entry) return;
|
||||
pushHistoryDebounced(`book:chapter:${id}:md`, 'book: edit chapter', 600);
|
||||
entry.chapterMarkdown = String(value || '');
|
||||
// Only re-render preview (cheap); thumb / pagination will
|
||||
// re-run in C.5.2 once the engine exists.
|
||||
const preview = document.getElementById('bookChapterEditorPreview');
|
||||
if (preview) preview.innerHTML = markdownToSafeHtml(entry.chapterMarkdown);
|
||||
}
|
||||
function updateBookChapterTitle(value) {
|
||||
const book = state.book;
|
||||
const id = book?.editingChapterId;
|
||||
if (!id) return;
|
||||
const entry = book.pages.find(p => p.id === id);
|
||||
if (!entry) return;
|
||||
pushHistoryDebounced(`book:chapter:${id}:title`, 'book: rename chapter', 400);
|
||||
entry.chapterTitle = String(value || '');
|
||||
}
|
||||
|
||||
// Master-edit mode: opens a master on the same canvas as the
|
||||
// per-page editor. Same body class so the CSS that hides
|
||||
// Pages overview / shows the sheet + tool palette applies; the
|
||||
@@ -10357,6 +10554,8 @@
|
||||
state.templateMode === 'book' && (!!state.book?.editingEntryId || !!state.book?.editingMasterId));
|
||||
document.body.classList.toggle('editing-book-master',
|
||||
state.templateMode === 'book' && !!state.book?.editingMasterId);
|
||||
document.body.classList.toggle('editing-book-chapter',
|
||||
state.templateMode === 'book' && !!state.book?.editingChapterId);
|
||||
document.body.classList.toggle('editing-deck-slide', !!state.deck && state.deck.editingIndex !== null);
|
||||
document.body.classList.toggle('hide-guides', !state.showGuides);
|
||||
document.body.classList.toggle('hide-bleed', !state.showBleed);
|
||||
@@ -13067,6 +13266,7 @@
|
||||
renderDeckSorter();
|
||||
renderBookPagesGrid();
|
||||
syncBookPageEditBar();
|
||||
syncBookChapterEditor();
|
||||
// Only repaint the cover preview when its view is the active
|
||||
// sub-view — saves work on every render() in book mode.
|
||||
if (document.getElementById('bookCoverView')?.style.display !== 'none'
|
||||
@@ -32059,6 +32259,11 @@
|
||||
// Book Designer — Pages overview + Cover view toggle.
|
||||
on('bookAddPageBtn', 'click', addBookDesignedPage);
|
||||
on('bookAddTenBtn', 'click', addBookTenPages);
|
||||
on('bookAddChapterBtn', 'click', addBookChapter);
|
||||
// Chapter editor panes.
|
||||
on('bookChapterEditorBack', 'click', closeBookChapter);
|
||||
on('bookChapterEditorTextarea', 'input', (e) => updateBookChapterMarkdown(e.target.value));
|
||||
on('bookChapterEditorTitle', 'input', (e) => updateBookChapterTitle(e.target.value));
|
||||
on('bookViewTogglePages', 'click', () => setBookSubView('pages'));
|
||||
on('bookViewToggleCover', 'click', () => setBookSubView('cover'));
|
||||
on('bookPageEditBack', 'click', () => {
|
||||
@@ -32398,11 +32603,16 @@
|
||||
const bookMastersM = $('bookMastersModal');
|
||||
if (bookMastersM && bookMastersM.getAttribute('aria-hidden') === 'false') { closeBookMastersModal(); return; }
|
||||
// Esc while editing a book surface returns to the right home:
|
||||
// master-edit → masters modal, page-edit → Pages overview.
|
||||
// master-edit → masters modal, page-edit / chapter-edit →
|
||||
// Pages overview.
|
||||
if (state.templateMode === 'book' && state.book?.editingMasterId) {
|
||||
closeBookMaster();
|
||||
return;
|
||||
}
|
||||
if (state.templateMode === 'book' && state.book?.editingChapterId) {
|
||||
closeBookChapter();
|
||||
return;
|
||||
}
|
||||
if (state.templateMode === 'book' && state.book?.editingEntryId) {
|
||||
closeBookPage();
|
||||
return;
|
||||
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
/**
|
||||
* marked v14.1.4 - a markdown parser
|
||||
* Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed)
|
||||
* https://github.com/markedjs/marked
|
||||
*/
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).marked={})}(this,(function(e){"use strict";function t(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}function n(t){e.defaults=t}e.defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};const s=/[&<>"']/,r=new RegExp(s.source,"g"),i=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,l=new RegExp(i.source,"g"),o={"&":"&","<":"<",">":">",'"':""","'":"'"},a=e=>o[e];function c(e,t){if(t){if(s.test(e))return e.replace(r,a)}else if(i.test(e))return e.replace(l,a);return e}const h=/(^|[^\[])\^/g;function p(e,t){let n="string"==typeof e?e:e.source;t=t||"";const s={replace:(e,t)=>{let r="string"==typeof t?t:t.source;return r=r.replace(h,"$1"),n=n.replace(e,r),s},getRegex:()=>new RegExp(n,t)};return s}function u(e){try{e=encodeURI(e).replace(/%25/g,"%")}catch{return null}return e}const k={exec:()=>null};function g(e,t){const n=e.replace(/\|/g,((e,t,n)=>{let s=!1,r=t;for(;--r>=0&&"\\"===n[r];)s=!s;return s?"|":" |"})).split(/ \|/);let s=0;if(n[0].trim()||n.shift(),n.length>0&&!n[n.length-1].trim()&&n.pop(),t)if(n.length>t)n.splice(t);else for(;n.length<t;)n.push("");for(;s<n.length;s++)n[s]=n[s].trim().replace(/\\\|/g,"|");return n}function f(e,t,n){const s=e.length;if(0===s)return"";let r=0;for(;r<s;){const i=e.charAt(s-r-1);if(i!==t||n){if(i===t||!n)break;r++}else r++}return e.slice(0,s-r)}function d(e,t,n,s){const r=t.href,i=t.title?c(t.title):null,l=e[1].replace(/\\([\[\]])/g,"$1");if("!"!==e[0].charAt(0)){s.state.inLink=!0;const e={type:"link",raw:n,href:r,title:i,text:l,tokens:s.inlineTokens(l)};return s.state.inLink=!1,e}return{type:"image",raw:n,href:r,title:i,text:c(l)}}class x{options;rules;lexer;constructor(t){this.options=t||e.defaults}space(e){const t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(/^(?: {1,4}| {0,3}\t)/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:f(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],n=function(e,t){const n=e.match(/^(\s+)(?:```)/);if(null===n)return t;const s=n[1];return t.split("\n").map((e=>{const t=e.match(/^\s+/);if(null===t)return e;const[n]=t;return n.length>=s.length?e.slice(s.length):e})).join("\n")}(e,t[3]||"");return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:n}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(/#$/.test(e)){const t=f(e,"#");this.options.pedantic?e=t.trim():t&&!/ $/.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:f(t[0],"\n")}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){let e=f(t[0],"\n").split("\n"),n="",s="";const r=[];for(;e.length>0;){let t=!1;const i=[];let l;for(l=0;l<e.length;l++)if(/^ {0,3}>/.test(e[l]))i.push(e[l]),t=!0;else{if(t)break;i.push(e[l])}e=e.slice(l);const o=i.join("\n"),a=o.replace(/\n {0,3}((?:=+|-+) *)(?=\n|$)/g,"\n $1").replace(/^ {0,3}>[ \t]?/gm,"");n=n?`${n}\n${o}`:o,s=s?`${s}\n${a}`:a;const c=this.lexer.state.top;if(this.lexer.state.top=!0,this.lexer.blockTokens(a,r,!0),this.lexer.state.top=c,0===e.length)break;const h=r[r.length-1];if("code"===h?.type)break;if("blockquote"===h?.type){const t=h,i=t.raw+"\n"+e.join("\n"),l=this.blockquote(i);r[r.length-1]=l,n=n.substring(0,n.length-t.raw.length)+l.raw,s=s.substring(0,s.length-t.text.length)+l.text;break}if("list"!==h?.type);else{const t=h,i=t.raw+"\n"+e.join("\n"),l=this.list(i);r[r.length-1]=l,n=n.substring(0,n.length-h.raw.length)+l.raw,s=s.substring(0,s.length-t.raw.length)+l.raw,e=i.substring(r[r.length-1].raw.length).split("\n")}}return{type:"blockquote",raw:n,tokens:r,text:s}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim();const s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");const i=new RegExp(`^( {0,3}${n})((?:[\t ][^\\n]*)?(?:\\n|$))`);let l=!1;for(;e;){let n=!1,s="",o="";if(!(t=i.exec(e)))break;if(this.rules.block.hr.test(e))break;s=t[0],e=e.substring(s.length);let a=t[2].split("\n",1)[0].replace(/^\t+/,(e=>" ".repeat(3*e.length))),c=e.split("\n",1)[0],h=!a.trim(),p=0;if(this.options.pedantic?(p=2,o=a.trimStart()):h?p=t[1].length+1:(p=t[2].search(/[^ ]/),p=p>4?1:p,o=a.slice(p),p+=t[1].length),h&&/^[ \t]*$/.test(c)&&(s+=c+"\n",e=e.substring(c.length+1),n=!0),!n){const t=new RegExp(`^ {0,${Math.min(3,p-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?
Line truncated
|
||||
Reference in new issue
Block a user