vidply 1.0.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.
@@ -0,0 +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
+
@@ -0,0 +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
+
@@ -0,0 +1,82 @@
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
+