@diplodoc/transform 4.27.1-beta → 4.28.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/dist/css/print.css.map +2 -2
- package/dist/css/yfm.css +21 -4
- package/dist/css/yfm.css.map +3 -3
- package/dist/css/yfm.min.css +1 -1
- package/dist/css/yfm.min.css.map +3 -3
- package/dist/js/yfm.js +74 -41
- package/dist/js/yfm.js.map +3 -3
- package/dist/js/yfm.min.js +1 -1
- package/dist/js/yfm.min.js.map +3 -3
- package/lib/plugins/code.js +35 -33
- package/lib/plugins/code.js.map +1 -1
- package/lib/plugins/term/index.js +1 -0
- package/lib/plugins/term/index.js.map +1 -1
- package/lib/sanitize.js +1 -1
- package/lib/sanitize.js.map +1 -1
- package/package.json +3 -3
- package/src/js/code.ts +1 -1
- package/src/js/term/index.ts +17 -48
- package/src/js/term/utils.ts +75 -5
- package/src/scss/_anchor.scss +10 -4
- package/src/scss/_code.scss +23 -10
- package/src/transform/plugins/code.ts +35 -33
- package/src/transform/plugins/term/index.ts +1 -0
- package/src/transform/sanitize.ts +2 -2
package/src/js/term/utils.ts
CHANGED
|
@@ -112,19 +112,19 @@ export function setDefinitionPosition(
|
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
function termOnResize() {
|
|
115
|
-
const
|
|
115
|
+
const openedDefinition = document.getElementsByClassName(openDefinitionClass)[0] as HTMLElement;
|
|
116
116
|
|
|
117
|
-
if (!
|
|
117
|
+
if (!openedDefinition) {
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
120
|
-
const termId =
|
|
120
|
+
const termId = openedDefinition.getAttribute('term-id') || '';
|
|
121
121
|
const termElement = document.getElementById(termId);
|
|
122
122
|
|
|
123
123
|
if (!termElement) {
|
|
124
124
|
return;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
setDefinitionPosition(
|
|
127
|
+
setDefinitionPosition(openedDefinition, termElement);
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
function termParentElement(term: HTMLElement | null) {
|
|
@@ -137,16 +137,57 @@ function termParentElement(term: HTMLElement | null) {
|
|
|
137
137
|
return closestScrollableParent || term.parentElement;
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
export function openDefinition(target: HTMLElement) {
|
|
141
|
+
const openedDefinition = document.getElementsByClassName(openDefinitionClass)[0] as HTMLElement;
|
|
142
|
+
|
|
143
|
+
const termId = target.getAttribute('id');
|
|
144
|
+
const termKey = target.getAttribute('term-key');
|
|
145
|
+
let definitionElement = document.getElementById(termKey + '_element');
|
|
146
|
+
|
|
147
|
+
if (termKey && !definitionElement) {
|
|
148
|
+
definitionElement = createDefinitionElement(target);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const isSameTerm = openedDefinition && termId === openedDefinition.getAttribute('term-id');
|
|
152
|
+
if (isSameTerm) {
|
|
153
|
+
closeDefinition(openedDefinition);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const isTargetDefinitionContent = target.closest(
|
|
158
|
+
[Selector.CONTENT.replace(' ', ''), openClass].join('.'),
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
if (openedDefinition && !isTargetDefinitionContent) {
|
|
162
|
+
closeDefinition(openedDefinition);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (!target.matches(Selector.TITLE) || !definitionElement) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
setDefinitionId(definitionElement, target);
|
|
170
|
+
setDefinitonAriaLive(definitionElement, target);
|
|
171
|
+
setDefinitionPosition(definitionElement, target);
|
|
172
|
+
|
|
173
|
+
definitionElement.classList.toggle(openClass);
|
|
174
|
+
|
|
175
|
+
trapFocus(definitionElement);
|
|
176
|
+
}
|
|
177
|
+
|
|
140
178
|
export function closeDefinition(definition: HTMLElement) {
|
|
141
179
|
definition.classList.remove(openClass);
|
|
142
180
|
const termId = definition.getAttribute('term-id') || '';
|
|
143
|
-
const
|
|
181
|
+
const term = document.getElementById(termId);
|
|
182
|
+
const termParent = termParentElement(term);
|
|
144
183
|
|
|
145
184
|
if (!termParent) {
|
|
146
185
|
return;
|
|
147
186
|
}
|
|
148
187
|
|
|
149
188
|
termParent.removeEventListener('scroll', termOnResize);
|
|
189
|
+
term?.focus(); // Set focus back to open button after closing popup
|
|
190
|
+
|
|
150
191
|
isListenerNeeded = true;
|
|
151
192
|
}
|
|
152
193
|
|
|
@@ -167,3 +208,32 @@ function getCoords(elem: HTMLElement) {
|
|
|
167
208
|
|
|
168
209
|
return {top: Math.round(top), left: Math.round(left)};
|
|
169
210
|
}
|
|
211
|
+
|
|
212
|
+
export function trapFocus(element: HTMLElement) {
|
|
213
|
+
const focusableElements = element.querySelectorAll(
|
|
214
|
+
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
|
|
215
|
+
);
|
|
216
|
+
const firstFocusableElement = focusableElements[0] as HTMLElement;
|
|
217
|
+
const lastFocusableElement = focusableElements[focusableElements.length - 1] as HTMLElement;
|
|
218
|
+
|
|
219
|
+
if (firstFocusableElement) {
|
|
220
|
+
firstFocusableElement.focus();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
element.addEventListener('keydown', function (e) {
|
|
224
|
+
const isTabPressed = e.key === 'Tab' || e.keyCode === 9;
|
|
225
|
+
if (!isTabPressed) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (e.shiftKey) {
|
|
230
|
+
if (document.activeElement === firstFocusableElement) {
|
|
231
|
+
lastFocusableElement.focus();
|
|
232
|
+
e.preventDefault();
|
|
233
|
+
}
|
|
234
|
+
} else if (document.activeElement === lastFocusableElement) {
|
|
235
|
+
firstFocusableElement.focus();
|
|
236
|
+
e.preventDefault();
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
}
|
package/src/scss/_anchor.scss
CHANGED
|
@@ -9,11 +9,17 @@
|
|
|
9
9
|
|
|
10
10
|
text-align: center;
|
|
11
11
|
font-size: 18px;
|
|
12
|
-
}
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
&:focus {
|
|
14
|
+
&::before {
|
|
15
|
+
opacity: 1;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
&::before {
|
|
20
|
+
content: '#';
|
|
21
|
+
opacity: 0;
|
|
22
|
+
}
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
&:hover .yfm-anchor::before {
|
package/src/scss/_code.scss
CHANGED
|
@@ -2,22 +2,35 @@
|
|
|
2
2
|
&-clipboard {
|
|
3
3
|
position: relative;
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
&-button {
|
|
6
|
+
&:hover, &:focus {
|
|
7
|
+
opacity: 1;
|
|
8
|
+
}
|
|
7
9
|
}
|
|
8
10
|
|
|
9
11
|
& > pre {
|
|
10
12
|
border-radius: 10px;
|
|
11
13
|
overflow: hidden;
|
|
12
14
|
}
|
|
13
|
-
}
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
&-button {
|
|
17
|
+
position: absolute;
|
|
18
|
+
top: 16px;
|
|
19
|
+
right: 16px;
|
|
20
|
+
z-index: 1;
|
|
21
|
+
opacity: 0;
|
|
22
|
+
|
|
23
|
+
//reset default button style
|
|
24
|
+
background: none;
|
|
25
|
+
color: inherit;
|
|
26
|
+
border: none;
|
|
27
|
+
padding: 0;
|
|
28
|
+
font: inherit;
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
&-icon {
|
|
33
|
+
pointer-events: none;
|
|
34
|
+
}
|
|
22
35
|
}
|
|
23
36
|
}
|
|
@@ -6,39 +6,41 @@ import {generateID} from './utils';
|
|
|
6
6
|
const wrapInClipboard = (element: string | undefined, id: number) => {
|
|
7
7
|
return `
|
|
8
8
|
<div class="yfm-clipboard">
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
9
|
+
${element}
|
|
10
|
+
<button class="yfm-clipboard-button">
|
|
11
|
+
<svg width="16" height="16" viewBox="0 0 24 24" class="yfm-clipboard-icon" data-animation="${id}">
|
|
12
|
+
<path
|
|
13
|
+
fill="currentColor"
|
|
14
|
+
d="M19,21H8V7H19M19,5H8A2,2 0 0,0 6,7V21A2,2 0 0,0 8,23H19A2,2 0 0,0 21,21V7A2,2 0 0,0 19,5M16,1H4A2,2 0 0,0 2,3V17H4V3H16V1Z"
|
|
15
|
+
/>
|
|
16
|
+
<path
|
|
17
|
+
stroke="currentColor"
|
|
18
|
+
fill="transparent"
|
|
19
|
+
stroke-width="1.5"
|
|
20
|
+
d="M9.5 13l3 3l5 -5"
|
|
21
|
+
visibility="hidden"
|
|
22
|
+
>
|
|
23
|
+
<animate
|
|
24
|
+
id="visibileAnimation-${id}"
|
|
25
|
+
attributeName="visibility"
|
|
26
|
+
from="hidden"
|
|
27
|
+
to="visible"
|
|
28
|
+
dur="0.2s"
|
|
29
|
+
fill="freeze"
|
|
30
|
+
begin=""
|
|
31
|
+
/>
|
|
32
|
+
<animate
|
|
33
|
+
id="hideAnimation-${id}"
|
|
34
|
+
attributeName="visibility"
|
|
35
|
+
from="visible"
|
|
36
|
+
to="hidden"
|
|
37
|
+
dur="1s"
|
|
38
|
+
begin="visibileAnimation-${id}.end+1"
|
|
39
|
+
fill="freeze"
|
|
40
|
+
/>
|
|
41
|
+
</path>
|
|
42
|
+
</svg>
|
|
43
|
+
</button>
|
|
42
44
|
</div>
|
|
43
45
|
`;
|
|
44
46
|
};
|
|
@@ -100,6 +100,7 @@ const term: MarkdownItPluginCb = (md, options) => {
|
|
|
100
100
|
token.attrSet('class', 'yfm yfm-term_title');
|
|
101
101
|
token.attrSet('term-key', ':' + termKey);
|
|
102
102
|
token.attrSet('aria-describedby', ':' + termKey + '_element');
|
|
103
|
+
token.attrSet('tabindex', '0');
|
|
103
104
|
token.attrSet('id', generateID());
|
|
104
105
|
nodes.push(token);
|
|
105
106
|
|
|
@@ -485,7 +485,7 @@ const defaultCssWhitelist = {
|
|
|
485
485
|
'--method': true,
|
|
486
486
|
};
|
|
487
487
|
|
|
488
|
-
const yfmHtmlAttrs = ['note-type', 'term-key'];
|
|
488
|
+
const yfmHtmlAttrs = ['note-type', 'yfm2xliff-explicit', 'term-key'];
|
|
489
489
|
|
|
490
490
|
const allowedTags = Array.from(
|
|
491
491
|
new Set([...htmlTags, ...svgTags, ...sanitizeHtml.defaults.allowedTags]),
|
|
@@ -518,7 +518,7 @@ export const defaultOptions: SanitizeOptions = {
|
|
|
518
518
|
function sanitizeStyleTags(dom: cheerio.CheerioAPI, cssWhiteList: CssWhiteList) {
|
|
519
519
|
const styleTags = dom('style');
|
|
520
520
|
|
|
521
|
-
styleTags.each((_index, element) => {
|
|
521
|
+
styleTags.each((_index: number, element: cheerio.Element) => {
|
|
522
522
|
const styleText = dom(element).text();
|
|
523
523
|
|
|
524
524
|
try {
|