@peaceroad/markdown-it-figure-with-p-caption 0.11.0 → 0.13.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 +10 -4
- package/imgAttrToPCaption.js +31 -53
- package/index.js +312 -195
- package/package.json +12 -6
- package/.vscode/settings.json +0 -5
- package/test/examples-all-iframe-type-figure-class-name.txt +0 -192
- package/test/examples-console.txt +0 -125
- package/test/examples-has-num-class.txt +0 -31
- package/test/examples-iframe-type-blockquote-without-caption.txt +0 -92
- package/test/examples-iframe-without-caption.txt +0 -64
- package/test/examples-img-alt-caption-number.en.txt +0 -51
- package/test/examples-img-alt-caption.en.txt +0 -60
- package/test/examples-img-alt-caption.ja.txt +0 -84
- package/test/examples-img-title-caption-number.en.txt +0 -60
- package/test/examples-img-title-caption.en.txt +0 -60
- package/test/examples-img-title-caption.ja.txt +0 -30
- package/test/examples-multiple-images.txt +0 -140
- package/test/examples-no-option.txt +0 -770
- package/test/examples-one-image-without-caption.txt +0 -59
- package/test/examples-set-figure-number.en.txt +0 -21
- package/test/examples-video-without-caption.txt +0 -52
- package/test/test.js +0 -208
package/index.js
CHANGED
|
@@ -1,112 +1,136 @@
|
|
|
1
1
|
import { setCaptionParagraph } from 'p7d-markdown-it-p-captions'
|
|
2
2
|
import { imgAttrToPCaption, setAltToLabel, setTitleToLabel } from './imgAttrToPCaption.js'
|
|
3
3
|
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
const htmlRegCache = new Map()
|
|
5
|
+
const classReg = /^f-(.+)$/
|
|
6
|
+
const blueskyEmbedReg = /^<blockquote class="bluesky-embed"[^]*?>[\s\S]*?$/
|
|
7
|
+
const videoIframeReg = /^<[^>]*? src="https:\/\/(?:www.youtube-nocookie.com|player.vimeo.com)\//i
|
|
8
|
+
const classNameReg = /^<[^>]*? class="(twitter-tweet|instagram-media|text-post-media|bluesky-embed|mastodon-embed)"/
|
|
9
|
+
const imageAttrsReg = /^ *\{(.*?)\} *$/
|
|
10
|
+
const classAttrReg = /^\./
|
|
11
|
+
const idAttrReg = /^#/
|
|
12
|
+
const attrParseReg = /^(.*?)="?(.*)"?$/
|
|
13
|
+
const whitespaceReg = /^ *$/
|
|
14
|
+
const sampLangReg = /^ *(?:samp|shell|console)(?:(?= )|$)/
|
|
15
|
+
const endBlockquoteScriptReg = /<\/blockquote> *<script[^>]*?><\/script>$/
|
|
11
16
|
|
|
12
|
-
|
|
17
|
+
const getHtmlReg = (tag) => {
|
|
18
|
+
if (htmlRegCache.has(tag)) return htmlRegCache.get(tag)
|
|
19
|
+
const regexStr = `^<${tag} ?[^>]*?>[\\s\\S]*?<\\/${tag}>(\\n| *?)(<script [^>]*?>(?:<\\/script>)?)? *(\\n|$)`
|
|
20
|
+
const reg = new RegExp(regexStr)
|
|
21
|
+
htmlRegCache.set(tag, reg)
|
|
22
|
+
return reg
|
|
23
|
+
}
|
|
13
24
|
|
|
14
|
-
|
|
15
|
-
if (
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
const getCaptionName = (token) => {
|
|
26
|
+
if (!token.attrs) return ''
|
|
27
|
+
const attrs = token.attrs
|
|
28
|
+
for (let i = 0, len = attrs.length; i < len; i++) {
|
|
29
|
+
const attr = attrs[i]
|
|
30
|
+
if (attr[0] === 'class') {
|
|
31
|
+
const match = attr[1].match(classReg)
|
|
32
|
+
if (match) return match[1]
|
|
33
|
+
}
|
|
20
34
|
}
|
|
35
|
+
return ''
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const checkPrevCaption = (tokens, n, caption, fNum, sp, opt, TokenConstructor) => {
|
|
39
|
+
if(n < 3) return caption
|
|
40
|
+
const captionStartToken = tokens[n-3]
|
|
41
|
+
const captionEndToken = tokens[n-1]
|
|
42
|
+
if (captionStartToken === undefined || captionEndToken === undefined) return
|
|
43
|
+
if (captionStartToken.type !== 'paragraph_open' && captionEndToken.type !== 'paragraph_close') return
|
|
44
|
+
setCaptionParagraph(n-3, { tokens, Token: TokenConstructor }, caption, fNum, sp, opt)
|
|
45
|
+
const captionName = getCaptionName(captionStartToken)
|
|
21
46
|
if(!captionName) return
|
|
22
47
|
caption.name = captionName
|
|
23
48
|
caption.isPrev = true
|
|
24
49
|
return
|
|
25
50
|
}
|
|
26
51
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
const captionEndToken =
|
|
52
|
+
const checkNextCaption = (tokens, en, caption, fNum, sp, opt, TokenConstructor) => {
|
|
53
|
+
if (en + 2 > tokens.length) return
|
|
54
|
+
const captionStartToken = tokens[en+1]
|
|
55
|
+
const captionEndToken = tokens[en+3]
|
|
56
|
+
if (captionStartToken === undefined || captionEndToken === undefined) return
|
|
57
|
+
if (captionStartToken.type !== 'paragraph_open' && captionEndToken.type !== 'paragraph_close') return
|
|
58
|
+
setCaptionParagraph(en+1, { tokens, Token: TokenConstructor }, caption, fNum, sp, opt)
|
|
59
|
+
const captionName = getCaptionName(captionStartToken)
|
|
60
|
+
if(!captionName) return
|
|
61
|
+
caption.name = captionName
|
|
62
|
+
caption.isNext = true
|
|
63
|
+
return
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const cleanCaptionRegCache = new Map()
|
|
67
|
+
|
|
68
|
+
const cleanCaptionTokenAttrs = (token, captionName) => {
|
|
69
|
+
if (!token.attrs) return
|
|
70
|
+
let reg = cleanCaptionRegCache.get(captionName)
|
|
71
|
+
if (!reg) {
|
|
72
|
+
reg = new RegExp(' *?f-' + captionName)
|
|
73
|
+
cleanCaptionRegCache.set(captionName, reg)
|
|
74
|
+
}
|
|
75
|
+
for (let i = token.attrs.length - 1; i >= 0; i--) {
|
|
76
|
+
if (token.attrs[i][0] === 'class') {
|
|
77
|
+
token.attrs[i][1] = token.attrs[i][1].replace(reg, '').trim()
|
|
78
|
+
if (token.attrs[i][1] === '') token.attrs.splice(i, 1)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const changePrevCaptionPosition = (tokens, n, caption, opt) => {
|
|
84
|
+
const captionStartToken = tokens[n-3]
|
|
85
|
+
const captionInlineToken = tokens[n-2]
|
|
86
|
+
const captionEndToken = tokens[n-1]
|
|
31
87
|
|
|
32
88
|
if (opt.imgAltCaption || opt.imgTitleCaption) {
|
|
33
89
|
let isNoCaption = false
|
|
34
90
|
if (captionInlineToken.attrs) {
|
|
35
|
-
|
|
36
|
-
|
|
91
|
+
const attrs = captionInlineToken.attrs, len = attrs.length
|
|
92
|
+
for (let i = 0; i < len; i++) {
|
|
93
|
+
const attr = attrs[i]
|
|
94
|
+
if (attr[0] === 'class' && attr[1] === 'nocaption') {
|
|
95
|
+
isNoCaption = true
|
|
96
|
+
break
|
|
97
|
+
}
|
|
37
98
|
}
|
|
38
99
|
}
|
|
39
100
|
if (isNoCaption) {
|
|
40
|
-
|
|
101
|
+
tokens.splice(n-3, 3)
|
|
41
102
|
return false
|
|
42
103
|
}
|
|
43
104
|
}
|
|
44
105
|
|
|
45
|
-
|
|
46
|
-
captionStartToken.attrs.forEach(attr => {
|
|
47
|
-
if (attr[0] === 'class') {
|
|
48
|
-
attr[1] = attr[1].replace(attrReplaceReg, '').trim()
|
|
49
|
-
if(attr[1] === '') {
|
|
50
|
-
captionStartToken.attrs.splice(captionStartToken.attrIndex('class'), 1)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
})
|
|
106
|
+
cleanCaptionTokenAttrs(captionStartToken, caption.name)
|
|
54
107
|
captionStartToken.type = 'figcaption_open'
|
|
55
108
|
captionStartToken.tag = 'figcaption'
|
|
56
109
|
captionEndToken.type = 'figcaption_close'
|
|
57
110
|
captionEndToken.tag = 'figcaption'
|
|
58
|
-
|
|
59
|
-
|
|
111
|
+
tokens.splice(n + 2, 0, captionStartToken, captionInlineToken, captionEndToken)
|
|
112
|
+
tokens.splice(n-3, 3)
|
|
60
113
|
return true
|
|
61
114
|
}
|
|
62
115
|
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
const captionEndToken =
|
|
67
|
-
|
|
68
|
-
if (captionStartToken.type !== 'paragraph_open' && captionEndToken.type !== 'paragraph_close') return
|
|
69
|
-
|
|
70
|
-
setCaptionParagraph(en+1, state, caption, fNum, sp, opt)
|
|
71
|
-
|
|
72
|
-
let captionName = ''
|
|
73
|
-
if (captionStartToken.attrs) {
|
|
74
|
-
captionStartToken.attrs.forEach(attr => {
|
|
75
|
-
let hasCaptionName = attr[1].match(/^f-(.+)$/)
|
|
76
|
-
if (attr[0] === 'class' && hasCaptionName) captionName = hasCaptionName[1]
|
|
77
|
-
})
|
|
78
|
-
}
|
|
79
|
-
if(!captionName) return
|
|
80
|
-
caption.name = captionName
|
|
81
|
-
caption.isNext = true
|
|
82
|
-
return
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const changeNextCaptionPosition = (state, en, caption) => {
|
|
86
|
-
const captionStartToken = state.tokens[en+2] // +1: text node for figure.
|
|
87
|
-
const captionInlineToken = state.tokens[en+3]
|
|
88
|
-
const captionEndToken = state.tokens[en+4]
|
|
89
|
-
captionStartToken.attrs.forEach(attr => {
|
|
90
|
-
if (attr[0] === 'class') {
|
|
91
|
-
attr[1] = attr[1].replace(new RegExp(' *?f-' + caption.name), '').trim()
|
|
92
|
-
if(attr[1] === '') {
|
|
93
|
-
captionStartToken.attrs.splice(captionStartToken.attrIndex('class'), 1)
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
})
|
|
116
|
+
const changeNextCaptionPosition = (tokens, en, caption) => {
|
|
117
|
+
const captionStartToken = tokens[en+2] // +1: text node for figure.
|
|
118
|
+
const captionInlineToken = tokens[en+3]
|
|
119
|
+
const captionEndToken = tokens[en+4]
|
|
120
|
+
cleanCaptionTokenAttrs(captionStartToken, caption.name)
|
|
97
121
|
captionStartToken.type = 'figcaption_open'
|
|
98
122
|
captionStartToken.tag = 'figcaption'
|
|
99
123
|
captionEndToken.type = 'figcaption_close'
|
|
100
124
|
captionEndToken.tag = 'figcaption'
|
|
101
|
-
|
|
102
|
-
|
|
125
|
+
tokens.splice(en, 0, captionStartToken, captionInlineToken, captionEndToken)
|
|
126
|
+
tokens.splice(en+5, 3)
|
|
103
127
|
return true
|
|
104
128
|
}
|
|
105
129
|
|
|
106
|
-
const wrapWithFigure = (
|
|
130
|
+
const wrapWithFigure = (tokens, range, checkTokenTagName, caption, replaceInsteadOfWrap, sp, opt, TokenConstructor) => {
|
|
107
131
|
let n = range.start
|
|
108
132
|
let en = range.end
|
|
109
|
-
const figureStartToken = new
|
|
133
|
+
const figureStartToken = new TokenConstructor('figure_open', 'figure', 1)
|
|
110
134
|
figureStartToken.attrSet('class', 'f-' + checkTokenTagName)
|
|
111
135
|
|
|
112
136
|
if (opt.allIframeTypeFigureClassName === '') {
|
|
@@ -134,8 +158,8 @@ const wrapWithFigure = (state, range, checkTokenTagName, caption, replaceInstead
|
|
|
134
158
|
if(/pre-(?:code|samp)/.test(checkTokenTagName) && opt.roleDocExample) {
|
|
135
159
|
figureStartToken.attrSet('role', 'doc-example')
|
|
136
160
|
}
|
|
137
|
-
const figureEndToken = new
|
|
138
|
-
const breakToken = new
|
|
161
|
+
const figureEndToken = new TokenConstructor('figure_close', 'figure', -1)
|
|
162
|
+
const breakToken = new TokenConstructor('text', '', 0)
|
|
139
163
|
breakToken.content = '\n'
|
|
140
164
|
if (opt.styleProcess && caption.isNext && sp.attrs.length > 0) {
|
|
141
165
|
for (let attr of sp.attrs) {
|
|
@@ -143,92 +167,146 @@ const wrapWithFigure = (state, range, checkTokenTagName, caption, replaceInstead
|
|
|
143
167
|
}
|
|
144
168
|
}
|
|
145
169
|
// For vsce
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
for (let attr of state.tokens[n].attrs) {
|
|
170
|
+
if(tokens[n].attrs && caption.name === 'img') {
|
|
171
|
+
for (let attr of tokens[n].attrs) {
|
|
149
172
|
figureStartToken.attrJoin(attr[0], attr[1])
|
|
150
173
|
}
|
|
151
174
|
}
|
|
152
175
|
if (replaceInsteadOfWrap) {
|
|
153
|
-
|
|
154
|
-
|
|
176
|
+
tokens.splice(en, 1, breakToken, figureEndToken, breakToken)
|
|
177
|
+
tokens.splice(n, 1, figureStartToken, breakToken)
|
|
155
178
|
en = en + 2
|
|
156
|
-
//console.log(state.tokens[n].type, state.tokens[en].type)
|
|
157
179
|
} else {
|
|
158
|
-
|
|
159
|
-
|
|
180
|
+
tokens.splice(en+1, 0, figureEndToken, breakToken)
|
|
181
|
+
tokens.splice(n, 0, figureStartToken, breakToken)
|
|
160
182
|
en = en + 3
|
|
161
|
-
//console.log(state.tokens[n].type, state.tokens[en].type)
|
|
162
183
|
}
|
|
163
184
|
range.start = n
|
|
164
185
|
range.end = en
|
|
165
186
|
return
|
|
166
187
|
}
|
|
167
188
|
|
|
168
|
-
const checkCaption = (
|
|
169
|
-
checkPrevCaption(
|
|
189
|
+
const checkCaption = (tokens, n, en, caption, fNum, sp, opt, TokenConstructor) => {
|
|
190
|
+
checkPrevCaption(tokens, n, caption, fNum, sp, opt, TokenConstructor)
|
|
170
191
|
if (caption.isPrev) return
|
|
171
|
-
checkNextCaption(
|
|
192
|
+
checkNextCaption(tokens, en, caption, fNum, sp, opt, TokenConstructor)
|
|
172
193
|
return
|
|
173
194
|
}
|
|
174
195
|
|
|
196
|
+
const processTokensRecursively = (tokens, opt, fNum, TokenConstructor, parentType) => {
|
|
197
|
+
const nestedContainers = ['blockquote', 'list_item', 'dd']
|
|
198
|
+
|
|
199
|
+
figureWithCaptionCore(tokens, opt, fNum, TokenConstructor, parentType)
|
|
200
|
+
|
|
201
|
+
const nestedRanges = []
|
|
202
|
+
let i = 0
|
|
203
|
+
while (i < tokens.length) {
|
|
204
|
+
const token = tokens[i]
|
|
205
|
+
let containerType = null
|
|
206
|
+
for (const container of nestedContainers) {
|
|
207
|
+
if (token.type === `${container}_open`) {
|
|
208
|
+
containerType = container
|
|
209
|
+
break
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (containerType) {
|
|
213
|
+
let depth = 1
|
|
214
|
+
let endIndex = i + 1
|
|
215
|
+
while (endIndex < tokens.length && depth > 0) {
|
|
216
|
+
if (tokens[endIndex].type === `${containerType}_open`) depth++
|
|
217
|
+
if (tokens[endIndex].type === `${containerType}_close`) depth--
|
|
218
|
+
endIndex++
|
|
219
|
+
}
|
|
220
|
+
if (depth === 0 && endIndex - i > 2) {
|
|
221
|
+
nestedRanges.push({
|
|
222
|
+
start: i + 1,
|
|
223
|
+
end: endIndex - 1,
|
|
224
|
+
type: containerType
|
|
225
|
+
})
|
|
226
|
+
}
|
|
227
|
+
i = endIndex
|
|
228
|
+
} else {
|
|
229
|
+
i++
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
for (let j = nestedRanges.length - 1; j >= 0; j--) {
|
|
234
|
+
const range = nestedRanges[j]
|
|
235
|
+
const innerTokens = tokens.slice(range.start, range.end)
|
|
236
|
+
if (innerTokens.length > 0) {
|
|
237
|
+
processTokensRecursively(innerTokens, opt, fNum, TokenConstructor, range.type)
|
|
238
|
+
tokens.splice(range.start, range.end - range.start, ...innerTokens)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
175
243
|
const figureWithCaption = (state, opt) => {
|
|
176
|
-
let n = 0
|
|
177
244
|
let fNum = {
|
|
178
245
|
img: 0,
|
|
179
246
|
table: 0,
|
|
180
247
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
248
|
+
|
|
249
|
+
processTokensRecursively(state.tokens, opt, fNum, state.Token, null)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const figureWithCaptionCore = (tokens, opt, fNum, TokenConstructor, parentType) => {
|
|
253
|
+
const checkTypes = ['table', 'pre', 'blockquote']
|
|
254
|
+
const htmlTags = ['video', 'audio', 'iframe', 'blockquote', 'div']
|
|
255
|
+
|
|
256
|
+
const rRange = { start: 0, end: 0 }
|
|
257
|
+
const rCaption = {
|
|
258
|
+
mark: '', name: '', nameSuffix: '', isPrev: false, isNext: false
|
|
259
|
+
}
|
|
260
|
+
const rSp = {
|
|
261
|
+
attrs: [], isVideoIframe: false, isIframeTypeBlockquote: false, hasImgCaption: false
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
let n = 0
|
|
265
|
+
while (n < tokens.length) {
|
|
266
|
+
const token = tokens[n]
|
|
267
|
+
const nextToken = tokens[n+1]
|
|
184
268
|
let en = n
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
269
|
+
|
|
270
|
+
rRange.start = n
|
|
271
|
+
rRange.end = en
|
|
189
272
|
let checkToken = false
|
|
190
273
|
let checkTokenTagName = ''
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
isIframeTypeBlockquote: false,
|
|
202
|
-
hasImgCaption: false,
|
|
203
|
-
}
|
|
274
|
+
rCaption.mark = ''
|
|
275
|
+
rCaption.name = ''
|
|
276
|
+
rCaption.nameSuffix = ''
|
|
277
|
+
rCaption.isPrev = false
|
|
278
|
+
rCaption.isNext = false
|
|
279
|
+
|
|
280
|
+
rSp.attrs.length = 0
|
|
281
|
+
rSp.isVideoIframe = false
|
|
282
|
+
rSp.isIframeTypeBlockquote = false
|
|
283
|
+
rSp.hasImgCaption = false
|
|
204
284
|
|
|
205
|
-
const checkTypes = ['table', 'pre', 'blockquote']
|
|
206
285
|
let cti = 0
|
|
207
|
-
//console.log(state.tokens[n].type, state.tokens[n].tag)
|
|
208
286
|
while (cti < checkTypes.length) {
|
|
209
287
|
if (token.type === checkTypes[cti] + '_open') {
|
|
210
288
|
// for n-1 token is line-break
|
|
211
|
-
if (n > 1 &&
|
|
289
|
+
if (n > 1 && tokens[n-2].type === 'figure_open') {
|
|
212
290
|
cti++; continue
|
|
213
291
|
}
|
|
214
292
|
checkToken = true
|
|
215
293
|
checkTokenTagName = token.tag
|
|
216
|
-
|
|
294
|
+
rCaption.name = checkTypes[cti]
|
|
217
295
|
if (checkTypes[cti] === 'pre') {
|
|
218
|
-
if (
|
|
219
|
-
if (
|
|
220
|
-
|
|
296
|
+
if (tokens[n+1].tag === 'code') rCaption.mark = 'pre-code'
|
|
297
|
+
if (tokens[n+1].tag === 'samp') rCaption.mark = 'pre-samp'
|
|
298
|
+
rCaption.name = rCaption.mark
|
|
221
299
|
}
|
|
222
|
-
while (en <
|
|
223
|
-
if(
|
|
300
|
+
while (en < tokens.length) {
|
|
301
|
+
if(tokens[en].type === checkTokenTagName + '_close') {
|
|
224
302
|
break
|
|
225
303
|
}
|
|
226
304
|
en++
|
|
227
305
|
}
|
|
228
|
-
|
|
229
|
-
checkCaption(
|
|
230
|
-
if (
|
|
231
|
-
wrapWithFigure(
|
|
306
|
+
rRange.end = en
|
|
307
|
+
checkCaption(tokens, n, en, rCaption, fNum, rSp, opt, TokenConstructor)
|
|
308
|
+
if (rCaption.isPrev || rCaption.isNext) {
|
|
309
|
+
wrapWithFigure(tokens, rRange, checkTokenTagName, rCaption, false, rSp, opt, TokenConstructor)
|
|
232
310
|
}
|
|
233
311
|
break
|
|
234
312
|
}
|
|
@@ -237,20 +315,20 @@ const figureWithCaption = (state, opt) => {
|
|
|
237
315
|
if (token.tag === 'code' && token.block) {
|
|
238
316
|
checkToken = true
|
|
239
317
|
let isSamp = false
|
|
240
|
-
if (
|
|
318
|
+
if (sampLangReg.test(token.info)) {
|
|
241
319
|
token.tag = 'samp'
|
|
242
320
|
isSamp = true
|
|
243
321
|
}
|
|
244
322
|
if (isSamp) {
|
|
245
323
|
checkTokenTagName = 'pre-samp'
|
|
246
|
-
|
|
324
|
+
rCaption.name = 'pre-samp'
|
|
247
325
|
} else {
|
|
248
326
|
checkTokenTagName = 'pre-code'
|
|
249
|
-
|
|
327
|
+
rCaption.name = 'pre-code'
|
|
250
328
|
}
|
|
251
|
-
checkCaption(
|
|
252
|
-
if (
|
|
253
|
-
wrapWithFigure(
|
|
329
|
+
checkCaption(tokens, n, en, rCaption, fNum, rSp, opt, TokenConstructor)
|
|
330
|
+
if (rCaption.isPrev || rCaption.isNext) {
|
|
331
|
+
wrapWithFigure(tokens, rRange, checkTokenTagName, rCaption, false, rSp, opt, TokenConstructor)
|
|
254
332
|
break
|
|
255
333
|
}
|
|
256
334
|
}
|
|
@@ -260,20 +338,19 @@ const figureWithCaption = (state, opt) => {
|
|
|
260
338
|
}
|
|
261
339
|
|
|
262
340
|
if (token.type === 'html_block') {
|
|
263
|
-
const tags = ['video', 'audio', 'iframe', 'blockquote', 'div']
|
|
264
341
|
let ctj = 0
|
|
265
342
|
let hasTag
|
|
266
|
-
while (ctj <
|
|
267
|
-
if (
|
|
343
|
+
while (ctj < htmlTags.length) {
|
|
344
|
+
if (htmlTags[ctj] === 'div') {
|
|
268
345
|
// for vimeo
|
|
269
|
-
hasTag = token.content.match(
|
|
270
|
-
|
|
271
|
-
|
|
346
|
+
hasTag = token.content.match(getHtmlReg('div'))
|
|
347
|
+
htmlTags[ctj] = 'iframe'
|
|
348
|
+
rSp.isVideoIframe = true
|
|
272
349
|
} else {
|
|
273
|
-
hasTag = token.content.match(
|
|
350
|
+
hasTag = token.content.match(getHtmlReg(htmlTags[ctj]))
|
|
274
351
|
}
|
|
275
|
-
const blueskyContMatch = token.content.match(
|
|
276
|
-
if (!(hasTag || (blueskyContMatch &&
|
|
352
|
+
const blueskyContMatch = token.content.match(blueskyEmbedReg)
|
|
353
|
+
if (!(hasTag || (blueskyContMatch && htmlTags[ctj] === 'blockquote'))) {
|
|
277
354
|
ctj++
|
|
278
355
|
continue
|
|
279
356
|
}
|
|
@@ -282,45 +359,45 @@ const figureWithCaption = (state, opt) => {
|
|
|
282
359
|
token.content += '\n'
|
|
283
360
|
}
|
|
284
361
|
} else if (blueskyContMatch) {
|
|
285
|
-
let addedCont = ''
|
|
362
|
+
let addedCont = ''
|
|
363
|
+
const tokensChildren = tokens
|
|
364
|
+
const tokensLength = tokensChildren.length
|
|
286
365
|
let j = n + 1
|
|
287
366
|
let hasEndBlockquote = true
|
|
288
|
-
while (j <
|
|
289
|
-
const nextToken =
|
|
290
|
-
if (nextToken.type === 'inline' &&
|
|
367
|
+
while (j < tokensLength) {
|
|
368
|
+
const nextToken = tokens[j]
|
|
369
|
+
if (nextToken.type === 'inline' && endBlockquoteScriptReg.test(nextToken.content)) {
|
|
291
370
|
addedCont += nextToken.content + '\n'
|
|
292
|
-
if (
|
|
293
|
-
|
|
371
|
+
if (tokens[j + 1] && tokens[j + 1].type === 'paragraph_close') {
|
|
372
|
+
tokens.splice(j + 1, 1)
|
|
294
373
|
}
|
|
295
|
-
|
|
296
|
-
|
|
374
|
+
nextToken.content = ''
|
|
375
|
+
nextToken.children.forEach((child) => {
|
|
297
376
|
child.content = ''
|
|
298
377
|
})
|
|
299
378
|
break
|
|
300
379
|
}
|
|
301
380
|
if (nextToken.type === 'paragraph_open') {
|
|
302
381
|
addedCont += '\n'
|
|
303
|
-
|
|
382
|
+
tokens.splice(j, 1)
|
|
304
383
|
continue
|
|
305
384
|
}
|
|
306
|
-
j
|
|
385
|
+
j++
|
|
307
386
|
}
|
|
308
|
-
token.content += addedCont
|
|
387
|
+
token.content += addedCont
|
|
309
388
|
if (!hasEndBlockquote) {
|
|
310
389
|
ctj++
|
|
311
390
|
continue
|
|
312
391
|
}
|
|
313
392
|
}
|
|
314
393
|
|
|
315
|
-
checkTokenTagName =
|
|
316
|
-
|
|
394
|
+
checkTokenTagName = htmlTags[ctj]
|
|
395
|
+
rCaption.name = htmlTags[ctj]
|
|
317
396
|
checkToken = true
|
|
318
397
|
if (checkTokenTagName === 'blockquote') {
|
|
319
|
-
const classNameReg = /^<[^>]*? class="(twitter-tweet|instagram-media|text-post-media|bluesky-embed|mastodon-embed)"/
|
|
320
398
|
const isIframeTypeBlockquote = token.content.match(classNameReg)
|
|
321
|
-
//console.log(isIframeTypeBlockquote)
|
|
322
399
|
if(isIframeTypeBlockquote) {
|
|
323
|
-
|
|
400
|
+
rSp.isIframeTypeBlockquote = true
|
|
324
401
|
} else {
|
|
325
402
|
ctj++
|
|
326
403
|
continue
|
|
@@ -330,19 +407,19 @@ const figureWithCaption = (state, opt) => {
|
|
|
330
407
|
}
|
|
331
408
|
if (!checkToken) {n++; continue;}
|
|
332
409
|
if (checkTokenTagName === 'iframe') {
|
|
333
|
-
if(
|
|
334
|
-
|
|
410
|
+
if(videoIframeReg.test(token.content)) {
|
|
411
|
+
rSp.isVideoIframe = true
|
|
335
412
|
}
|
|
336
413
|
}
|
|
337
414
|
|
|
338
|
-
checkCaption(
|
|
339
|
-
if (
|
|
340
|
-
wrapWithFigure(
|
|
415
|
+
checkCaption(tokens, n, en, rCaption, fNum, rSp, opt, TokenConstructor)
|
|
416
|
+
if (rCaption.isPrev || rCaption.isNext) {
|
|
417
|
+
wrapWithFigure(tokens, rRange, checkTokenTagName, rCaption, false, rSp, opt, TokenConstructor)
|
|
341
418
|
n = en + 2
|
|
342
419
|
} else if ((opt.iframeWithoutCaption && (checkTokenTagName === 'iframe')) ||
|
|
343
420
|
(opt.videoWithoutCaption && (checkTokenTagName === 'video')) ||
|
|
344
421
|
(opt.iframeTypeBlockquoteWithoutCaption && (checkTokenTagName === 'blockquote'))) {
|
|
345
|
-
wrapWithFigure(
|
|
422
|
+
wrapWithFigure(tokens, rRange, checkTokenTagName, rCaption, false, rSp, opt, TokenConstructor)
|
|
346
423
|
n = en + 2
|
|
347
424
|
}
|
|
348
425
|
}
|
|
@@ -353,27 +430,30 @@ const figureWithCaption = (state, opt) => {
|
|
|
353
430
|
let isMultipleImagesHorizontal = true
|
|
354
431
|
let isMultipleImagesVertical = true
|
|
355
432
|
checkToken = true
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
433
|
+
rCaption.name = 'img'
|
|
434
|
+
const children = nextToken.children
|
|
435
|
+
const childrenLength = children.length
|
|
436
|
+
while (ntChildTokenIndex < childrenLength) {
|
|
437
|
+
const ntChildToken = children[ntChildTokenIndex]
|
|
438
|
+
if (ntChildTokenIndex === childrenLength - 1) {
|
|
439
|
+
let imageAttrs = ntChildToken.content.match(imageAttrsReg)
|
|
361
440
|
if(ntChildToken.type === 'text' && imageAttrs) {
|
|
362
441
|
imageAttrs = imageAttrs[1].split(/ +/)
|
|
363
442
|
let iai = 0
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
443
|
+
const attrsLength = imageAttrs.length
|
|
444
|
+
while (iai < attrsLength) {
|
|
445
|
+
if (classAttrReg.test(imageAttrs[iai])) {
|
|
446
|
+
imageAttrs[iai] = imageAttrs[iai].replace(classAttrReg, "class=")
|
|
367
447
|
}
|
|
368
|
-
if (
|
|
369
|
-
imageAttrs[iai] = imageAttrs[iai].replace(
|
|
448
|
+
if (idAttrReg.test(imageAttrs[iai])) {
|
|
449
|
+
imageAttrs[iai] = imageAttrs[iai].replace(idAttrReg, "id=")
|
|
370
450
|
}
|
|
371
|
-
let imageAttr = imageAttrs[iai].match(
|
|
451
|
+
let imageAttr = imageAttrs[iai].match(attrParseReg)
|
|
372
452
|
if (!imageAttr || !imageAttr[1]) {
|
|
373
453
|
iai++
|
|
374
454
|
continue
|
|
375
455
|
}
|
|
376
|
-
|
|
456
|
+
rSp.attrs.push([imageAttr[1], imageAttr[2]])
|
|
377
457
|
iai++
|
|
378
458
|
}
|
|
379
459
|
break
|
|
@@ -386,7 +466,7 @@ const figureWithCaption = (state, opt) => {
|
|
|
386
466
|
}
|
|
387
467
|
if (ntChildToken.type === 'image') {
|
|
388
468
|
imageNum += 1
|
|
389
|
-
} else if (ntChildToken.type === 'text' &&
|
|
469
|
+
} else if (ntChildToken.type === 'text' && whitespaceReg.test(ntChildToken.content)) {
|
|
390
470
|
isMultipleImagesVertical = false
|
|
391
471
|
if (isMultipleImagesVertical) {
|
|
392
472
|
isMultipleImagesHorizontal = false
|
|
@@ -404,50 +484,58 @@ const figureWithCaption = (state, opt) => {
|
|
|
404
484
|
}
|
|
405
485
|
if (checkToken && imageNum > 1 && opt.multipleImages) {
|
|
406
486
|
if (isMultipleImagesHorizontal) {
|
|
407
|
-
|
|
487
|
+
rCaption.nameSuffix = '-horizontal'
|
|
408
488
|
} else if (isMultipleImagesVertical) {
|
|
409
|
-
|
|
489
|
+
rCaption.nameSuffix = '-vertical'
|
|
410
490
|
} else {
|
|
411
|
-
|
|
491
|
+
rCaption.nameSuffix = '-multiple'
|
|
412
492
|
}
|
|
413
493
|
ntChildTokenIndex = 0
|
|
414
|
-
while (ntChildTokenIndex <
|
|
415
|
-
const ccToken =
|
|
416
|
-
if (ccToken.type === 'text' &&
|
|
494
|
+
while (ntChildTokenIndex < childrenLength) {
|
|
495
|
+
const ccToken = children[ntChildTokenIndex]
|
|
496
|
+
if (ccToken.type === 'text' && whitespaceReg.test(ccToken.content)) {
|
|
417
497
|
ccToken.content = ''
|
|
418
498
|
}
|
|
419
499
|
ntChildTokenIndex++
|
|
420
500
|
}
|
|
421
501
|
}
|
|
422
502
|
en = n + 2
|
|
423
|
-
|
|
503
|
+
rRange.end = en
|
|
424
504
|
checkTokenTagName = 'img'
|
|
425
505
|
nextToken.children[0].type = 'image'
|
|
426
506
|
|
|
427
|
-
if (opt.imgAltCaption) setAltToLabel(
|
|
428
|
-
if (opt.imgTitleCaption) setTitleToLabel(
|
|
429
|
-
checkCaption(
|
|
507
|
+
if (opt.imgAltCaption) setAltToLabel({ tokens, Token: TokenConstructor }, n)
|
|
508
|
+
if (opt.imgTitleCaption) setTitleToLabel({ tokens, Token: TokenConstructor }, n)
|
|
509
|
+
checkCaption(tokens, n, en, rCaption, fNum, rSp, opt, TokenConstructor)
|
|
430
510
|
|
|
431
|
-
if (
|
|
432
|
-
|
|
511
|
+
if (parentType === 'list_item' || isInListItem(tokens, n)) {
|
|
512
|
+
const isInTightList = token.hidden === true
|
|
513
|
+
if (isInTightList) {
|
|
514
|
+
checkToken = false
|
|
515
|
+
} else {
|
|
516
|
+
if (!opt.oneImageWithoutCaption && !rCaption.isPrev && !rCaption.isNext) {
|
|
517
|
+
checkToken = false
|
|
518
|
+
}
|
|
519
|
+
}
|
|
433
520
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
521
|
+
|
|
522
|
+
if (checkToken && (opt.oneImageWithoutCaption || rCaption.isPrev || rCaption.isNext)) {
|
|
523
|
+
if (rCaption.nameSuffix) checkTokenTagName += rCaption.nameSuffix
|
|
524
|
+
wrapWithFigure(tokens, rRange, checkTokenTagName, rCaption, true, rSp, opt, TokenConstructor)
|
|
437
525
|
}
|
|
438
526
|
}
|
|
439
527
|
|
|
440
|
-
if (!checkToken || !
|
|
528
|
+
if (!checkToken || !rCaption.name) {n++; continue;}
|
|
441
529
|
|
|
442
|
-
n =
|
|
443
|
-
en =
|
|
444
|
-
if (
|
|
445
|
-
changePrevCaptionPosition(
|
|
530
|
+
n = rRange.start
|
|
531
|
+
en = rRange.end
|
|
532
|
+
if (rCaption.isPrev) {
|
|
533
|
+
changePrevCaptionPosition(tokens, n, rCaption, opt)
|
|
446
534
|
n = en + 1
|
|
447
535
|
continue
|
|
448
536
|
}
|
|
449
|
-
if (
|
|
450
|
-
changeNextCaptionPosition(
|
|
537
|
+
if (rCaption.isNext) {
|
|
538
|
+
changeNextCaptionPosition(tokens, en, rCaption)
|
|
451
539
|
n = en + 4
|
|
452
540
|
continue
|
|
453
541
|
}
|
|
@@ -456,6 +544,36 @@ const figureWithCaption = (state, opt) => {
|
|
|
456
544
|
return
|
|
457
545
|
}
|
|
458
546
|
|
|
547
|
+
const isInListItem = (() => {
|
|
548
|
+
const cache = new WeakMap()
|
|
549
|
+
return (tokens, idx) => {
|
|
550
|
+
if (cache.has(tokens)) {
|
|
551
|
+
const cachedResult = cache.get(tokens)
|
|
552
|
+
if (cachedResult[idx] !== undefined) {
|
|
553
|
+
return cachedResult[idx]
|
|
554
|
+
}
|
|
555
|
+
} else {
|
|
556
|
+
cache.set(tokens, {})
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
const result = cache.get(tokens)
|
|
560
|
+
|
|
561
|
+
for (let i = idx - 1; i >= 0; i--) {
|
|
562
|
+
if (tokens[i].type === 'list_item_open') {
|
|
563
|
+
result[idx] = true
|
|
564
|
+
return true
|
|
565
|
+
}
|
|
566
|
+
if (tokens[i].type === 'list_item_close' || tokens[i].type === 'list_open') {
|
|
567
|
+
result[idx] = false
|
|
568
|
+
return false
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
result[idx] = false
|
|
573
|
+
return false
|
|
574
|
+
}
|
|
575
|
+
})()
|
|
576
|
+
|
|
459
577
|
const mditFigureWithPCaption = (md, option) => {
|
|
460
578
|
let opt = {
|
|
461
579
|
classPrefix: 'f',
|
|
@@ -488,10 +606,9 @@ const mditFigureWithPCaption = (md, option) => {
|
|
|
488
606
|
opt.oneImageWithoutCaption = true
|
|
489
607
|
opt.multipleImages = false
|
|
490
608
|
if (opt.setFigureNumber) {
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
609
|
+
opt.removeUnnumberedLabelExceptMarks = opt.removeUnnumberedLabelExceptMarks.filter(
|
|
610
|
+
mark => mark !== 'img' && mark !== 'table'
|
|
611
|
+
)
|
|
495
612
|
}
|
|
496
613
|
md.block.ruler.before('paragraph', 'img_attr_caption', (state) => {
|
|
497
614
|
imgAttrToPCaption(state, state.line, opt)
|
|
@@ -504,4 +621,4 @@ const mditFigureWithPCaption = (md, option) => {
|
|
|
504
621
|
})
|
|
505
622
|
}
|
|
506
623
|
|
|
507
|
-
export default mditFigureWithPCaption
|
|
624
|
+
export default mditFigureWithPCaption
|