@peaceroad/markdown-it-figure-with-p-caption 0.10.1 → 0.12.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 CHANGED
@@ -515,3 +515,45 @@ From version 0.8, role="doc-example" is not included as standard in figure.f-pre
515
515
  ```js
516
516
  const mdImgAltCaption = mdit({html: true}).use(mditFigureWithPCaption, {roleDocExample: true})
517
517
  ```
518
+
519
+ ### Option: allIframeTypeFigureClassName
520
+
521
+ From version 0.16.0, unify the figure element that wraps the iframe or blockquote tag in the embed code to figure.f-embed (this may become the default in the future).
522
+
523
+ ```js
524
+ const mdAllIframeTypeFigureClassName = mdit({html: true}).use(mdFigureWithPCaption, {
525
+ allIframeTypeFigureClassName: 'f-embed',
526
+ videoWithoutCaption = true,
527
+ iframeWithoutCaption = true,
528
+ iframeTypeBlockquoteWithoutCaption = true,
529
+ }).use(mditAttrs).use(mditRndererFence);
530
+ ```
531
+
532
+ ```
533
+ [Markdown]
534
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
535
+ [HTML]
536
+ <figure class="f-embed">
537
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
538
+ </figure>
539
+
540
+
541
+ [Markdown]
542
+ Video. A youtube.
543
+
544
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
545
+ [HTML]
546
+ <figure class="f-embed">
547
+ <figcaption><span class="f-video-label">Video<span class="f-video-label-joint">.</span></span> A youtube.</figcaption>
548
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
549
+ </figure>
550
+
551
+
552
+ [Markdown]
553
+ <blockquote class="mastodon-embed" data-embed-url="https://mastodon.social/@xxxx/xxxx/embed" ...>xxxxxxxxxxxxxxxx</blockquote> <script data-allowed-prefixes="https://mastodon.social/" async src="https://mastodon.social/embed.js"></script>
554
+
555
+ [HTML]
556
+ <figure class="f-embed">
557
+ <blockquote class="mastodon-embed" data-embed-url="https://mastodon.social/@xxxx/xxxx/embed" ...>xxxxxxxxxxxxxxxx</blockquote> <script data-allowed-prefixes="https://mastodon.social/" async src="https://mastodon.social/embed.js"></script>
558
+ </figure>
559
+ ```
@@ -0,0 +1,82 @@
1
+ import { markReg } from 'p7d-markdown-it-p-captions'
2
+
3
+ const imgReg = /^( *!\[)(.*?)\]\( *?((.*?)(?: +?"(.*?)")?) *?\)( *?\{.*?\})? *$/
4
+
5
+ const imgAttrToPCaption = (state, startLine, opt) => {
6
+ const imgMarkReg = markReg['img']
7
+ let pos = state.bMarks[startLine] + state.tShift[startLine]
8
+ let max = state.eMarks[startLine]
9
+ let inline = state.src.slice(pos, max)
10
+ const img = inline.match(imgReg)
11
+ if (!img) return
12
+
13
+ let alt = img[2] ?? ''
14
+ let title = img[5] ?? ''
15
+ const caption = opt.imgTitleCaption ? title : (opt.imgAltCaption ? alt : '')
16
+ const altCap = typeof opt.imgAltCaption === 'string' ? opt.imgAltCaption : ''
17
+ const titleCap = typeof opt.imgTitleCaption === 'string' ? opt.imgTitleCaption : ''
18
+
19
+ const hasMarkLabel = caption.match(imgMarkReg)
20
+ let modCaption = ''
21
+ if (hasMarkLabel) {
22
+ modCaption = caption
23
+ } else {
24
+ const prefix = altCap || titleCap || ''
25
+ if (prefix && /[a-zA-Z]/.test(prefix)) {
26
+ modCaption = caption === '' ? prefix + '.' : prefix + '. ' + caption
27
+ } else {
28
+ modCaption = caption === '' ? prefix + ' ' : prefix + ' ' + caption
29
+ }
30
+ if (!prefix) {
31
+ modCaption = 'Figure.' + (caption !== '' ? ' ' + caption : '')
32
+ }
33
+ }
34
+ let token = state.push('paragraph_open', 'p', 1)
35
+ token.map = [startLine, startLine + 1]
36
+ token = state.push('inline', '', 0)
37
+ token.content = modCaption
38
+ token.children = [new state.Token('text', modCaption, 0)]
39
+ if (!opt.setFigureNumber) {
40
+ if(caption === '') token.attrs = [['class', 'nocaption']]
41
+ }
42
+ token = state.push('paragraph_close', 'p', -1)
43
+ return true
44
+ }
45
+
46
+ const setAltToLabel = (state, n) => {
47
+ if (n < 2) return false
48
+ const imageToken = state.tokens[n+1].children[0]
49
+ if (imageToken.type !== 'image' || !state.tokens[n-2].children) return false
50
+ const prevTokenChild = state.tokens[n-2].children[0]
51
+ if (state.tokens[n-2].children) {
52
+ state.tokens[n+1].content = state.tokens[n+1].content.replace(/^!\[.*?\]/, '![' + prevTokenChild.content + ']')
53
+ if (!imageToken.children[0]) {
54
+ const textToken = new state.Token('text', '', 0)
55
+ imageToken.children.push(textToken)
56
+ }
57
+ imageToken.children[0].content = ''
58
+ }
59
+ imageToken.content = ''
60
+ return true
61
+ }
62
+
63
+ const setTitleToLabel = (state, n) => {
64
+ if (n < 2) return false
65
+ const imageToken = state.tokens[n+1].children[0]
66
+ if (imageToken.type !== 'image') return false
67
+ if (!state.tokens[n-2].children[0]) return false
68
+ imageToken.attrSet('alt', imageToken.content)
69
+ if (!imageToken.children[0]) {
70
+ const textToken = new state.Token('text', '', 0)
71
+ imageToken.children.push(textToken)
72
+ }
73
+ for (let i = 0; i < imageToken.attrs.length; i++) {
74
+ if (imageToken.attrs[i][0] === 'title') {
75
+ imageToken.attrs.splice(i, 1)
76
+ break
77
+ }
78
+ }
79
+ return true
80
+ }
81
+
82
+ export { imgAttrToPCaption, setAltToLabel, setTitleToLabel }
package/index.js CHANGED
@@ -1,51 +1,94 @@
1
- import {setCaptionParagraph} from 'p7d-markdown-it-p-captions'
1
+ import { setCaptionParagraph } from 'p7d-markdown-it-p-captions'
2
+ import { imgAttrToPCaption, setAltToLabel, setTitleToLabel } from './imgAttrToPCaption.js'
3
+
4
+ const htmlRegCache = {}
5
+ const classReg = /^f-(.+)$/
6
+ const blueskyEmbedReg = /^<blockquote class="bluesky-embed"[^]*?>[\s\S]*?$/
7
+
8
+ const getHtmlReg = (tag) => {
9
+ if (htmlRegCache[tag]) return htmlRegCache[tag]
10
+ let regexStr = '^<' + tag + ' ?[^>]*?>[\\s\\S]*?<\\/' + tag + '>(\\n| *?)(<script [^>]*?>(?:<\\/script>)?)? *(\\n|$)'
11
+ const reg = new RegExp(regexStr)
12
+ htmlRegCache[tag] = reg
13
+ return reg
14
+ }
2
15
 
