vidply 1.0.4 → 1.0.6

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.
@@ -1,154 +1,154 @@
1
- /**
2
- * DOM manipulation utilities
3
- */
4
-
5
- export const DOMUtils = {
6
- createElement(tag, options = {}) {
7
- const element = document.createElement(tag);
8
-
9
- if (options.className) {
10
- element.className = options.className;
11
- }
12
-
13
- if (options.attributes) {
14
- Object.entries(options.attributes).forEach(([key, value]) => {
15
- element.setAttribute(key, value);
16
- });
17
- }
18
-
19
- if (options.innerHTML) {
20
- element.innerHTML = options.innerHTML;
21
- }
22
-
23
- if (options.textContent) {
24
- element.textContent = options.textContent;
25
- }
26
-
27
- if (options.style) {
28
- Object.assign(element.style, options.style);
29
- }
30
-
31
- if (options.children) {
32
- options.children.forEach(child => {
33
- if (child) element.appendChild(child);
34
- });
35
- }
36
-
37
- return element;
38
- },
39
-
40
- addClass(element, className) {
41
- if (element && className) {
42
- element.classList.add(className);
43
- }
44
- },
45
-
46
- removeClass(element, className) {
47
- if (element && className) {
48
- element.classList.remove(className);
49
- }
50
- },
51
-
52
- toggleClass(element, className) {
53
- if (element && className) {
54
- element.classList.toggle(className);
55
- }
56
- },
57
-
58
- hasClass(element, className) {
59
- return element && element.classList.contains(className);
60
- },
61
-
62
- show(element) {
63
- if (element) {
64
- element.style.display = '';
65
- }
66
- },
67
-
68
- hide(element) {
69
- if (element) {
70
- element.style.display = 'none';
71
- }
72
- },
73
-
74
- fadeIn(element, duration = 300) {
75
- if (!element) return;
76
-
77
- element.style.opacity = '0';
78
- element.style.display = '';
79
-
80
- let start = null;
81
- const animate = (timestamp) => {
82
- if (!start) start = timestamp;
83
- const progress = timestamp - start;
84
- const opacity = Math.min(progress / duration, 1);
85
-
86
- element.style.opacity = opacity;
87
-
88
- if (progress < duration) {
89
- requestAnimationFrame(animate);
90
- }
91
- };
92
-
93
- requestAnimationFrame(animate);
94
- },
95
-
96
- fadeOut(element, duration = 300) {
97
- if (!element) return;
98
-
99
- const startOpacity = parseFloat(getComputedStyle(element).opacity) || 1;
100
- let start = null;
101
-
102
- const animate = (timestamp) => {
103
- if (!start) start = timestamp;
104
- const progress = timestamp - start;
105
- const opacity = Math.max(startOpacity - (progress / duration), 0);
106
-
107
- element.style.opacity = opacity;
108
-
109
- if (progress < duration) {
110
- requestAnimationFrame(animate);
111
- } else {
112
- element.style.display = 'none';
113
- }
114
- };
115
-
116
- requestAnimationFrame(animate);
117
- },
118
-
119
- offset(element) {
120
- if (!element) return { top: 0, left: 0 };
121
-
122
- const rect = element.getBoundingClientRect();
123
- return {
124
- top: rect.top + window.pageYOffset,
125
- left: rect.left + window.pageXOffset,
126
- width: rect.width,
127
- height: rect.height
128
- };
129
- },
130
-
131
- escapeHTML(str) {
132
- const div = document.createElement('div');
133
- div.textContent = str;
134
- return div.innerHTML;
135
- },
136
-
137
- sanitizeHTML(html) {
138
- // Basic HTML sanitization - allow safe tags for VTT captions
139
- // Since we control the HTML (from VTT parsing), we can safely allow these tags
140
- const temp = document.createElement('div');
141
-
142
- // Strip out any potentially dangerous tags/attributes
143
- // Allow: strong, em, u, span, b, i with class and data-voice attributes
144
- const safeHtml = html
145
- .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
146
- .replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi, '')
147
- .replace(/on\w+\s*=/gi, '') // Remove event handlers
148
- .replace(/javascript:/gi, ''); // Remove javascript: protocol
149
-
150
- temp.innerHTML = safeHtml;
151
- return temp.innerHTML;
152
- }
153
- };
154
-
1
+ /**
2
+ * DOM manipulation utilities
3
+ */
4
+
5
+ export const DOMUtils = {
6
+ createElement(tag, options = {}) {
7
+ const element = document.createElement(tag);
8
+
9
+ if (options.className) {
10
+ element.className = options.className;
11
+ }
12
+
13
+ if (options.attributes) {
14
+ Object.entries(options.attributes).forEach(([key, value]) => {
15
+ element.setAttribute(key, value);
16
+ });
17
+ }
18
+
19
+ if (options.innerHTML) {
20
+ element.innerHTML = options.innerHTML;
21
+ }
22
+
23
+ if (options.textContent) {
24
+ element.textContent = options.textContent;
25
+ }
26
+
27
+ if (options.style) {
28
+ Object.assign(element.style, options.style);
29
+ }
30
+
31
+ if (options.children) {
32
+ options.children.forEach(child => {
33
+ if (child) element.appendChild(child);
34
+ });
35
+ }
36
+
37
+ return element;
38
+ },
39
+
40
+ addClass(element, className) {
41
+ if (element && className) {
42
+ element.classList.add(className);
43
+ }
44
+ },
45
+
46
+ removeClass(element, className) {
47
+ if (element && className) {
48
+ element.classList.remove(className);
49
+ }
50
+ },
51
+
52
+ toggleClass(element, className) {
53
+ if (element && className) {
54
+ element.classList.toggle(className);
55
+ }
56
+ },
57
+
58
+ hasClass(element, className) {
59
+ return element && element.classList.contains(className);
60
+ },
61
+
62
+ show(element) {
63
+ if (element) {
64
+ element.style.display = '';
65
+ }
66
+ },
67
+
68
+ hide(element) {
69
+ if (element) {
70
+ element.style.display = 'none';
71
+ }
72
+ },
73
+
74
+ fadeIn(element, duration = 300) {
75
+ if (!element) return;
76
+
77
+ element.style.opacity = '0';
78
+ element.style.display = '';
79
+
80
+ let start = null;
81
+ const animate = (timestamp) => {
82
+ if (!start) start = timestamp;
83
+ const progress = timestamp - start;
84
+ const opacity = Math.min(progress / duration, 1);
85
+
86
+ element.style.opacity = opacity;
87
+
88
+ if (progress < duration) {
89
+ requestAnimationFrame(animate);
90
+ }
91
+ };
92
+
93
+ requestAnimationFrame(animate);
94
+ },
95
+
96
+ fadeOut(element, duration = 300) {
97
+ if (!element) return;
98
+
99
+ const startOpacity = parseFloat(getComputedStyle(element).opacity) || 1;
100
+ let start = null;
101
+
102
+ const animate = (timestamp) => {
103
+ if (!start) start = timestamp;
104
+ const progress = timestamp - start;
105
+ const opacity = Math.max(startOpacity - (progress / duration), 0);
106
+
107
+ element.style.opacity = opacity;
108
+
109
+ if (progress < duration) {
110
+ requestAnimationFrame(animate);
111
+ } else {
112
+ element.style.display = 'none';
113
+ }
114
+ };
115
+
116
+ requestAnimationFrame(animate);
117
+ },
118
+
119
+ offset(element) {
120
+ if (!element) return { top: 0, left: 0 };
121
+
122
+ const rect = element.getBoundingClientRect();
123
+ return {
124
+ top: rect.top + window.pageYOffset,
125
+ left: rect.left + window.pageXOffset,
126
+ width: rect.width,
127
+ height: rect.height
128
+ };
129
+ },
130
+
131
+ escapeHTML(str) {
132
+ const div = document.createElement('div');
133
+ div.textContent = str;
134
+ return div.innerHTML;
135
+ },
136
+
137
+ sanitizeHTML(html) {
138
+ // Basic HTML sanitization - allow safe tags for VTT captions
139
+ // Since we control the HTML (from VTT parsing), we can safely allow these tags
140
+ const temp = document.createElement('div');
141
+
142
+ // Strip out any potentially dangerous tags/attributes
143
+ // Allow: strong, em, u, span, b, i with class and data-voice attributes
144
+ const safeHtml = html
145
+ .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
146
+ .replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi, '')
147
+ .replace(/on\w+\s*=/gi, '') // Remove event handlers
148
+ .replace(/javascript:/gi, ''); // Remove javascript: protocol
149
+
150
+ temp.innerHTML = safeHtml;
151
+ return temp.innerHTML;
152
+ }
153
+ };
154
+
@@ -1,53 +1,53 @@
1
- /**
2
- * Simple EventEmitter implementation
3
- */
4
-
5
- export class EventEmitter {
6
- constructor() {
7
- this.events = {};
8
- }
9
-
10
- on(event, listener) {
11
- if (!this.events[event]) {
12
- this.events[event] = [];
13
- }
14
- this.events[event].push(listener);
15
- return this;
16
- }
17
-
18
- once(event, listener) {
19
- const onceListener = (...args) => {
20
- listener(...args);
21
- this.off(event, onceListener);
22
- };
23
- return this.on(event, onceListener);
24
- }
25
-
26
- off(event, listener) {
27
- if (!this.events[event]) return this;
28
-
29
- if (!listener) {
30
- delete this.events[event];
31
- } else {
32
- this.events[event] = this.events[event].filter(l => l !== listener);
33
- }
34
-
35
- return this;
36
- }
37
-
38
- emit(event, ...args) {
39
- if (!this.events[event]) return this;
40
-
41
- this.events[event].forEach(listener => {
42
- listener(...args);
43
- });
44
-
45
- return this;
46
- }
47
-
48
- removeAllListeners() {
49
- this.events = {};
50
- return this;
51
- }
52
- }
53
-
1
+ /**
2
+ * Simple EventEmitter implementation
3
+ */
4
+
5
+ export class EventEmitter {
6
+ constructor() {
7
+ this.events = {};
8
+ }
9
+
10
+ on(event, listener) {
11
+ if (!this.events[event]) {
12
+ this.events[event] = [];
13
+ }
14
+ this.events[event].push(listener);
15
+ return this;
16
+ }
17
+
18
+ once(event, listener) {
19
+ const onceListener = (...args) => {
20
+ listener(...args);
21
+ this.off(event, onceListener);
22
+ };
23
+ return this.on(event, onceListener);
24
+ }
25
+
26
+ off(event, listener) {
27
+ if (!this.events[event]) return this;
28
+
29
+ if (!listener) {
30
+ delete this.events[event];
31
+ } else {
32
+ this.events[event] = this.events[event].filter(l => l !== listener);
33
+ }
34
+
35
+ return this;
36
+ }
37
+
38
+ emit(event, ...args) {
39
+ if (!this.events[event]) return this;
40
+
41
+ this.events[event].forEach(listener => {
42
+ listener(...args);
43
+ });
44
+
45
+ return this;
46
+ }
47
+
48
+ removeAllListeners() {
49
+ this.events = {};
50
+ return this;
51
+ }
52
+ }
53
+
@@ -1,82 +1,87 @@
1
- /**
2
- * Time formatting and conversion utilities
3
- */
4
-
5
- export const TimeUtils = {
6
- /**
7
- * Format seconds to time string (HH:MM:SS or MM:SS)
8
- */
9
- formatTime(seconds, alwaysShowHours = false) {
10
- if (!isFinite(seconds) || seconds < 0) {
11
- return alwaysShowHours ? '00:00:00' : '00:00';
12
- }
13
-
14
- const hours = Math.floor(seconds / 3600);
15
- const minutes = Math.floor((seconds % 3600) / 60);
16
- const secs = Math.floor(seconds % 60);
17
-
18
- const pad = (num) => String(num).padStart(2, '0');
19
-
20
- if (hours > 0 || alwaysShowHours) {
21
- return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;
22
- }
23
-
24
- return `${pad(minutes)}:${pad(secs)}`;
25
- },
26
-
27
- /**
28
- * Parse time string to seconds
29
- */
30
- parseTime(timeString) {
31
- const parts = timeString.split(':').map(p => parseInt(p, 10));
32
-
33
- if (parts.length === 3) {
34
- // HH:MM:SS
35
- return parts[0] * 3600 + parts[1] * 60 + parts[2];
36
- } else if (parts.length === 2) {
37
- // MM:SS
38
- return parts[0] * 60 + parts[1];
39
- } else if (parts.length === 1) {
40
- // SS
41
- return parts[0];
42
- }
43
-
44
- return 0;
45
- },
46
-
47
- /**
48
- * Format seconds to readable duration
49
- */
50
- formatDuration(seconds) {
51
- if (!isFinite(seconds) || seconds < 0) {
52
- return '0 seconds';
53
- }
54
-
55
- const hours = Math.floor(seconds / 3600);
56
- const minutes = Math.floor((seconds % 3600) / 60);
57
- const secs = Math.floor(seconds % 60);
58
-
59
- const parts = [];
60
-
61
- if (hours > 0) {
62
- parts.push(`${hours} hour${hours !== 1 ? 's' : ''}`);
63
- }
64
- if (minutes > 0) {
65
- parts.push(`${minutes} minute${minutes !== 1 ? 's' : ''}`);
66
- }
67
- if (secs > 0 || parts.length === 0) {
68
- parts.push(`${secs} second${secs !== 1 ? 's' : ''}`);
69
- }
70
-
71
- return parts.join(', ');
72
- },
73
-
74
- /**
75
- * Format percentage
76
- */
77
- formatPercentage(value, total) {
78
- if (total === 0) return 0;
79
- return Math.round((value / total) * 100);
80
- }
81
- };
82
-
1
+ /**
2
+ * Time formatting and conversion utilities
3
+ */
4
+
5
+ import {i18n} from '../i18n/i18n.js';
6
+
7
+ export const TimeUtils = {
8
+ /**
9
+ * Format seconds to time string (HH:MM:SS or MM:SS)
10
+ */
11
+ formatTime(seconds, alwaysShowHours = false) {
12
+ if (!isFinite(seconds) || seconds < 0) {
13
+ return alwaysShowHours ? '00:00:00' : '00:00';
14
+ }
15
+
16
+ const hours = Math.floor(seconds / 3600);
17
+ const minutes = Math.floor((seconds % 3600) / 60);
18
+ const secs = Math.floor(seconds % 60);
19
+
20
+ const pad = (num) => String(num).padStart(2, '0');
21
+
22
+ if (hours > 0 || alwaysShowHours) {
23
+ return `${pad(hours)}:${pad(minutes)}:${pad(secs)}`;
24
+ }
25
+
26
+ return `${pad(minutes)}:${pad(secs)}`;
27
+ },
28
+
29
+ /**
30
+ * Parse time string to seconds
31
+ */
32
+ parseTime(timeString) {
33
+ const parts = timeString.split(':').map(p => parseInt(p, 10));
34
+
35
+ if (parts.length === 3) {
36
+ // HH:MM:SS
37
+ return parts[0] * 3600 + parts[1] * 60 + parts[2];
38
+ } else if (parts.length === 2) {
39
+ // MM:SS
40
+ return parts[0] * 60 + parts[1];
41
+ } else if (parts.length === 1) {
42
+ // SS
43
+ return parts[0];
44
+ }
45
+
46
+ return 0;
47
+ },
48
+
49
+ /**
50
+ * Format seconds to readable duration
51
+ */
52
+ formatDuration(seconds) {
53
+ if (!isFinite(seconds) || seconds < 0) {
54
+ return i18n.t('time.seconds', { count: 0 });
55
+ }
56
+
57
+ const hours = Math.floor(seconds / 3600);
58
+ const minutes = Math.floor((seconds % 3600) / 60);
59
+ const secs = Math.floor(seconds % 60);
60
+
61
+ const parts = [];
62
+
63
+ if (hours > 0) {
64
+ const key = hours === 1 ? 'time.hour' : 'time.hours';
65
+ parts.push(i18n.t(key, { count: hours }));
66
+ }
67
+ if (minutes > 0) {
68
+ const key = minutes === 1 ? 'time.minute' : 'time.minutes';
69
+ parts.push(i18n.t(key, { count: minutes }));
70
+ }
71
+ if (secs > 0 || parts.length === 0) {
72
+ const key = secs === 1 ? 'time.second' : 'time.seconds';
73
+ parts.push(i18n.t(key, { count: secs }));
74
+ }
75
+
76
+ return parts.join(', ');
77
+ },
78
+
79
+ /**
80
+ * Format percentage
81
+ */
82
+ formatPercentage(value, total) {
83
+ if (total === 0) return 0;
84
+ return Math.round((value / total) * 100);
85
+ }
86
+ };
87
+