vidply 1.0.21 → 1.0.24
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/vidply.css +720 -547
- package/dist/vidply.esm.js +411 -104
- package/dist/vidply.esm.js.map +2 -2
- package/dist/vidply.esm.min.js +11 -7
- package/dist/vidply.esm.min.meta.json +30 -25
- package/dist/vidply.js +411 -104
- package/dist/vidply.js.map +2 -2
- package/dist/vidply.min.css +1 -1
- package/dist/vidply.min.js +11 -7
- package/dist/vidply.min.meta.json +30 -25
- package/package.json +2 -2
- package/src/controls/ControlBar.js +3343 -3246
- package/src/controls/TranscriptManager.js +2296 -2271
- package/src/core/Player.js +4768 -4730
- package/src/features/PlaylistManager.js +1202 -1039
- package/src/i18n/languages/de.js +5 -1
- package/src/i18n/languages/en.js +5 -1
- package/src/i18n/languages/es.js +5 -1
- package/src/i18n/languages/fr.js +5 -1
- package/src/i18n/languages/ja.js +5 -1
- package/src/styles/vidply.css +720 -547
- package/src/utils/DOMUtils.js +67 -0
- package/src/utils/MenuUtils.js +10 -4
- package/src/utils/SettingsMenuFactory.js +8 -4
- package/src/utils/WindowComponents.js +6 -4
package/src/utils/DOMUtils.js
CHANGED
|
@@ -149,6 +149,73 @@ export const DOMUtils = {
|
|
|
149
149
|
|
|
150
150
|
temp.innerHTML = safeHtml;
|
|
151
151
|
return temp.innerHTML;
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Create a tooltip element that is aria-hidden (not read by screen readers)
|
|
156
|
+
* @param {string} text - Tooltip text
|
|
157
|
+
* @param {string} classPrefix - Class prefix for styling
|
|
158
|
+
* @returns {HTMLElement} Tooltip element
|
|
159
|
+
*/
|
|
160
|
+
createTooltip(text, classPrefix = 'vidply') {
|
|
161
|
+
const tooltip = this.createElement('span', {
|
|
162
|
+
className: `${classPrefix}-tooltip`,
|
|
163
|
+
textContent: text,
|
|
164
|
+
attributes: {
|
|
165
|
+
'aria-hidden': 'true'
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
return tooltip;
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Attach a tooltip to an element
|
|
173
|
+
* @param {HTMLElement} element - Element to attach tooltip to
|
|
174
|
+
* @param {string} text - Tooltip text
|
|
175
|
+
* @param {string} classPrefix - Class prefix for styling
|
|
176
|
+
*/
|
|
177
|
+
attachTooltip(element, text, classPrefix = 'vidply') {
|
|
178
|
+
if (!element || !text) return;
|
|
179
|
+
|
|
180
|
+
// Remove existing tooltip if any
|
|
181
|
+
const existingTooltip = element.querySelector(`.${classPrefix}-tooltip`);
|
|
182
|
+
if (existingTooltip) {
|
|
183
|
+
existingTooltip.remove();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const tooltip = this.createTooltip(text, classPrefix);
|
|
187
|
+
element.appendChild(tooltip);
|
|
188
|
+
|
|
189
|
+
// Show tooltip on hover/focus
|
|
190
|
+
const showTooltip = () => {
|
|
191
|
+
tooltip.classList.add(`${classPrefix}-tooltip-visible`);
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const hideTooltip = () => {
|
|
195
|
+
tooltip.classList.remove(`${classPrefix}-tooltip-visible`);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
element.addEventListener('mouseenter', showTooltip);
|
|
199
|
+
element.addEventListener('mouseleave', hideTooltip);
|
|
200
|
+
element.addEventListener('focus', showTooltip);
|
|
201
|
+
element.addEventListener('blur', hideTooltip);
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Create visible button text that is hidden by CSS but visible when CSS is disabled
|
|
206
|
+
* @param {string} text - Button text
|
|
207
|
+
* @param {string} classPrefix - Class prefix for styling
|
|
208
|
+
* @returns {HTMLElement} Button text element
|
|
209
|
+
*/
|
|
210
|
+
createButtonText(text, classPrefix = 'vidply') {
|
|
211
|
+
const buttonText = this.createElement('span', {
|
|
212
|
+
className: `${classPrefix}-button-text`,
|
|
213
|
+
textContent: text,
|
|
214
|
+
attributes: {
|
|
215
|
+
'aria-hidden': 'true'
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
return buttonText;
|
|
152
219
|
}
|
|
153
220
|
};
|
|
154
221
|
|
package/src/utils/MenuUtils.js
CHANGED
|
@@ -81,7 +81,8 @@ export function attachMenuKeyboardNavigation(menu, button, itemSelector, onClose
|
|
|
81
81
|
menuItems.forEach((item, idx) => {
|
|
82
82
|
item.setAttribute('tabindex', idx === nextIndex ? '0' : '-1');
|
|
83
83
|
});
|
|
84
|
-
menuItems[nextIndex].focus();
|
|
84
|
+
menuItems[nextIndex].focus({ preventScroll: false });
|
|
85
|
+
menuItems[nextIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
85
86
|
break;
|
|
86
87
|
|
|
87
88
|
case 'ArrowUp':
|
|
@@ -91,7 +92,8 @@ export function attachMenuKeyboardNavigation(menu, button, itemSelector, onClose
|
|
|
91
92
|
menuItems.forEach((item, idx) => {
|
|
92
93
|
item.setAttribute('tabindex', idx === prevIndex ? '0' : '-1');
|
|
93
94
|
});
|
|
94
|
-
menuItems[prevIndex].focus();
|
|
95
|
+
menuItems[prevIndex].focus({ preventScroll: false });
|
|
96
|
+
menuItems[prevIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
95
97
|
break;
|
|
96
98
|
|
|
97
99
|
case 'Home':
|
|
@@ -100,7 +102,8 @@ export function attachMenuKeyboardNavigation(menu, button, itemSelector, onClose
|
|
|
100
102
|
menuItems.forEach((item, idx) => {
|
|
101
103
|
item.setAttribute('tabindex', idx === 0 ? '0' : '-1');
|
|
102
104
|
});
|
|
103
|
-
menuItems[0].focus();
|
|
105
|
+
menuItems[0].focus({ preventScroll: false });
|
|
106
|
+
menuItems[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
104
107
|
break;
|
|
105
108
|
|
|
106
109
|
case 'End':
|
|
@@ -110,7 +113,8 @@ export function attachMenuKeyboardNavigation(menu, button, itemSelector, onClose
|
|
|
110
113
|
menuItems.forEach((item, idx) => {
|
|
111
114
|
item.setAttribute('tabindex', idx === lastIndex ? '0' : '-1');
|
|
112
115
|
});
|
|
113
|
-
menuItems[lastIndex].focus();
|
|
116
|
+
menuItems[lastIndex].focus({ preventScroll: false });
|
|
117
|
+
menuItems[lastIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
114
118
|
break;
|
|
115
119
|
|
|
116
120
|
case 'Enter':
|
|
@@ -159,6 +163,8 @@ export function focusFirstMenuItem(menu, itemSelector, delay = 0) {
|
|
|
159
163
|
item.setAttribute('tabindex', index === 0 ? '0' : '-1');
|
|
160
164
|
});
|
|
161
165
|
focusElement(menuItems[0], { delay: 0 });
|
|
166
|
+
// Scroll into view for keyboard users
|
|
167
|
+
menuItems[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
162
168
|
}
|
|
163
169
|
}, delay);
|
|
164
170
|
}
|
|
@@ -190,7 +190,8 @@ export function setupSettingsMenuKeyboard(menu, button, onClose) {
|
|
|
190
190
|
menuItems.forEach((item, idx) => {
|
|
191
191
|
item.setAttribute('tabindex', idx === nextIndex ? '0' : '-1');
|
|
192
192
|
});
|
|
193
|
-
menuItems[nextIndex].focus();
|
|
193
|
+
menuItems[nextIndex].focus({ preventScroll: false });
|
|
194
|
+
menuItems[nextIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
194
195
|
break;
|
|
195
196
|
|
|
196
197
|
case 'ArrowUp':
|
|
@@ -199,7 +200,8 @@ export function setupSettingsMenuKeyboard(menu, button, onClose) {
|
|
|
199
200
|
menuItems.forEach((item, idx) => {
|
|
200
201
|
item.setAttribute('tabindex', idx === prevIndex ? '0' : '-1');
|
|
201
202
|
});
|
|
202
|
-
menuItems[prevIndex].focus();
|
|
203
|
+
menuItems[prevIndex].focus({ preventScroll: false });
|
|
204
|
+
menuItems[prevIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
203
205
|
break;
|
|
204
206
|
|
|
205
207
|
case 'Home':
|
|
@@ -207,7 +209,8 @@ export function setupSettingsMenuKeyboard(menu, button, onClose) {
|
|
|
207
209
|
menuItems.forEach((item, idx) => {
|
|
208
210
|
item.setAttribute('tabindex', idx === 0 ? '0' : '-1');
|
|
209
211
|
});
|
|
210
|
-
menuItems[0].focus();
|
|
212
|
+
menuItems[0].focus({ preventScroll: false });
|
|
213
|
+
menuItems[0].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
211
214
|
break;
|
|
212
215
|
|
|
213
216
|
case 'End':
|
|
@@ -216,7 +219,8 @@ export function setupSettingsMenuKeyboard(menu, button, onClose) {
|
|
|
216
219
|
menuItems.forEach((item, idx) => {
|
|
217
220
|
item.setAttribute('tabindex', idx === lastIndex ? '0' : '-1');
|
|
218
221
|
});
|
|
219
|
-
menuItems[lastIndex].focus();
|
|
222
|
+
menuItems[lastIndex].focus({ preventScroll: false });
|
|
223
|
+
menuItems[lastIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' });
|
|
220
224
|
break;
|
|
221
225
|
|
|
222
226
|
case 'Escape':
|
|
@@ -47,15 +47,16 @@ export function createWindowHeader({
|
|
|
47
47
|
// Add settings button if requested
|
|
48
48
|
let settingsButton = null;
|
|
49
49
|
if (showSettings && onSettingsClick) {
|
|
50
|
+
const settingsAriaLabel = i18n.t('settings.title');
|
|
50
51
|
settingsButton = DOMUtils.createElement('button', {
|
|
51
52
|
className: `${classPrefix}-icon-button ${headerClass}-settings`,
|
|
52
53
|
attributes: {
|
|
53
54
|
'type': 'button',
|
|
54
|
-
'aria-label':
|
|
55
|
-
'title': i18n.t('settings.title')
|
|
55
|
+
'aria-label': settingsAriaLabel
|
|
56
56
|
}
|
|
57
57
|
});
|
|
58
58
|
settingsButton.appendChild(createIconElement('settings'));
|
|
59
|
+
DOMUtils.attachTooltip(settingsButton, settingsAriaLabel, classPrefix);
|
|
59
60
|
settingsButton.addEventListener('click', onSettingsClick);
|
|
60
61
|
leftSide.appendChild(settingsButton);
|
|
61
62
|
}
|
|
@@ -74,15 +75,16 @@ export function createWindowHeader({
|
|
|
74
75
|
leftSide.appendChild(title);
|
|
75
76
|
|
|
76
77
|
// Create close button
|
|
78
|
+
const closeAriaLabel = i18n.t('player.close');
|
|
77
79
|
const closeButton = DOMUtils.createElement('button', {
|
|
78
80
|
className: `${classPrefix}-icon-button ${headerClass}-close`,
|
|
79
81
|
attributes: {
|
|
80
82
|
'type': 'button',
|
|
81
|
-
'aria-label':
|
|
82
|
-
'title': i18n.t('player.close')
|
|
83
|
+
'aria-label': closeAriaLabel
|
|
83
84
|
}
|
|
84
85
|
});
|
|
85
86
|
closeButton.appendChild(createIconElement('close'));
|
|
87
|
+
DOMUtils.attachTooltip(closeButton, closeAriaLabel, classPrefix);
|
|
86
88
|
if (onClose) {
|
|
87
89
|
closeButton.addEventListener('click', onClose);
|
|
88
90
|
}
|