3
- const checkPrevCaption = (state, n, caption, sp, opt) => {
16
+ const getCaptionName = (token) => {
17
+ if (!token.attrs) return ''
18
+ const attrs = token.attrs
19
+ for (let i = 0, len = attrs.length; i < len; i++) {
20
+ const attr = attrs[i]
21
+ if (attr[0] === 'class') {
22
+ const match = attr[1].match(classReg)
23
+ if (match) return match[1]
24
+ }
25
+ }
26
+ return ''
27
+ }
28
+
29
+ const checkPrevCaption = (state, n, caption, fNum, sp, opt) => {
4
30
  if(n < 3) return caption
5
31
  const captionStartToken = state.tokens[n-3]
6
32
  const captionEndToken = state.tokens[n-1]
7
- if (captionStartToken === undefined || captionEndToken === undefined) return caption
8
-
9
- if (captionStartToken.type !== 'paragraph_open' && captionEndToken.type !== 'paragraph_close') return caption
33
+ if (captionStartToken === undefined || captionEndToken === undefined) return
34
+ if (captionStartToken.type !== 'paragraph_open' && captionEndToken.type !== 'paragraph_close') return
35
+ setCaptionParagraph(n-3, state, caption, fNum, sp, opt)
36
+ const captionName = getCaptionName(captionStartToken)
37
+ if(!captionName) return
38
+ caption.name = captionName
39
+ caption.isPrev = true
40
+ return
41
+ }
10
42
 
11
- caption = setCaptionParagraph(n-3, state, caption, sp, opt)
43
+ const checkNextCaption = (state, en, caption, fNum, sp, opt) => {
44
+ if (en + 2 > state.tokens.length) return
45
+ const captionStartToken = state.tokens[en+1]
46
+ const captionEndToken = state.tokens[en+3]
47
+ if (captionStartToken === undefined || captionEndToken === undefined) return
48
+ if (captionStartToken.type !== 'paragraph_open' && captionEndToken.type !== 'paragraph_close') return
49
+ setCaptionParagraph(en+1, state, caption, fNum, sp, opt)
50
+ const captionName = getCaptionName(captionStartToken)
51
+ if(!captionName) return
52
+ caption.name = captionName
53
+ caption.isNext = true
54
+ return
55
+ }
12
56
 
13
- let captionName = ''
14
- if (captionStartToken.attrs) {
15
- captionStartToken.attrs.forEach(attr => {
16
- let hasCaptionName = attr[1].match(/^f-(.+)$/)
17
- if (attr[0] === 'class' && hasCaptionName) captionName = hasCaptionName[1]
18
- })
57
+ const cleanCaptionTokenAttrs = (token, captionName) => {
58
+ const reg = new RegExp(' *?f-' + captionName)
59
+ if (!token.attrs) return
60
+ for (let i = token.attrs.length - 1; i >= 0; i--) {
61
+ if (token.attrs[i][0] === 'class') {
62
+ token.attrs[i][1] = token.attrs[i][1].replace(reg, '').trim()
63
+ if (token.attrs[i][1] === '') token.attrs.splice(i, 1)
64
+ }
19
65
  }
20
- if(!captionName) return caption
21
- caption.name = captionName
22
- caption.isPrev = true
23
- return caption
24
66
  }
25
67
 
26
- const changePrevCaptionPosition = (state, n, caption) => {
68
+ const changePrevCaptionPosition = (state, n, caption, opt) => {
27
69
  const captionStartToken = state.tokens[n-3]
28
70
  const captionInlineToken = state.tokens[n-2]
29
71
  const captionEndToken = state.tokens[n-1]
30
- let isNoCaption = false
31
- if (captionInlineToken.attrs) {
32
- for (let attr of captionInlineToken.attrs) {
33
- if (attr[0] === 'class' && attr[1] === 'nocaption') isNoCaption = true
34
- }
35
- }
36
- if (isNoCaption) {
37
- state.tokens.splice(n-3, 3)
38
- return
39
- }
40
72
 
41
- captionStartToken.attrs.forEach(attr => {
42
- if (attr[0] === 'class') {
43
- attr[1] = attr[1].replace(new RegExp(' *?f-' + caption.name), '').trim()
44
- if(attr[1] === '') {
45
- captionStartToken.attrs.splice(captionStartToken.attrIndex('class'), 1)
73
+ if (opt.imgAltCaption || opt.imgTitleCaption) {
74
+ let isNoCaption = false
75
+ if (captionInlineToken.attrs) {
76
+ const attrs = captionInlineToken.attrs, len = attrs.length
77
+ for (let i = 0; i < len; i++) {
78
+ const attr = attrs[i]
79
+ if (attr[0] === 'class' && attr[1] === 'nocaption') {
80
+ isNoCaption = true
81
+ break
82
+ }
46
83
  }
47
84
  }
48
- })
85
+ if (isNoCaption) {
86
+ state.tokens.splice(n-3, 3)
87
+ return false
88
+ }
89
+ }
90
+
91
+ cleanCaptionTokenAttrs(captionStartToken, caption.name)
49
92
  captionStartToken.type = 'figcaption_open'
50
93
  captionStartToken.tag = 'figcaption'
51
94
  captionEndToken.type = 'figcaption_close'
@@ -55,40 +98,11 @@ const changePrevCaptionPosition = (state, n, caption) => {
55
98
  return true
56
99
  }
57
100
 
58
- const checkNextCaption = (state, en, caption, sp, opt) => {
59
- if (en + 2 > state.tokens.length) return caption
60
- const captionStartToken = state.tokens[en+1]
61
- const captionEndToken = state.tokens[en+3]
62
- if (captionStartToken === undefined || captionEndToken === undefined) return caption
63
- if (captionStartToken.type !== 'paragraph_open' && captionEndToken.type !== 'paragraph_close') return caption
64
-
65
- caption = setCaptionParagraph(en+1, state, caption, sp, opt)
66
-
67
- let captionName = ''
68
- if (captionStartToken.attrs) {
69
- captionStartToken.attrs.forEach(attr => {
70
- let hasCaptionName = attr[1].match(/^f-(.+)$/)
71
- if (attr[0] === 'class' && hasCaptionName) captionName = hasCaptionName[1]
72
- })
73
- }
74
- if(!captionName) return caption
75
- caption.name = captionName
76
- caption.isNext = true
77
- return caption
78
- }
79
-
80
101
  const changeNextCaptionPosition = (state, en, caption) => {
81
102
  const captionStartToken = state.tokens[en+2] // +1: text node for figure.
82
103
  const captionInlineToken = state.tokens[en+3]
83
104
  const captionEndToken = state.tokens[en+4]
84
- captionStartToken.attrs.forEach(attr => {
85
- if (attr[0] === 'class') {
86
- attr[1] = attr[1].replace(new RegExp(' *?f-' + caption.name), '').trim()
87
- if(attr[1] === '') {
88
- captionStartToken.attrs.splice(captionStartToken.attrIndex('class'), 1)
89
- }
90
- }
91
- })
105
+ cleanCaptionTokenAttrs(captionStartToken, caption.name)
92
106
  captionStartToken.type = 'figcaption_open'
93
107
  captionStartToken.tag = 'figcaption'
94
108
  captionEndToken.type = 'figcaption_close'
@@ -103,23 +117,29 @@ const wrapWithFigure = (state, range, checkTokenTagName, caption, replaceInstead
103
117
  let en = range.end
104
118
  const figureStartToken = new state.Token('figure_open', 'figure', 1)
105
119
  figureStartToken.attrSet('class', 'f-' + checkTokenTagName)
106
- if (sp.isVideoIframe) {
107
- figureStartToken.attrSet('class', 'f-video')
108
- }
109
- if (sp.isIframeTypeBlockquote) {
110
- let figureClassThatWrapsIframeTypeBlockquote = 'i-frame'
111
- if (caption.isPrev || caption.isNext) {
112
- if (caption.name === 'blockquote' || caption.name === 'img') {
113
- figureClassThatWrapsIframeTypeBlockquote = 'f-img'
120
+
121
+ if (opt.allIframeTypeFigureClassName === '') {
122
+ if (sp.isVideoIframe) {
123
+ figureStartToken.attrSet('class', 'f-video')
124
+ }
125
+ if (sp.isIframeTypeBlockquote) {
126
+ let figureClassThatWrapsIframeTypeBlockquote = 'i-frame'
127
+ if (caption.isPrev || caption.isNext) {
128
+ if (caption.name === 'blockquote' || caption.name === 'img') {
129
+ figureClassThatWrapsIframeTypeBlockquote = 'f-img'
130
+ }
131
+ figureStartToken.attrSet('class', figureClassThatWrapsIframeTypeBlockquote)
132
+ } else {
133
+ figureClassThatWrapsIframeTypeBlockquote = opt.figureClassThatWrapsIframeTypeBlockquote
134
+ figureStartToken.attrSet('class', figureClassThatWrapsIframeTypeBlockquote)
114
135
  }
115
- figureStartToken.attrSet('class', figureClassThatWrapsIframeTypeBlockquote)
116
- } else {
117
- figureClassThatWrapsIframeTypeBlockquote = opt.figureClassThatWrapsIframeTypeBlockquote
118
- figureStartToken.attrSet('class', figureClassThatWrapsIframeTypeBlockquote)
136
+ }
137
+ } else {
138
+ if (checkTokenTagName === 'iframe' || sp.isIframeTypeBlockquote) {
139
+ figureStartToken.attrSet('class', opt.allIframeTypeFigureClassName)
119
140
  }
120
141
  }
121
142
 
122
-
123
143
  if(/pre-(?:code|samp)/.test(checkTokenTagName) && opt.roleDocExample) {
124
144
  figureStartToken.attrSet('role', 'doc-example')
125
145
  }
@@ -132,7 +152,6 @@ const wrapWithFigure = (state, range, checkTokenTagName, caption, replaceInstead
132
152
  }
133
153
  }
134
154
  // For vsce
135
- //console.log(caption)
136
155
  if(state.tokens[n].attrs && caption.name === 'img') {
137
156
  for (let attr of state.tokens[n].attrs) {
138
157
  figureStartToken.attrJoin(attr[0], attr[1])
@@ -142,37 +161,42 @@ const wrapWithFigure = (state, range, checkTokenTagName, caption, replaceInstead
142
161
  state.tokens.splice(en, 1, breakToken, figureEndToken, breakToken)
143
162
  state.tokens.splice(n, 1, figureStartToken, breakToken)
144
163
  en = en + 2
145
- //console.log(state.tokens[n].type, state.tokens[en].type)
146
164
  } else {
147
165
  state.tokens.splice(en+1, 0, figureEndToken, breakToken)
148
166
  state.tokens.splice(n, 0, figureStartToken, breakToken)
149
167
  en = en + 3
150
- //console.log(state.tokens[n].type, state.tokens[en].type)
151
168
  }
152
169
  range.start = n
153
170
  range.end = en
154
- return range
171
+ return
155
172
  }
156
173
 
157
- const checkCaption = (state, n, en, caption, sp, opt) => {
158
- caption = checkPrevCaption(state, n, caption, sp, opt)
159
- if (caption.isPrev) return caption
160
- caption = checkNextCaption(state, en, caption, sp, opt)
161
- return caption
174
+ const checkCaption = (state, n, en, caption, fNum, sp, opt) => {
175
+ checkPrevCaption(state, n, caption, fNum, sp, opt)
176
+ if (caption.isPrev) return
177
+ checkNextCaption(state, en, caption, fNum, sp, opt)
178
+ return
162
179
  }
163
180
 
164
181
  const figureWithCaption = (state, opt) => {
182
+ const tokens = state.tokens
183
+ const checkTypes = ['table', 'pre', 'blockquote']
184
+ const htmlTags = ['video', 'audio', 'iframe', 'blockquote', 'div']
185
+
165
186
  let n = 0
166
- while (n < state.tokens.length) {
167
- const token = state.tokens[n]
168
- const nextToken = state.tokens[n+1]
187
+ let fNum = {
188
+ img: 0,
189
+ table: 0,
190
+ }
191
+ while (n < tokens.length) {
192
+ const token = tokens[n]
193
+ const nextToken = tokens[n+1]
169
194
  let en = n
170
195
  let range = {
171
196
  start: n,
172
197
  end: en,
173
198
  }
174
199
  let checkToken = false
175
- let hasCloseTag = false
176
200
  let checkTokenTagName = ''
177
201
  let caption = {
178
202
  mark: '',
@@ -180,7 +204,7 @@ const figureWithCaption = (state, opt) => {
180
204
  nameSuffix: '',
181
205
  isPrev: false,
182
206
  isNext: false,
183
- };
207
+ }
184
208
  const sp = {
185
209
  attrs: [],
186
210
  isVideoIframe: false,
@@ -188,34 +212,31 @@ const figureWithCaption = (state, opt) => {
188
212
  hasImgCaption: false,
189
213
  }
190
214
 
191
- const checkTypes = ['table', 'pre', 'blockquote']
192
215
  let cti = 0
193
- //console.log(state.tokens[n].type, state.tokens[n].tag)
194
216
  while (cti < checkTypes.length) {
195
217
  if (token.type === checkTypes[cti] + '_open') {
196
218
  // for n-1 token is line-break
197
- if (n > 1 && state.tokens[n-2].type === 'figure_open') {
219
+ if (n > 1 && tokens[n-2].type === 'figure_open') {
198
220
  cti++; continue
199
221
  }
200
222
  checkToken = true
201
223
  checkTokenTagName = token.tag
202
224
  caption.name = checkTypes[cti]
203
225
  if (checkTypes[cti] === 'pre') {
204
- if (state.tokens[n+1].tag === 'code') caption.mark = 'pre-code'
205
- if (state.tokens[n+1].tag === 'samp') caption.mark = 'pre-samp'
226
+ if (tokens[n+1].tag === 'code') caption.mark = 'pre-code'
227
+ if (tokens[n+1].tag === 'samp') caption.mark = 'pre-samp'
206
228
  caption.name = caption.mark
207
229
  }
208
- while (en < state.tokens.length) {
209
- if(state.tokens[en].type === checkTokenTagName + '_close') {
210
- hasCloseTag = true
230
+ while (en < tokens.length) {
231
+ if(tokens[en].type === checkTokenTagName + '_close') {
211
232
  break
212
233
  }
213
234
  en++
214
235
  }
215
236
  range.end = en
216
- caption = checkCaption(state, n, en, caption, sp, opt)
237
+ checkCaption(state, n, en, caption, fNum, sp, opt)
217
238
  if (caption.isPrev || caption.isNext) {
218
- range = wrapWithFigure(state, range, checkTokenTagName, caption, false, sp, opt)
239
+ wrapWithFigure(state, range, checkTokenTagName, caption, false, sp, opt)
219
240
  }
220
241
  break
221
242
  }
@@ -235,9 +256,9 @@ const figureWithCaption = (state, opt) => {
235
256
  checkTokenTagName = 'pre-code'
236
257
  caption.name = 'pre-code'
237
258
  }
238
- caption = checkCaption(state, n, en, caption, sp, opt)
259
+ checkCaption(state, n, en, caption, fNum, sp, opt)
239
260
  if (caption.isPrev || caption.isNext) {
240
- range = wrapWithFigure(state, range, checkTokenTagName, caption, false, sp, opt)
261
+ wrapWithFigure(state, range, checkTokenTagName, caption, false, sp, opt)
241
262
  break
242
263
  }
243
264
  }
@@ -247,23 +268,66 @@ const figureWithCaption = (state, opt) => {
247
268
  }
248
269
 
249
270
  if (token.type === 'html_block') {
250
- const tags = ['video', 'audio', 'iframe', 'blockquote']
251
271
  let ctj = 0
252
- while (ctj < tags.length) {
253
- const hasTag = token.content.match(new RegExp('^<'+ tags[ctj] + ' ?[^>]*?>[\\s\\S]*?<\\/' + tags[ctj] + '>(\\n| *?)(<script [^>]*?>(?:<\\/script>)?)? *(\\n|$)'))
254
- if (!hasTag) {
272
+ let hasTag
273
+ while (ctj < htmlTags.length) {
274
+ if (htmlTags[ctj] === 'div') {
275
+ // for vimeo
276
+ hasTag = token.content.match(getHtmlReg('div'))
277
+ htmlTags[ctj] = 'iframe'
278
+ sp.isVideoIframe = true
279
+ } else {
280
+ hasTag = token.content.match(getHtmlReg(htmlTags[ctj]))
281
+ }
282
+ const blueskyContMatch = token.content.match(blueskyEmbedReg)
283
+ if (!(hasTag || (blueskyContMatch && htmlTags[ctj] === 'blockquote'))) {
255
284
  ctj++
256
285
  continue
257
286
  }
258
- if ((hasTag[2] && hasTag[3] !== '\n') || (hasTag[1] !== '\n' && hasTag[2] === undefined)) {
259
- token.content += '\n'
287
+ if (hasTag) {
288
+ if ((hasTag[2] && hasTag[3] !== '\n') || (hasTag[1] !== '\n' && hasTag[2] === undefined)) {
289
+ token.content += '\n'
290
+ }
291
+ } else if (blueskyContMatch) {
292
+ let addedCont = ''
293
+ const tokensChildren = tokens
294
+ const tokensLength = tokensChildren.length
295
+ let j = n + 1
296
+ let hasEndBlockquote = true
297
+ while (j < tokensLength) {
298
+ const nextToken = tokens[j]
299
+ if (nextToken.type === 'inline' && /<\/blockquote> *<script[^>]*?><\/script>$/.test(nextToken.content)) {
300
+ addedCont += nextToken.content + '\n'
301
+ if (tokens[j + 1] && tokens[j + 1].type === 'paragraph_close') {
302
+ tokens.splice(j + 1, 1)
303
+ }
304
+ nextToken.content = ''
305
+ nextToken.children.forEach((child) => {
306
+ child.content = ''
307
+ })
308
+ break
309
+ }
310
+ if (nextToken.type === 'paragraph_open') {
311
+ addedCont += '\n'
312
+ tokens.splice(j, 1)
313
+ continue
314
+ }
315
+ j++
316
+ }
317
+ token.content += addedCont
318
+ if (!hasEndBlockquote) {
319
+ ctj++
320
+ continue
321
+ }
260
322
  }
261
- checkTokenTagName = tags[ctj]
262
- caption.name = tags[ctj]
323
+
324
+ checkTokenTagName = htmlTags[ctj]
325
+ caption.name = htmlTags[ctj]
263
326
  checkToken = true
264
327
  if (checkTokenTagName === 'blockquote') {
265
- //text-post-media: threads
266
- if(/^<[^>]*? class="(?:twitter-tweet|instagram-media|text-post-media|bluesky-embed)"/.test(token.content)) {
328
+ const classNameReg = /^<[^>]*? class="(twitter-tweet|instagram-media|text-post-media|bluesky-embed|mastodon-embed)"/
329
+ const isIframeTypeBlockquote = token.content.match(classNameReg)
330
+ if(isIframeTypeBlockquote) {
267
331
  sp.isIframeTypeBlockquote = true
268
332
  } else {
269
333
  ctj++
@@ -279,14 +343,14 @@ const figureWithCaption = (state, opt) => {
279
343
  }
280
344
  }
281
345
 
282
- caption = checkCaption(state, n, en, caption, sp, opt)
346
+ checkCaption(state, n, en, caption, fNum, sp, opt)
283
347
  if (caption.isPrev || caption.isNext) {
284
- range = wrapWithFigure(state, range, checkTokenTagName, caption, false, sp, opt)
348
+ wrapWithFigure(state, range, checkTokenTagName, caption, false, sp, opt)
285
349
  n = en + 2
286
350
  } else if ((opt.iframeWithoutCaption && (checkTokenTagName === 'iframe')) ||
287
351
  (opt.videoWithoutCaption && (checkTokenTagName === 'video')) ||
288
352
  (opt.iframeTypeBlockquoteWithoutCaption && (checkTokenTagName === 'blockquote'))) {
289
- range = wrapWithFigure(state, range, checkTokenTagName, caption, false, sp, opt)
353
+ wrapWithFigure(state, range, checkTokenTagName, caption, false, sp, opt)
290
354
  n = en + 2
291
355
  }
292
356
  }
@@ -298,19 +362,22 @@ const figureWithCaption = (state, opt) => {
298
362
  let isMultipleImagesVertical = true
299
363
  checkToken = true
300
364
  caption.name = 'img'
301
- while (ntChildTokenIndex < nextToken.children.length) {
302
- const ntChildToken = nextToken.children[ntChildTokenIndex]
303
- if (ntChildTokenIndex === nextToken.children.length - 1) {
365
+ const children = nextToken.children
366
+ const childrenLength = children.length
367
+ while (ntChildTokenIndex < childrenLength) {
368
+ const ntChildToken = children[ntChildTokenIndex]
369
+ if (ntChildTokenIndex === childrenLength - 1) {
304
370
  let imageAttrs = ntChildToken.content.match(/^ *\{(.*?)\} *$/)
305
371
  if(ntChildToken.type === 'text' && imageAttrs) {
306
372
  imageAttrs = imageAttrs[1].split(/ +/)
307
373
  let iai = 0
308
- while (iai < imageAttrs.length) {
374
+ const attrsLength = imageAttrs.length
375
+ while (iai < attrsLength) {
309
376
  if (/^\./.test(imageAttrs[iai])) {
310
377
  imageAttrs[iai] = imageAttrs[iai].replace(/^\./, "class=")
311
378
  }
312
379
  if (/^#/.test(imageAttrs[iai])) {
313
- imageAttrs[iai] = imageAttrs[iai].replace(/^\#/, "id=")
380
+ imageAttrs[iai] = imageAttrs[iai].replace(/^#/, "id=")
314
381
  }
315
382
  let imageAttr = imageAttrs[iai].match(/^(.*?)="?(.*)"?$/)
316
383
  if (!imageAttr || !imageAttr[1]) {
@@ -355,8 +422,8 @@ const figureWithCaption = (state, opt) => {
355
422
  caption.nameSuffix = '-multiple'
356
423
  }
357
424
  ntChildTokenIndex = 0
358
- while (ntChildTokenIndex < nextToken.children.length) {
359
- const ccToken = nextToken.children[ntChildTokenIndex]
425
+ while (ntChildTokenIndex < childrenLength) {
426
+ const ccToken = children[ntChildTokenIndex]
360
427
  if (ccToken.type === 'text' && /^ *$/.test(ccToken.content)) {
361
428
  ccToken.content = ''
362
429
  }
@@ -369,15 +436,15 @@ const figureWithCaption = (state, opt) => {
369
436
  nextToken.children[0].type = 'image'
370
437
 
371
438
  if (opt.imgAltCaption) setAltToLabel(state, n)
372
- if (opt.imgTitleCaption) setTitleToLabel(state, n, en, checkTokenTagName, caption, opt)
373
- caption = checkCaption(state, n, en, caption, sp, opt)
439
+ if (opt.imgTitleCaption) setTitleToLabel(state, n)
440
+ checkCaption(state, n, en, caption, fNum, sp, opt)
374
441
 
375
- if (opt.oneImageWithoutCaption && state.tokens[n-1]) {
376
- if (state.tokens[n-1].type === 'list_item_open') checkToken = false
442
+ if (opt.oneImageWithoutCaption && tokens[n-1]) {
443
+ if (tokens[n-1].type === 'list_item_open') checkToken = false
377
444
  }
378
445
  if (checkToken && (opt.oneImageWithoutCaption || caption.isPrev || caption.isNext)) {
379
446
  if (caption.nameSuffix) checkTokenTagName += caption.nameSuffix
380
- range = wrapWithFigure(state, range, checkTokenTagName, caption, true, sp, opt)
447
+ wrapWithFigure(state, range, checkTokenTagName, caption, true, sp, opt)
381
448
  }
382
449
  }
383
450
 
@@ -386,7 +453,7 @@ const figureWithCaption = (state, opt) => {
386
453
  n = range.start
387
454
  en = range.end
388
455
  if (caption.isPrev) {
389
- changePrevCaptionPosition(state, n, caption)
456
+ changePrevCaptionPosition(state, n, caption, opt)
390
457
  n = en + 1
391
458
  continue
392
459
  }
@@ -400,112 +467,7 @@ const figureWithCaption = (state, opt) => {
400
467
  return
401
468
  }
402
469
 
403
- const setAltToLabel = (state, n) => {
404
- if (n < 2) return false
405
- if (state.tokens[n+1].children[0].type !== 'image' || !state.tokens[n-2].children) return false
406
- if (state.tokens[n-2].children) {
407
- state.tokens[n+1].content = state.tokens[n+1].content.replace(/^!\[.*?\]/, '![' + state.tokens[n-2].children[0].content + ']')
408
- if (!state.tokens[n+1].children[0].children[0]) {
409
- const textToken = new state.Token('text', '', 0)
410
- state.tokens[n+1].children[0].children.push(textToken)
411
- }
412
- // Set figure label:
413
- //state.tokens[n+1].children[0].children[0].content = state.tokens[n-2].children[2].content
414
- // Set img alt to empty value:
415
- state.tokens[n+1].children[0].children[0].content = ''
416
- }
417
- // Set figure label:
418
- //state.tokens[n+1].children[0].content = state.tokens[n-2].children[2].content
419
- // Set img alt to empty value:
420
- state.tokens[n+1].children[0].content = ''
421
- //console.log(state.tokens[n+1].children[0])
422
- return true
423
- }
424
-
425
- const setTitleToLabel = (state, n, en, checkTokenTagName, caption, opt) => {
426
- if (n < 2) return false
427
- if (state.tokens[n+1].children[0].type !== 'image') return false
428
- if (!state.tokens[n-2].children[0]) return false
429
- state.tokens[n+1].children[0].attrSet('alt', state.tokens[n+1].children[0].content)
430
- if (!state.tokens[n+1].children[0].children[0]) {
431
- const textToken = new state.Token('text', '', 0)
432
- state.tokens[n+1].children[0].children.push(textToken)
433
- }
434
- let i = 0
435
- while (0 < state.tokens[n+1].children[0].attrs.length) {
436
- if (state.tokens[n+1].children[0].attrs[i][0] === 'title') {
437
- state.tokens[n+1].children[0].attrs.splice(i, i + 1)
438
- break
439
- } else {
440
- state.tokens[n+1].children[0].attrJoin('title', '')
441
- }
442
- i++
443
- }
444
- //console.log(state.tokens[n+1].children[0])
445
- return true
446
- }
447
-
448
- const imgAttrToPCaption = (state, startLine, opt) => {
449
- let pos = state.bMarks[startLine] + state.tShift[startLine]
450
- let max = state.eMarks[startLine]
451
- let inline = state.src.slice(pos, max)
452
- let label = ''
453
- if (opt.imgAltCaption && typeof opt.imgAltCaption === 'string') label = opt.imgAltCaption
454
- if (opt.imgTitleCaption && typeof opt.imgTitleCaption === 'string') label = opt.imgTitleCaption
455
- let caption = ''
456
- let imgAttrUsedCaption = ''
457
-
458
- const img = inline.match(/^( *!\[)(.*?)\]\( *?((.*?)(?: +?\"(.*?)\")?) *?\)( *?\{.*?\})? *$/)
459
- if (!img) return
460
-
461
- let hasLabel
462
- if (opt.imgAltCaption) {
463
- caption = img[2]
464
- hasLabel = img[2].match(new RegExp('^' + opt.imgAltCaption))
465
- imgAttrUsedCaption = 'alt'
466
- }
467
- if (opt.imgTitleCaption) {
468
- if (!img[5]) img[5] = ''
469
- caption = img[5]
470
- hasLabel = img[5].match(new RegExp('^' + opt.imgTitleCaption))
471
- imgAttrUsedCaption = 'title'
472
- }
473
- let token
474
- token = state.push('paragraph_open', 'p', 1)
475
- token.map = [startLine, startLine + 1]
476
- token = state.push('inline', '', 0)
477
- if (hasLabel) {
478
- token.content = caption
479
- } else {
480
- if (!label) {
481
- if (imgAttrUsedCaption === 'alt') {
482
- label = opt.imgAltCaption
483
- } else if (imgAttrUsedCaption === 'title') {
484
- label = opt.imgTitleCaption
485
- } else if (imgAttrUsedCaption) {
486
- label = 'Figure'
487
- }
488
- }
489
- token.content = label
490
- if (/[a-zA-Z]/.test(label)) {
491
- token.content += '.'
492
- if (caption) token.content += ' '
493
- } else {
494
- token.content += ' '
495
- }
496
- token.content += caption
497
- }
498
- token.map = [startLine, startLine + 1]
499
- token.children = []
500
- if (caption.length === 0) {
501
- token.attrs = [['class', 'nocaption']]
502
- }
503
- token = state.push('paragraph_close', 'p', -1)
504
- return
505
- }
506
-
507
470
  const mditFigureWithPCaption = (md, option) => {
508
-
509
471
  let opt = {
510
472
  classPrefix: 'f',
511
473
  figureClassThatWrapsIframeTypeBlockquote: 'f-img',
@@ -523,19 +485,25 @@ const mditFigureWithPCaption = (md, option) => {
523
485
  iframeTypeBlockquoteWithoutCaption: false,
524
486
  removeUnnumberedLabel: false,
525
487
  removeUnnumberedLabelExceptMarks: [],
488
+ removeMarkNameInCaptionClass: false,
526
489
  multipleImages: true,
527
490
  imgAltCaption: false,
491
+ setFigureNumber: false,
528
492
  imgTitleCaption: false,
529
493
  roleDocExample: false,
494
+ allIframeTypeFigureClassName: '',
530
495
  }
531
- if (option !== undefined) {
532
- for (let o in option) {
533
- opt[o] = option[o]
534
- }
535
- }
496
+ if (option) Object.assign(opt, option)
536
497
 
537
498
  if (opt.imgAltCaption || opt.imgTitleCaption) {
538
- opt.oneImageWithoutCaption = false
499
+ opt.oneImageWithoutCaption = true
500
+ opt.multipleImages = false
501
+ if (opt.setFigureNumber) {
502
+ for (let mark of opt.removeUnnumberedLabelExceptMarks) {
503
+ if (mark === 'img') opt.removeUnnumberedLabelExceptMarks.splice(opt.removeUnnumberedLabelExceptMarks.indexOf(mark), 1)
504
+ if (mark === 'table') opt.removeUnnumberedLabelExceptMarks.splice(opt.removeUnnumberedLabelExceptMarks.indexOf(mark), 1)
505
+ }
506
+ }
539
507
  md.block.ruler.before('paragraph', 'img_attr_caption', (state) => {
540
508
  imgAttrToPCaption(state, state.line, opt)
541
509
  })
package/package.json CHANGED
@@ -1,25 +1,28 @@
1
1
  {
2
2
  "name": "@peaceroad/markdown-it-figure-with-p-caption",
3
- "version": "0.10.1",
3
+ "version": "0.12.0",
4
4
  "description": "A markdown-it plugin. For a paragraph with only one image, a table or code block or blockquote, and by writing a caption paragraph immediately before or after, they are converted into the figure element with the figcaption element.",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "test": "node test/test.js"
9
9
  },
10
- "repository": "https://github.com/peaceroad/p7d-markdown-it-figure-with-p-caption.git",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/peaceroad/p7d-markdown-it-figure-with-p-caption.git"
13
+ },
11
14
  "author": "peaceroad <peaceroad@gmail.com>",
12
15
  "license": "MIT",
13
16
  "bugs": {
14
17
  "url": "https://github.com/peaceroad/p7d-markdown-it-figure-with-p-caption/issues"
15
18
  },
16
19
  "devDependencies": {
17
- "@peaceroad/markdown-it-renderer-fence": "^0.1.1",
18
- "highlight.js": "^11.10.0",
20
+ "@peaceroad/markdown-it-renderer-fence": "^0.1.2",
21
+ "highlight.js": "^11.11.1",
19
22
  "markdown-it": "^14.1.0",
20
- "markdown-it-attrs": "^4.2.0"
23
+ "markdown-it-attrs": "^4.3.1"
21
24
  },
22
25
  "dependencies": {
23
- "p7d-markdown-it-p-captions": "^0.15.2"
26
+ "p7d-markdown-it-p-captions": "^0.17.0"
24
27
  }
25
28
  }
@@ -0,0 +1,192 @@
1
+ [Markdown]
2
+ A paragraph.
3
+
4
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
5
+
6
+ A paragraph.
7
+ [HTML]
8
+ <p>A paragraph.</p>
9
+ <figure class="f-embed">
10
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
11
+ </figure>
12
+ <p>A paragraph.</p>
13
+
14
+
15
+ [Markdown]
16
+ A paragraph.
17
+
18
+ Video. A youtube.
19
+
20
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
21
+
22
+ A paragraph.
23
+ [HTML]
24
+ <p>A paragraph.</p>
25
+ <figure class="f-embed">
26
+ <figcaption><span class="f-video-label">Video<span class="f-video-label-joint">.</span></span> A youtube.</figcaption>
27
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
28
+ </figure>
29
+ <p>A paragraph.</p>
30
+
31
+
32
+ [Markdown]
33
+ A paragraph.
34
+
35
+ Source. Twitter Post.
36
+
37
+ <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
38
+
39
+ A paragraph.
40
+ [HTML]
41
+ <p>A paragraph.</p>
42
+ <figure class="f-embed">
43
+ <figcaption><span class="f-blockquote-label">Source<span class="f-blockquote-label-joint">.</span></span> Twitter Post.</figcaption>
44
+ <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
45
+ </figure>
46
+ <p>A paragraph.</p>
47
+
48
+ [Markdown]
49
+ A paragraph.
50
+
51
+ Figure. Twitter Post.
52
+
53
+ <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
54
+
55
+ A paragraph.
56
+ [HTML]
57
+ <p>A paragraph.</p>
58
+ <figure class="f-embed">
59
+ <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> Twitter Post.</figcaption>
60
+ <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
61
+ </figure>
62
+ <p>A paragraph.</p>
63
+
64
+ [Markdown]
65
+ A paragraph.
66
+
67
+ <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
68
+
69
+ Figure. Twitter Post.
70
+
71
+ A paragraph.
72
+ [HTML]
73
+ <p>A paragraph.</p>
74
+ <figure class="f-embed">
75
+ <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
76
+ <figcaption><span class="f-img-label">Figure<span class="f-img-label-joint">.</span></span> Twitter Post.</figcaption>
77
+ </figure>
78
+ <p>A paragraph.</p>
79
+
80
+ [Markdown]
81
+ A paragraph.
82
+
83
+ <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
84
+
85
+ Quote. Twitter Post.
86
+
87
+ A paragraph.
88
+ [HTML]
89
+ <p>A paragraph.</p>
90
+ <figure class="f-embed">
91
+ <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
92
+ <figcaption><span class="f-blockquote-label">Quote<span class="f-blockquote-label-joint">.</span></span> Twitter Post.</figcaption>
93
+ </figure>
94
+ <p>A paragraph.</p>
95
+
96
+
97
+ [Markdown]
98
+ A paragraph. 28.
99
+
100
+ <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
101
+
102
+ A paragraph.
103
+ [HTML]
104
+ <p>A paragraph. 28.</p>
105
+ <figure class="f-embed">
106
+ <blockquote class="twitter-tweet"><p lang="ja" dir="ltr">XXXXX <a href="https://t.co/XXXXX">https://t.co/XXXXX</a></p>&mdash; User (@twitter) <a href="https://twitter.com/UserID/status/XXXXX">August 4, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
107
+ </figure>
108
+ <p>A paragraph.</p>
109
+
110
+
111
+ [Markdown]
112
+ <video controls width="400" height="300">
113
+ <source src="example.mp4" type="video/mp4">
114
+ </video>
115
+ [HTML]
116
+ <figure class="f-video">
117
+ <video controls width="400" height="300">
118
+ <source src="example.mp4" type="video/mp4">
119
+ </video>
120
+ </figure>
121
+
122
+ [Markdown]
123
+ Video. A caption.
124
+
125
+ <video controls width="400" height="300">
126
+ <source src="example.mp4" type="video/mp4">
127
+ </video>
128
+ [HTML]
129
+ <figure class="f-video">
130
+ <figcaption><span class="f-video-label">Video<span class="f-video-label-joint">.</span></span> A caption.</figcaption>
131
+ <video controls width="400" height="300">
132
+ <source src="example.mp4" type="video/mp4">
133
+ </video>
134
+ </figure>
135
+
136
+
137
+ [Markdown]
138
+ A YouTube paragraph.
139
+
140
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
141
+
142
+ A paragraph.
143
+ [HTML]
144
+ <p>A YouTube paragraph.</p>
145
+ <figure class="f-embed">
146
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
147
+ </figure>
148
+ <p>A paragraph.</p>
149
+
150
+
151
+ [Markdown]
152
+ Video. A YouTube caption.
153
+
154
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
155
+
156
+ A paragraph.
157
+ [HTML]
158
+ <figure class="f-embed">
159
+ <figcaption><span class="f-video-label">Video<span class="f-video-label-joint">.</span></span> A YouTube caption.</figcaption>
160
+ <iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/XXXXXXXXXXX" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
161
+ </figure>
162
+ <p>A paragraph.</p>
163
+
164
+
165
+ [Markdown]
166
+ <blockquote class="bluesky-embed" data-bluesky-uri="at://xxxxxxxxxxxxx" data-bluesky-cid="xxxx"><p lang="en">xxxx
167
+
168
+ xxxx</p>&mdash; xxxx (<a href="https://bsky.app/profile/xxx">@xxx</a>) <a href="https://bsky.app/profile/xxx?ref_src=embed">1970年01月01日 00:00</a></blockquote><script async src="https://embed.bsky.app/static/embed.js" charset="utf-8"></script>
169
+
170
+ [HTML]
171
+ <figure class="f-embed">
172
+ <blockquote class="bluesky-embed" data-bluesky-uri="at://xxxxxxxxxxxxx" data-bluesky-cid="xxxx"><p lang="en">xxxx
173
+
174
+ xxxx</p>&mdash; xxxx (<a href="https://bsky.app/profile/xxx">@xxx</a>) <a href="https://bsky.app/profile/xxx?ref_src=embed">1970年01月01日 00:00</a></blockquote><script async src="https://embed.bsky.app/static/embed.js" charset="utf-8"></script>
175
+ </figure>
176
+
177
+
178
+ [Markdown]
179
+ <blockquote class="mastodon-embed" data-embed-url="https://mastodon.social/@xxxx/xxxx/embed" style="background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;"> <a href="https://mastodon.social/xxxx" target="_blank" style="align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 79 75"><path d="xxx" fill="currentColor"/></svg> <div style="color: #787588; margin-top: 16px;">Post by @xxx</div> <div style="font-weight: 500;">View on Mastodon</div> </a> </blockquote> <script data-allowed-prefixes="https://mastodon.social/" async src="https://mastodon.social/embed.js"></script>
180
+
181
+ [HTML]
182
+ <figure class="f-embed">
183
+ <blockquote class="mastodon-embed" data-embed-url="https://mastodon.social/@xxxx/xxxx/embed" style="background: #FCF8FF; border-radius: 8px; border: 1px solid #C9C4DA; margin: 0; max-width: 540px; min-width: 270px; overflow: hidden; padding: 0;"> <a href="https://mastodon.social/xxxx" target="_blank" style="align-items: center; color: #1C1A25; display: flex; flex-direction: column; font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', Roboto, sans-serif; font-size: 14px; justify-content: center; letter-spacing: 0.25px; line-height: 20px; padding: 24px; text-decoration: none;"> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="32" height="32" viewBox="0 0 79 75"><path d="xxx" fill="currentColor"/></svg> <div style="color: #787588; margin-top: 16px;">Post by @xxx</div> <div style="font-weight: 500;">View on Mastodon</div> </a> </blockquote> <script data-allowed-prefixes="https://mastodon.social/" async src="https://mastodon.social/embed.js"></script>
184
+ </figure>
185
+
186
+
187
+ [Markdown]
188
+ <div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/xxxxxxx" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="xxxx"></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
189
+ [HTML]
190
+ <figure class="f-embed">
191
+ <div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/xxxxxxx" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write" style="position:absolute;top:0;left:0;width:100%;height:100%;" title="xxxx"></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>
192
+ </figure>
@@ -0,0 +1,51 @@
1
+ [Markdown]
2
+ ![A caption.](cat.jpg)
3
+
4
+ [HTML]
5
+ <figure class="f-img">
6
+ <figcaption><span class="f-img-label">Figure 1<span class="f-img-label-joint">.</span></span> A caption.</figcaption>
7
+ <img src="cat.jpg" alt="">
8
+ </figure>
9
+
10
+
11
+ [Markdown]
12
+ ![Figure. A caption.](cat.jpg)
13
+
14
+ [HTML]
15
+ <figure class="f-img">
16
+ <figcaption><span class="f-img-label">Figure 1<span class="f-img-label-joint">.</span></span> A caption.</figcaption>
17
+ <img src="cat.jpg" alt="">
18
+ </figure>
19
+
20
+
21
+ [Markdown]
22
+ ![](cat.jpg)
23
+
24
+ [HTML]
25
+ <figure class="f-img">
26
+ <figcaption><span class="f-img-label">Figure 1<span class="f-img-label-joint">.</span></span></figcaption>
27
+ <img src="cat.jpg" alt="">
28
+ </figure>
29
+
30
+
31
+ [Markdown]
32
+ Figure. A caption.
33
+
34
+ ![](cat.jpg)
35
+
36
+ [HTML]
37
+ <p>Figure. A caption.</p>
38
+ <figure class="f-img">
39
+ <figcaption><span class="f-img-label">Figure 1<span class="f-img-label-joint">.</span></span></figcaption>
40
+ <img src="cat.jpg" alt="">
41
+ </figure>
42
+
43
+
44
+ [Markdown]
45
+ ![Figure 12. A caption.](cat.jpg)
46
+
47
+ [HTML]
48
+ <figure class="f-img">
49
+ <figcaption><span class="f-img-label">Figure 12<span class="f-img-label-joint">.</span></span> A caption.</figcaption>
50
+ <img src="cat.jpg" alt="">
51
+ </figure>
@@ -48,4 +48,13 @@ Figure. A caption.
48
48
  <img src="cat.jpg" alt="">
49
49
  </figure>
50
50
 
51
+ [Markdown]
52
+ ![Figure.1 A caption.](cat.jpg)
53
+
54
+ [HTML]
55
+ <figure class="f-img">
56
+ <figcaption><span class="f-img-label">Figure.1</span> A caption.</figcaption>
57
+ <img src="cat.jpg" alt="">
58
+ </figure>
59
+
51
60
 
@@ -0,0 +1,60 @@
1
+ [Markdown]
2
+ ![](cat.jpg "A caption.")
3
+
4
+ [HTML]
5
+ <figure class="f-img">
6
+ <figcaption><span class="f-img-label">Figure 1<span class="f-img-label-joint">.</span></span> A caption.</figcaption>
7
+ <img src="cat.jpg" alt="">
8
+ </figure>
9
+
10
+
11
+ [Markdown]
12
+ ![](cat.jpg "Figure. A caption.")
13
+
14
+ [HTML]
15
+ <figure class="f-img">
16
+ <figcaption><span class="f-img-label">Figure 1<span class="f-img-label-joint">.</span></span> A caption.</figcaption>
17
+ <img src="cat.jpg" alt="">
18
+ </figure>
19
+
20
+
21
+ [Markdown]
22
+ ![A alt text.](cat.jpg)
23
+
24
+ [HTML]
25
+ <figure class="f-img">
26
+ <img src="cat.jpg" alt="A alt text.">
27
+ </figure>
28
+
29
+ [Markdown]
30
+ ![A alt text.](cat.jpg "Figure.")
31
+
32
+ [HTML]
33
+ <figure class="f-img">
34
+ <figcaption><span class="f-img-label">Figure 1<span class="f-img-label-joint">.</span></span></figcaption>
35
+ <img src="cat.jpg" alt="A alt text.">
36
+ </figure>
37
+
38
+
39
+ [Markdown]
40
+ Figure. A caption.
41
+
42
+ ![](cat.jpg)
43
+
44
+ [HTML]
45
+ <p>Figure. A caption.</p>
46
+ <figure class="f-img">
47
+ <img src="cat.jpg" alt="">
48
+ </figure>
49
+
50
+
51
+ [Markdown]
52
+ ![](cat.jpg "Figure 12. A caption.")
53
+
54
+ [HTML]
55
+ <figure class="f-img">
56
+ <figcaption><span class="f-img-label">Figure 12<span class="f-img-label-joint">.</span></span> A caption.</figcaption>
57
+ <img src="cat.jpg" alt="">
58
+ </figure>
59
+
60
+
@@ -741,3 +741,30 @@ code
741
741
  <pre><samp>&gt;
742
742
  </samp></pre>
743
743
  </figure>
744
+
745
+ [Markdown]
746
+ リスト キャプション
747
+
748
+ ```
749
+ >
750
+ ```
751
+ [HTML]
752
+ <figure class="f-pre-code">
753
+ <figcaption><span class="f-pre-code-label">リスト</span> キャプション</figcaption>
754
+ <pre><code>&gt;
755
+ </code></pre>
756
+ </figure>
757
+
758
+
759
+ [Markdown]
760
+ 図 キャプション
761
+
762
+ ```samp
763
+ >
764
+ ```
765
+ [HTML]
766
+ <figure class="f-pre-samp">
767
+ <figcaption><span class="f-pre-samp-label">図</span> キャプション</figcaption>
768
+ <pre><samp>&gt;
769
+ </samp></pre>
770
+ </figure>
@@ -0,0 +1,21 @@
1
+ [Markdown]
2
+ Figure. A caption.
3
+
4
+ ![](example.jpg)
5
+
6
+ Figure. A caption.
7
+
8
+ ![](example.jpg)
9
+
10
+ [HTML]
11
+ <figure class="f-img">
12
+ <figcaption><span class="f-img-label">Figure 1<span class="f-img-label-joint">.</span></span> A caption.</figcaption>
13
+ <img src="example.jpg" alt="">
14
+ </figure>
15
+ <figure class="f-img">
16
+ <figcaption><span class="f-img-label">Figure 2<span class="f-img-label-joint">.</span></span> A caption.</figcaption>
17
+ <img src="example.jpg" alt="">
18
+ </figure>
19
+
20
+
21
+
package/test/test.js CHANGED
@@ -16,6 +16,7 @@ let opt = {
16
16
  videoWithoutCaption: false,
17
17
  hasNumClass: false,
18
18
  iframeTypeBlockquoteWithoutCaption: false,
19
+ setFigureNumber: false,
19
20
  }
20
21
 
21
22
  const md = mdit({ html: true }).use(mdFigureWithPCaption, opt).use(mditAttrs).use(mditRndererFence);
@@ -40,6 +41,7 @@ const mdMultipleImages = mdit({ html: true }).use(mdFigureWithPCaption, opt).use
40
41
  opt.videoWithoutCaption = true
41
42
  const mdVideoWithoutCaption = mdit({ html: true }).use(mdFigureWithPCaption, opt).use(mditAttrs).use(mditRndererFence);
42
43
 
44
+
43
45
  const mdConsole = mdit({
44
46
  html: true,
45
47
  langPrefix: 'language-',
@@ -73,6 +75,10 @@ const testData = {
73
75
  imgAltCaption: __dirname + path.sep + 'examples-img-alt-caption.txt',
74
76
  imgTitleCaption: __dirname + path.sep + 'examples-img-title-caption.txt',
75
77
  console: __dirname + path.sep + 'examples-console.txt',
78
+ setFigureNumber: __dirname + path.sep + 'examples-set-figure-number.txt',
79
+ imgAltCaptionNumber: __dirname + path.sep + 'examples-img-alt-caption-number.txt',
80
+ imgTitleCaptionNumber: __dirname + path.sep + 'examples-img-title-caption-number.txt',
81
+ allIframeTypeFigureClassName: __dirname + path.sep + 'examples-all-iframe-type-figure-class-name.txt',
76
82
  }
77
83
 
78
84
  const getTestData = (pat) => {
@@ -125,7 +131,7 @@ const runTest = (process, pat, pass, testId) => {
125
131
  while(n <= end) {
126
132
 
127
133
  if (!ms[n]
128
- //|| n != 43
134
+ //|| n != 11
129
135
  ) {
130
136
  n++
131
137
  continue
@@ -177,4 +183,26 @@ opt.imgTitleCaption = '図'
177
183
  const mdImgTitleCaptionJa = mdit({html: true}).use(mdFigureWithPCaption, opt).use(mditAttrs).use(mditRndererFence);
178
184
  pass = runTest(mdImgTitleCaptionJa, testData.imgTitleCaption.replace(/.txt$/, '.ja.txt'), pass)
179
185
 
186
+ opt = {}
187
+ opt.setFigureNumber = true
188
+ const mdSetFigureNumber = mdit({html: true}).use(mdFigureWithPCaption, opt).use(mditAttrs).use(mditRndererFence);
189
+ pass = runTest(mdSetFigureNumber, testData.setFigureNumber.replace(/\.txt$/, '.en.txt'), pass)
190
+
191
+ opt.imgAltCaption = true
192
+ const mdImgAltCaptionNumber = mdit({html: true}).use(mdFigureWithPCaption, opt).use(mditAttrs).use(mditRndererFence);
193
+ pass = runTest(mdImgAltCaptionNumber, testData.imgAltCaptionNumber.replace(/\.txt$/, '.en.txt'), pass)
194
+
195
+ opt = {}
196
+ opt.imgTitleCaption = true
197
+ const mdImgTitleCaptionNumber = mdit({html: true}).use(mdFigureWithPCaption, opt).use(mditAttrs).use(mditRndererFence);
198
+ //pass = runTest(mdImgTitleCaptionNumber, testData.imgTitleCaptionNumber.replace(/\.txt$/, '.en.txt'), pass)
199
+
200
+ opt = {}
201
+ opt.videoWithoutCaption = true
202
+ opt.iframeWithoutCaption = true
203
+ opt.iframeTypeBlockquoteWithoutCaption = true
204
+ opt.allIframeTypeFigureClassName = 'f-embed'
205
+ const mdAllIframeTypeFigureClassName = mdit({html: true}).use(mdFigureWithPCaption, opt).use(mditAttrs).use(mditRndererFence);
206
+ pass = runTest(mdAllIframeTypeFigureClassName, testData.allIframeTypeFigureClassName, pass)
207
+
180
208
  if (pass) console.log('Passed all test.')