@docsector/docsector-reader 3.4.0 → 3.6.0
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.
- package/README.md +17 -0
- package/bin/docsector.js +1 -1
- package/jsconfig.json +1 -1
- package/package.json +1 -1
- package/public/images/cards/getting-started-cover.svg +60 -0
- package/public/images/cards/quick-links-cover.svg +71 -0
- package/src/components/DBlockCard.vue +223 -0
- package/src/components/DPageEmbeddedUrl.vue +375 -0
- package/src/components/DPageTokens.vue +15 -0
- package/src/components/page-section-tokens.js +123 -2
- package/src/composables/useEmbeddedUrl.js +365 -0
- package/src/pages/manual/content/blocks/cards.overview.en-US.md +32 -0
- package/src/pages/manual/content/blocks/cards.overview.pt-BR.md +32 -0
- package/src/pages/manual/content/blocks/cards.showcase.en-US.md +39 -0
- package/src/pages/manual/content/blocks/cards.showcase.pt-BR.md +39 -0
- package/src/pages/manual/content/blocks/embedded-urls.overview.en-US.md +33 -0
- package/src/pages/manual/content/blocks/embedded-urls.overview.pt-BR.md +33 -0
- package/src/pages/manual/content/blocks/embedded-urls.showcase.en-US.md +25 -0
- package/src/pages/manual/content/blocks/embedded-urls.showcase.pt-BR.md +25 -0
- package/src/pages/manual.index.js +56 -0
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { useI18n } from 'vue-i18n'
|
|
4
|
+
|
|
5
|
+
import { resolveEmbeddedUrl } from '../composables/useEmbeddedUrl'
|
|
6
|
+
|
|
7
|
+
defineOptions({
|
|
8
|
+
name: 'DPageEmbeddedUrl'
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const props = defineProps({
|
|
12
|
+
url: {
|
|
13
|
+
type: String,
|
|
14
|
+
default: ''
|
|
15
|
+
},
|
|
16
|
+
title: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: ''
|
|
19
|
+
},
|
|
20
|
+
caption: {
|
|
21
|
+
type: String,
|
|
22
|
+
default: ''
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const { t } = useI18n()
|
|
27
|
+
|
|
28
|
+
const resolved = computed(() => {
|
|
29
|
+
return resolveEmbeddedUrl(props.url, {
|
|
30
|
+
title: props.title
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const isEmbedded = computed(() => {
|
|
35
|
+
return resolved.value.mode === 'embed' && resolved.value.embedSrc !== ''
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const isCompactEmbed = computed(() => {
|
|
39
|
+
return isEmbedded.value && resolved.value.provider === 'spotify'
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const displayTitle = computed(() => {
|
|
43
|
+
return resolved.value.title || props.title || resolved.value.providerLabel || props.url
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const displayUrl = computed(() => {
|
|
47
|
+
return resolved.value.displayUrl || props.url
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const compactUrl = computed(() => {
|
|
51
|
+
return String(displayUrl.value || '').replace(/^https?:\/\//i, '')
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
const frameStyle = computed(() => {
|
|
55
|
+
const style = {}
|
|
56
|
+
|
|
57
|
+
if (resolved.value.aspectRatio) {
|
|
58
|
+
style.aspectRatio = resolved.value.aspectRatio
|
|
59
|
+
} else {
|
|
60
|
+
style.aspectRatio = 'auto'
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (resolved.value.frameHeight > 0) {
|
|
64
|
+
style.height = `${resolved.value.frameHeight}px`
|
|
65
|
+
style.minHeight = `${resolved.value.frameHeight}px`
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return style
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
const openHref = computed(() => {
|
|
72
|
+
return resolved.value.canonicalUrl || props.url
|
|
73
|
+
})
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<template>
|
|
77
|
+
<div
|
|
78
|
+
class="d-page-embedded-url"
|
|
79
|
+
:class="{
|
|
80
|
+
'd-page-embedded-url--compact': isCompactEmbed,
|
|
81
|
+
'd-page-embedded-url--embedded': isEmbedded,
|
|
82
|
+
'd-page-embedded-url--fallback': !isEmbedded
|
|
83
|
+
}"
|
|
84
|
+
>
|
|
85
|
+
<div
|
|
86
|
+
v-if="isEmbedded"
|
|
87
|
+
class="d-page-embedded-url__frame-shell"
|
|
88
|
+
:style="frameStyle"
|
|
89
|
+
>
|
|
90
|
+
<iframe
|
|
91
|
+
class="d-page-embedded-url__frame"
|
|
92
|
+
:src="resolved.embedSrc"
|
|
93
|
+
:title="displayTitle"
|
|
94
|
+
:allow="resolved.allow || undefined"
|
|
95
|
+
:allowfullscreen="resolved.allowFullscreen"
|
|
96
|
+
loading="lazy"
|
|
97
|
+
referrerpolicy="strict-origin-when-cross-origin"
|
|
98
|
+
></iframe>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<div
|
|
102
|
+
v-if="!isCompactEmbed || caption"
|
|
103
|
+
class="d-page-embedded-url__body"
|
|
104
|
+
>
|
|
105
|
+
<template v-if="!isCompactEmbed">
|
|
106
|
+
<div
|
|
107
|
+
v-if="!isEmbedded"
|
|
108
|
+
class="d-page-embedded-url__media"
|
|
109
|
+
aria-hidden="true"
|
|
110
|
+
>
|
|
111
|
+
<q-icon
|
|
112
|
+
:name="resolved.icon || 'link'"
|
|
113
|
+
size="28px"
|
|
114
|
+
/>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<div class="d-page-embedded-url__content">
|
|
118
|
+
<div
|
|
119
|
+
v-if="resolved.providerLabel"
|
|
120
|
+
class="d-page-embedded-url__provider"
|
|
121
|
+
>
|
|
122
|
+
<q-icon
|
|
123
|
+
:name="resolved.icon || 'link'"
|
|
124
|
+
size="16px"
|
|
125
|
+
/>
|
|
126
|
+
<span>{{ resolved.providerLabel }}</span>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div class="d-page-embedded-url__title">{{ displayTitle }}</div>
|
|
130
|
+
|
|
131
|
+
<div
|
|
132
|
+
v-if="compactUrl"
|
|
133
|
+
class="d-page-embedded-url__url"
|
|
134
|
+
>{{ compactUrl }}</div>
|
|
135
|
+
|
|
136
|
+
<div
|
|
137
|
+
v-if="caption"
|
|
138
|
+
class="d-page-embedded-url__caption"
|
|
139
|
+
v-html="caption"
|
|
140
|
+
></div>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<div class="d-page-embedded-url__actions">
|
|
144
|
+
<q-btn
|
|
145
|
+
no-caps
|
|
146
|
+
unelevated
|
|
147
|
+
padding="8px 12px"
|
|
148
|
+
class="d-page-embedded-url__action-button"
|
|
149
|
+
icon="open_in_new"
|
|
150
|
+
:label="t('page.file.open')"
|
|
151
|
+
:href="openHref"
|
|
152
|
+
target="_blank"
|
|
153
|
+
rel="noopener noreferrer"
|
|
154
|
+
/>
|
|
155
|
+
</div>
|
|
156
|
+
</template>
|
|
157
|
+
|
|
158
|
+
<div
|
|
159
|
+
v-else-if="caption"
|
|
160
|
+
class="d-page-embedded-url__compact-caption"
|
|
161
|
+
v-html="caption"
|
|
162
|
+
></div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</template>
|
|
166
|
+
|
|
167
|
+
<style lang="sass">
|
|
168
|
+
body.body--light
|
|
169
|
+
--d-page-embedded-url-bg: linear-gradient(180deg, #f7faf5 0%, #ffffff 100%)
|
|
170
|
+
--d-page-embedded-url-border: rgba(52, 85, 54, 0.14)
|
|
171
|
+
--d-page-embedded-url-shadow: rgba(52, 85, 54, 0.08)
|
|
172
|
+
--d-page-embedded-url-frame-bg: rgba(44, 60, 45, 0.04)
|
|
173
|
+
--d-page-embedded-url-media-bg: rgba(255, 255, 255, 0.92)
|
|
174
|
+
--d-page-embedded-url-media-border: rgba(52, 85, 54, 0.08)
|
|
175
|
+
--d-page-embedded-url-accent: #30583a
|
|
176
|
+
--d-page-embedded-url-meta: #56715c
|
|
177
|
+
--d-page-embedded-url-caption: #405148
|
|
178
|
+
--d-page-embedded-url-action-border: rgba(52, 85, 54, 0.18)
|
|
179
|
+
--d-page-embedded-url-action-hover: rgba(52, 85, 54, 0.06)
|
|
180
|
+
|
|
181
|
+
body.body--dark
|
|
182
|
+
--d-page-embedded-url-bg: linear-gradient(180deg, rgba(226, 255, 234, 0.05) 0%, rgba(255, 255, 255, 0.02) 100%)
|
|
183
|
+
--d-page-embedded-url-border: rgba(214, 245, 224, 0.14)
|
|
184
|
+
--d-page-embedded-url-shadow: rgba(0, 0, 0, 0.3)
|
|
185
|
+
--d-page-embedded-url-frame-bg: rgba(255, 255, 255, 0.03)
|
|
186
|
+
--d-page-embedded-url-media-bg: rgba(255, 255, 255, 0.06)
|
|
187
|
+
--d-page-embedded-url-media-border: rgba(255, 255, 255, 0.1)
|
|
188
|
+
--d-page-embedded-url-accent: #b9e2c5
|
|
189
|
+
--d-page-embedded-url-meta: rgba(255, 255, 255, 0.72)
|
|
190
|
+
--d-page-embedded-url-caption: rgba(255, 255, 255, 0.9)
|
|
191
|
+
--d-page-embedded-url-action-border: rgba(214, 245, 224, 0.16)
|
|
192
|
+
--d-page-embedded-url-action-hover: rgba(214, 245, 224, 0.08)
|
|
193
|
+
|
|
194
|
+
.d-page-embedded-url
|
|
195
|
+
margin: 1.5rem 0
|
|
196
|
+
border: 1px solid var(--d-page-embedded-url-border)
|
|
197
|
+
border-radius: 18px
|
|
198
|
+
background: var(--d-page-embedded-url-bg)
|
|
199
|
+
box-shadow: 0 16px 36px var(--d-page-embedded-url-shadow)
|
|
200
|
+
overflow: hidden
|
|
201
|
+
|
|
202
|
+
.d-page-embedded-url__frame-shell
|
|
203
|
+
position: relative
|
|
204
|
+
width: 100%
|
|
205
|
+
min-height: 240px
|
|
206
|
+
aspect-ratio: 16 / 9
|
|
207
|
+
background: var(--d-page-embedded-url-frame-bg)
|
|
208
|
+
border-bottom: 1px solid var(--d-page-embedded-url-border)
|
|
209
|
+
|
|
210
|
+
.d-page-embedded-url__frame
|
|
211
|
+
position: absolute
|
|
212
|
+
inset: 0
|
|
213
|
+
width: 100%
|
|
214
|
+
height: 100%
|
|
215
|
+
border: 0
|
|
216
|
+
background: transparent
|
|
217
|
+
|
|
218
|
+
.d-page-embedded-url__body
|
|
219
|
+
display: flex
|
|
220
|
+
align-items: center
|
|
221
|
+
gap: 1rem
|
|
222
|
+
padding: 0.95rem 1rem
|
|
223
|
+
|
|
224
|
+
.d-page-embedded-url--embedded
|
|
225
|
+
.d-page-embedded-url__body
|
|
226
|
+
padding-top: 1.25rem
|
|
227
|
+
|
|
228
|
+
.d-page-embedded-url__content
|
|
229
|
+
padding-top: 0.1rem
|
|
230
|
+
|
|
231
|
+
.d-page-embedded-url--compact
|
|
232
|
+
border: 0
|
|
233
|
+
border-radius: 0
|
|
234
|
+
background: transparent
|
|
235
|
+
box-shadow: none
|
|
236
|
+
overflow: visible
|
|
237
|
+
|
|
238
|
+
.d-page-embedded-url__frame-shell
|
|
239
|
+
border: 0
|
|
240
|
+
background: transparent
|
|
241
|
+
|
|
242
|
+
.d-page-embedded-url__body
|
|
243
|
+
display: block
|
|
244
|
+
padding: 0.6rem 0 0
|
|
245
|
+
|
|
246
|
+
.d-page-embedded-url__compact-caption
|
|
247
|
+
margin-top: 0.65rem
|
|
248
|
+
color: var(--d-page-embedded-url-caption)
|
|
249
|
+
|
|
250
|
+
> :first-child
|
|
251
|
+
margin-top: 0
|
|
252
|
+
|
|
253
|
+
> :last-child
|
|
254
|
+
margin-bottom: 0
|
|
255
|
+
|
|
256
|
+
.d-page-embedded-url__media
|
|
257
|
+
width: 56px
|
|
258
|
+
height: 56px
|
|
259
|
+
flex: 0 0 56px
|
|
260
|
+
display: flex
|
|
261
|
+
align-items: center
|
|
262
|
+
justify-content: center
|
|
263
|
+
border-radius: 16px
|
|
264
|
+
background: var(--d-page-embedded-url-media-bg)
|
|
265
|
+
box-shadow: inset 0 0 0 1px var(--d-page-embedded-url-media-border)
|
|
266
|
+
color: var(--d-page-embedded-url-accent)
|
|
267
|
+
|
|
268
|
+
.d-page-embedded-url__content
|
|
269
|
+
min-width: 0
|
|
270
|
+
flex: 1 1 auto
|
|
271
|
+
|
|
272
|
+
.d-page-embedded-url__provider
|
|
273
|
+
display: inline-flex
|
|
274
|
+
align-items: center
|
|
275
|
+
gap: 0.35rem
|
|
276
|
+
margin-bottom: 0.35rem
|
|
277
|
+
color: var(--d-page-embedded-url-meta)
|
|
278
|
+
font-size: 0.82rem
|
|
279
|
+
font-weight: 700
|
|
280
|
+
line-height: 1
|
|
281
|
+
text-transform: uppercase
|
|
282
|
+
letter-spacing: 0.06em
|
|
283
|
+
|
|
284
|
+
.d-page-embedded-url__title
|
|
285
|
+
font-size: 1rem
|
|
286
|
+
font-weight: 700
|
|
287
|
+
line-height: 1.4
|
|
288
|
+
word-break: break-word
|
|
289
|
+
|
|
290
|
+
.d-page-embedded-url__url
|
|
291
|
+
margin-top: 0.2rem
|
|
292
|
+
color: var(--d-page-embedded-url-meta)
|
|
293
|
+
font-size: 0.84rem
|
|
294
|
+
line-height: 1.35
|
|
295
|
+
word-break: break-all
|
|
296
|
+
|
|
297
|
+
.d-page-embedded-url__caption
|
|
298
|
+
margin-top: 0.45rem
|
|
299
|
+
color: var(--d-page-embedded-url-caption)
|
|
300
|
+
|
|
301
|
+
> :first-child
|
|
302
|
+
margin-top: 0
|
|
303
|
+
|
|
304
|
+
> :last-child
|
|
305
|
+
margin-bottom: 0
|
|
306
|
+
|
|
307
|
+
.d-page-embedded-url__actions
|
|
308
|
+
flex: 0 0 auto
|
|
309
|
+
display: flex
|
|
310
|
+
align-items: center
|
|
311
|
+
align-self: stretch
|
|
312
|
+
|
|
313
|
+
.d-page-embedded-url__action-button
|
|
314
|
+
min-height: 40px
|
|
315
|
+
border-radius: 10px
|
|
316
|
+
border: 1px solid var(--d-page-embedded-url-action-border)
|
|
317
|
+
background: transparent !important
|
|
318
|
+
color: var(--d-page-embedded-url-accent) !important
|
|
319
|
+
transition: transform 0.18s ease, background-color 0.18s ease, border-color 0.18s ease
|
|
320
|
+
|
|
321
|
+
.q-btn__content
|
|
322
|
+
gap: 0.45rem
|
|
323
|
+
font-size: 0.9rem
|
|
324
|
+
font-weight: 600
|
|
325
|
+
line-height: 1
|
|
326
|
+
|
|
327
|
+
.q-focus-helper,
|
|
328
|
+
&:before,
|
|
329
|
+
&:after
|
|
330
|
+
display: none
|
|
331
|
+
|
|
332
|
+
&:hover
|
|
333
|
+
transform: translateY(-1px)
|
|
334
|
+
background: var(--d-page-embedded-url-action-hover) !important
|
|
335
|
+
|
|
336
|
+
&:focus-visible
|
|
337
|
+
outline: 2px solid var(--d-page-embedded-url-accent)
|
|
338
|
+
outline-offset: 2px
|
|
339
|
+
|
|
340
|
+
.d-page-embedded-url--fallback
|
|
341
|
+
.d-page-embedded-url__body
|
|
342
|
+
padding-block: 1.05rem
|
|
343
|
+
|
|
344
|
+
@media (max-width: 720px)
|
|
345
|
+
.d-page-embedded-url__frame-shell
|
|
346
|
+
min-height: 200px
|
|
347
|
+
|
|
348
|
+
.d-page-embedded-url__body
|
|
349
|
+
flex-wrap: wrap
|
|
350
|
+
align-items: flex-start
|
|
351
|
+
|
|
352
|
+
.d-page-embedded-url__actions
|
|
353
|
+
width: 100%
|
|
354
|
+
justify-content: flex-start
|
|
355
|
+
|
|
356
|
+
.d-page-embedded-url__action-button
|
|
357
|
+
width: 100%
|
|
358
|
+
justify-content: center
|
|
359
|
+
|
|
360
|
+
@media (max-width: 520px)
|
|
361
|
+
.d-page-embedded-url__body
|
|
362
|
+
gap: 0.85rem
|
|
363
|
+
padding: 0.9rem
|
|
364
|
+
|
|
365
|
+
.d-page-embedded-url__media
|
|
366
|
+
width: 48px
|
|
367
|
+
height: 48px
|
|
368
|
+
flex-basis: 48px
|
|
369
|
+
|
|
370
|
+
.d-page-embedded-url__provider
|
|
371
|
+
font-size: 0.76rem
|
|
372
|
+
|
|
373
|
+
.d-page-embedded-url__title
|
|
374
|
+
font-size: 0.95rem
|
|
375
|
+
</style>
|
|
@@ -24,6 +24,8 @@ import DMermaidDiagram from './DMermaidDiagram.vue'
|
|
|
24
24
|
import DPageBlockquote from './DPageBlockquote.vue'
|
|
25
25
|
import DPageImage from './DPageImage.vue'
|
|
26
26
|
import DPageFile from './DPageFile.vue'
|
|
27
|
+
import DPageEmbeddedUrl from './DPageEmbeddedUrl.vue'
|
|
28
|
+
import DBlockCard from './DBlockCard.vue'
|
|
27
29
|
import DQuickLinks from './DQuickLinks.vue'
|
|
28
30
|
import DPageExpandable from './DPageExpandable.vue'
|
|
29
31
|
</script>
|
|
@@ -105,6 +107,13 @@ import DPageExpandable from './DPageExpandable.vue'
|
|
|
105
107
|
:caption="token.caption"
|
|
106
108
|
/>
|
|
107
109
|
|
|
110
|
+
<d-page-embedded-url
|
|
111
|
+
v-else-if="token.tag === 'embedded-url'"
|
|
112
|
+
:url="token.url"
|
|
113
|
+
:title="token.title"
|
|
114
|
+
:caption="token.caption"
|
|
115
|
+
/>
|
|
116
|
+
|
|
108
117
|
<d-page-source-code
|
|
109
118
|
v-else-if="token.tag === 'code'"
|
|
110
119
|
:index="id + token.codeIndex"
|
|
@@ -120,6 +129,12 @@ import DPageExpandable from './DPageExpandable.vue'
|
|
|
120
129
|
:content="token.content"
|
|
121
130
|
/>
|
|
122
131
|
|
|
132
|
+
<d-block-card
|
|
133
|
+
v-else-if="token.tag === 'cards'"
|
|
134
|
+
:title="token.title"
|
|
135
|
+
:items="token.items"
|
|
136
|
+
/>
|
|
137
|
+
|
|
123
138
|
<d-quick-links
|
|
124
139
|
v-else-if="token.tag === 'quick-links'"
|
|
125
140
|
:title="token.title"
|
|
@@ -13,9 +13,11 @@ const ALERT_MESSAGE_TYPES = new Set([
|
|
|
13
13
|
'caution'
|
|
14
14
|
])
|
|
15
15
|
|
|
16
|
+
const CARDS_MARKER_PREFIX = '@@DOCSECTOR_CARDS_'
|
|
16
17
|
const QUICK_LINKS_MARKER_PREFIX = '@@DOCSECTOR_QUICK_LINKS_'
|
|
17
18
|
const EXPANDABLE_MARKER_PREFIX = '@@DOCSECTOR_EXPANDABLE_'
|
|
18
19
|
const FILE_MARKER_PREFIX = '@@DOCSECTOR_FILE_'
|
|
20
|
+
const EMBEDDED_URL_MARKER_PREFIX = '@@DOCSECTOR_EMBEDDED_URL_'
|
|
19
21
|
const CODE_SEGMENT_MARKER_PREFIX = '@@DOCSECTOR_CODE_SEGMENT_'
|
|
20
22
|
const MATH_KATEX_OPTIONS = {
|
|
21
23
|
throwOnError: false,
|
|
@@ -189,6 +191,55 @@ const extractQuickLinksBlocks = (source = '') => {
|
|
|
189
191
|
}
|
|
190
192
|
}
|
|
191
193
|
|
|
194
|
+
const extractCardsBlocks = (source = '') => {
|
|
195
|
+
const map = new Map()
|
|
196
|
+
let index = 0
|
|
197
|
+
|
|
198
|
+
const blockPattern = /<d-(?:block-)?cards\b([^>]*)>([\s\S]*?)<\/d-(?:block-)?cards>/gi
|
|
199
|
+
const replaced = String(source).replace(blockPattern, (_, blockAttrsRaw, inner) => {
|
|
200
|
+
const blockAttrs = parseCustomTagAttributes(blockAttrsRaw)
|
|
201
|
+
const items = []
|
|
202
|
+
const itemPattern = /<d-(?:block-)?card\b([^>]*)\/?\s*>/gi
|
|
203
|
+
|
|
204
|
+
let itemMatch = itemPattern.exec(inner)
|
|
205
|
+
while (itemMatch !== null) {
|
|
206
|
+
const itemAttrs = parseCustomTagAttributes(itemMatch[1])
|
|
207
|
+
const title = itemAttrs.title || ''
|
|
208
|
+
const description = itemAttrs.description || ''
|
|
209
|
+
const to = itemAttrs.to || ''
|
|
210
|
+
const href = itemAttrs.href || ''
|
|
211
|
+
|
|
212
|
+
if (title && description && (to || href)) {
|
|
213
|
+
items.push({
|
|
214
|
+
title,
|
|
215
|
+
description,
|
|
216
|
+
to,
|
|
217
|
+
href,
|
|
218
|
+
image: itemAttrs.image || '',
|
|
219
|
+
icon: itemAttrs.icon || ''
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
itemMatch = itemPattern.exec(inner)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const marker = `${CARDS_MARKER_PREFIX}${index}@@`
|
|
227
|
+
index++
|
|
228
|
+
|
|
229
|
+
map.set(marker, {
|
|
230
|
+
title: blockAttrs.title || '',
|
|
231
|
+
items
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
return `\n${marker}\n`
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
source: replaced,
|
|
239
|
+
cardsMap: map
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
192
243
|
const parseExpandableOpenState = (raw = '') => {
|
|
193
244
|
return ['1', 'true', 'yes', 'on'].includes(String(raw).trim().toLowerCase())
|
|
194
245
|
}
|
|
@@ -274,6 +325,41 @@ const extractFileBlocks = (source = '') => {
|
|
|
274
325
|
}
|
|
275
326
|
}
|
|
276
327
|
|
|
328
|
+
const extractEmbeddedUrlBlocks = (source = '') => {
|
|
329
|
+
const map = new Map()
|
|
330
|
+
let index = 0
|
|
331
|
+
|
|
332
|
+
const replaceBlock = (match, rawAttrs, rawCaption = '') => {
|
|
333
|
+
const attrs = parseCustomTagAttributes(rawAttrs)
|
|
334
|
+
const url = decodeHtmlEntities(attrs.url || attrs.href || attrs.src || '').trim()
|
|
335
|
+
|
|
336
|
+
if (!url) {
|
|
337
|
+
return match
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const marker = `${EMBEDDED_URL_MARKER_PREFIX}${index}@@`
|
|
341
|
+
index++
|
|
342
|
+
|
|
343
|
+
map.set(marker, {
|
|
344
|
+
url,
|
|
345
|
+
title: decodeHtmlEntities(attrs.title || '').trim(),
|
|
346
|
+
caption: String(rawCaption).trim()
|
|
347
|
+
})
|
|
348
|
+
|
|
349
|
+
return `\n${marker}\n`
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const replacedSelfClosing = String(source).replace(/<d-embedded-url\b([^>]*)\/\s*>/gi, (match, rawAttrs) => {
|
|
353
|
+
return replaceBlock(match, rawAttrs)
|
|
354
|
+
})
|
|
355
|
+
const replaced = replacedSelfClosing.replace(/<d-embedded-url\b([^>]*)>([\s\S]*?)<\/d-embedded-url>/gi, replaceBlock)
|
|
356
|
+
|
|
357
|
+
return {
|
|
358
|
+
source: replaced,
|
|
359
|
+
embeddedUrlMap: map
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
277
363
|
const parseFenceAttributes = (raw = '') => {
|
|
278
364
|
const parsed = {}
|
|
279
365
|
const pattern = /([\w-]+)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s;]+))/g
|
|
@@ -565,8 +651,10 @@ export const tokenizePageSectionSource = (source = '', options = {}) => {
|
|
|
565
651
|
})
|
|
566
652
|
})
|
|
567
653
|
|
|
568
|
-
const { source:
|
|
654
|
+
const { source: sourceWithCards, cardsMap } = extractCardsBlocks(sourceWithExpandables)
|
|
655
|
+
const { source: sourceWithQuickLinks, quickLinksMap } = extractQuickLinksBlocks(sourceWithCards)
|
|
569
656
|
const { source: sourceWithFiles, fileMap } = extractFileBlocks(sourceWithQuickLinks)
|
|
657
|
+
const { source: sourceWithEmbeddedUrls, embeddedUrlMap } = extractEmbeddedUrlBlocks(sourceWithFiles)
|
|
570
658
|
|
|
571
659
|
fileMap.forEach((data, marker) => {
|
|
572
660
|
fileMap.set(marker, {
|
|
@@ -575,10 +663,17 @@ export const tokenizePageSectionSource = (source = '', options = {}) => {
|
|
|
575
663
|
})
|
|
576
664
|
})
|
|
577
665
|
|
|
666
|
+
embeddedUrlMap.forEach((data, marker) => {
|
|
667
|
+
embeddedUrlMap.set(marker, {
|
|
668
|
+
...data,
|
|
669
|
+
caption: restoreShieldedCodeSegments(data.caption, codeSegmentsMap)
|
|
670
|
+
})
|
|
671
|
+
})
|
|
672
|
+
|
|
578
673
|
const markdown = createMarkdownBlockParser()
|
|
579
674
|
const markdownInline = createMarkdownInlineParser()
|
|
580
675
|
const markdownEnv = {}
|
|
581
|
-
const parsed = markdown.parse(restoreShieldedCodeSegments(
|
|
676
|
+
const parsed = markdown.parse(restoreShieldedCodeSegments(sourceWithEmbeddedUrls, codeSegmentsMap), markdownEnv)
|
|
582
677
|
const tokens = []
|
|
583
678
|
|
|
584
679
|
let level = 0
|
|
@@ -735,6 +830,17 @@ export const tokenizePageSectionSource = (source = '', options = {}) => {
|
|
|
735
830
|
break
|
|
736
831
|
}
|
|
737
832
|
|
|
833
|
+
if (cardsMap.has(element.content.trim())) {
|
|
834
|
+
const data = cardsMap.get(element.content.trim())
|
|
835
|
+
|
|
836
|
+
tokens.push({
|
|
837
|
+
tag: 'cards',
|
|
838
|
+
title: data.title,
|
|
839
|
+
items: data.items
|
|
840
|
+
})
|
|
841
|
+
break
|
|
842
|
+
}
|
|
843
|
+
|
|
738
844
|
if (quickLinksMap.has(element.content.trim())) {
|
|
739
845
|
const data = quickLinksMap.get(element.content.trim())
|
|
740
846
|
|
|
@@ -762,6 +868,21 @@ export const tokenizePageSectionSource = (source = '', options = {}) => {
|
|
|
762
868
|
break
|
|
763
869
|
}
|
|
764
870
|
|
|
871
|
+
if (embeddedUrlMap.has(element.content.trim())) {
|
|
872
|
+
const data = embeddedUrlMap.get(element.content.trim())
|
|
873
|
+
|
|
874
|
+
tokens.push({
|
|
875
|
+
tag: 'embedded-url',
|
|
876
|
+
map: element.map,
|
|
877
|
+
url: data.url,
|
|
878
|
+
title: data.title,
|
|
879
|
+
caption: data.caption !== ''
|
|
880
|
+
? markdownInline.renderInline(data.caption, markdownEnv)
|
|
881
|
+
: ''
|
|
882
|
+
})
|
|
883
|
+
break
|
|
884
|
+
}
|
|
885
|
+
|
|
765
886
|
if (tag === 'p') {
|
|
766
887
|
const imageToken = parseStandaloneImageToken(element.content)
|
|
767
888
|
|