smsmslib 1.0.40 → 1.0.42
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/javascr/av_controller/AvControllerState_t.js +66 -0
- package/javascr/av_controller/HtmlControl_t.js +56 -0
- package/javascr/av_controller/HtmlMedia_t.js +515 -0
- package/javascr/av_controller/HtmlPlay_t.js +231 -0
- package/javascr/av_controller/HtmlSkipForward_t.js +99 -0
- package/javascr/av_controller/HtmlSkipRewind_t.js +99 -0
- package/javascr/av_controller/HtmlTimerBar_t.js +175 -0
- package/javascr/av_controller/HtmlTimerDigit_t.js +143 -0
- package/javascr/av_controller/HtmlTimerFrame_t.js +75 -0
- package/javascr/av_controller/av_controller.js +195 -0
- package/javascr/av_controller/index.js +19 -0
- package/javascr/index.js +10 -0
- package/javascr/system/App_t.js +124 -0
- package/javascr/system/HtmlElement_t.js +203 -0
- package/javascr/system/Observer_t.js +78 -0
- package/javascr/system/SubjectSet_t.js +187 -0
- package/javascr/system/Subject_t.js +349 -0
- package/javascr/system/array.js +102 -0
- package/javascr/system/arrayapp.js +223 -0
- package/javascr/system/dataset.js +214 -0
- package/javascr/system/document.js +76 -0
- package/javascr/system/error.js +5 -0
- package/javascr/system/html.js +38 -0
- package/javascr/system/index.js +22 -0
- package/javascr/system/prop.js +278 -0
- package/javascr/system/type.js +227 -0
- package/package.json +5 -1
- package/mdcat.mk +0 -30
- package/npm_access_token.txt +0 -1
- package/npm_recovery_codes.txt +0 -5
- package/publish.sh +0 -10
- package/tags_JavaScript +0 -50
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
* Implementation of the AvControllerState_t class.
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* This module defines the data structure representing the playback state
|
|
7
|
+
* of an AV controller. It encapsulates essential properties from the
|
|
8
|
+
* HTMLMediaElement to be used as the shared state within the Observer
|
|
9
|
+
* pattern, facilitating synchronization between the media element and
|
|
10
|
+
* its associated UI components.
|
|
11
|
+
*
|
|
12
|
+
* @module src/av_controller/AvControllerState_t
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Av controller status.
|
|
18
|
+
*/
|
|
19
|
+
export class AvControllerState_t
|
|
20
|
+
{
|
|
21
|
+
/** The initial start time of the media in seconds. */
|
|
22
|
+
d_start_sec;
|
|
23
|
+
|
|
24
|
+
/** The initial end time of the media in seconds.
|
|
25
|
+
* A negative value indicates that the end time is invalid or indefinite
|
|
26
|
+
* (e.g., live streaming).
|
|
27
|
+
*/
|
|
28
|
+
d_end_sec;
|
|
29
|
+
|
|
30
|
+
/** The total duration of the media in seconds.
|
|
31
|
+
* A negative value indicates that the duration is unavailable or infinite.
|
|
32
|
+
*/
|
|
33
|
+
duration;
|
|
34
|
+
|
|
35
|
+
/** HTMLMediaElement.paused (Read only)
|
|
36
|
+
* A boolean that indicates whether the media element is paused. */
|
|
37
|
+
paused;
|
|
38
|
+
|
|
39
|
+
/** HTMLMediaElement.playbackRate
|
|
40
|
+
* A double that indicates the rate at which the media is being played back. */
|
|
41
|
+
playbackRate;
|
|
42
|
+
|
|
43
|
+
/** HTMLMediaElement.currentTime
|
|
44
|
+
* A double-precision floating-point value indicating the current playback
|
|
45
|
+
* time in seconds. */
|
|
46
|
+
currentTime;
|
|
47
|
+
|
|
48
|
+
/** Element.clientWidth (of the outer container)
|
|
49
|
+
* The maximum width of the progress bar background in pixels.
|
|
50
|
+
* This represents the total length of the seek bar. */
|
|
51
|
+
i_bar_px_max;
|
|
52
|
+
|
|
53
|
+
constructor()
|
|
54
|
+
{
|
|
55
|
+
this.d_start_sec = 0.0;
|
|
56
|
+
this.d_end_sec = 10.0;
|
|
57
|
+
this.duration = 10.0;
|
|
58
|
+
this.paused = true;
|
|
59
|
+
this.playbackRate = 1.0;
|
|
60
|
+
this.currentTime = this.d_start_sec;
|
|
61
|
+
this.i_bar_px_max = 10;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
* Implementation of the HtmlControl_t class.
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* This module provides the HtmlControl_t class, which manages the
|
|
7
|
+
* visibility of the AV custom control container. It acts as an
|
|
8
|
+
* observer linked to a specific DOM element and
|
|
9
|
+
* ensures the UI is revealed only when the media state is initialized.
|
|
10
|
+
*
|
|
11
|
+
* @module src/HtmlControl_t
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
/** ---------------------------------------------------------------------------
|
|
16
|
+
* Imports.
|
|
17
|
+
* --------------------------------------------------------------------------- */
|
|
18
|
+
|
|
19
|
+
import {HtmlElement_t} from "../system/index.js";
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
/** ---------------------------------------------------------------------------
|
|
23
|
+
* Class.
|
|
24
|
+
* --------------------------------------------------------------------------- */
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Manages the visibility and lifecycle of the custom AV control interface.
|
|
28
|
+
*
|
|
29
|
+
* This class serves as the container for custom playback UI elements.
|
|
30
|
+
*/
|
|
31
|
+
export class HtmlControl_t extends HtmlElement_t
|
|
32
|
+
{
|
|
33
|
+
/**
|
|
34
|
+
* @see HtmlElement_t#constructor
|
|
35
|
+
*/
|
|
36
|
+
constructor(s_selector)
|
|
37
|
+
{
|
|
38
|
+
super(s_selector);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Synchronizes the initial state to display the custom controls.
|
|
43
|
+
*
|
|
44
|
+
* @param {AvControllerState_t} o_state [in]
|
|
45
|
+
* The initial data state provided by the subject.
|
|
46
|
+
*
|
|
47
|
+
* @see Observer_t#handle_initial_update
|
|
48
|
+
*/
|
|
49
|
+
handle_initial_update(o_state)
|
|
50
|
+
{
|
|
51
|
+
this._o_element.style.visibility = "visible"; /* Show custom UI for playback. */
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file
|
|
3
|
+
* Implementation of the HtmlMedia_t class and its associated helper functions.
|
|
4
|
+
*
|
|
5
|
+
* @description
|
|
6
|
+
* This module provides the HtmlMedia_t class, which serves as a specialized
|
|
7
|
+
* observer for HTMLMediaElements (e.g., <video> or <audio>). It facilitates
|
|
8
|
+
* bidirectional synchronization:
|
|
9
|
+
*
|
|
10
|
+
* @module src/av_controller/HtmlMedia_t
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
/** ---------------------------------------------------------------------------
|
|
14
|
+
* Imports.
|
|
15
|
+
* --------------------------------------------------------------------------- */
|
|
16
|
+
|
|
17
|
+
import
|
|
18
|
+
{
|
|
19
|
+
sj_is_number,
|
|
20
|
+
sj_is_object,
|
|
21
|
+
sj_prop_chg_own,
|
|
22
|
+
HtmlElement_t,
|
|
23
|
+
sj_element_key_get,
|
|
24
|
+
sj_Subject_get,
|
|
25
|
+
Subject_t
|
|
26
|
+
}
|
|
27
|
+
from "../system/index.js";
|
|
28
|
+
|
|
29
|
+
import {AvControllerState_t} from "./AvControllerState_t.js"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
/** ---------------------------------------------------------------------------
|
|
33
|
+
* Class.
|
|
34
|
+
* --------------------------------------------------------------------------- */
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Synchronizes a media element (e.g., <video> or <audio>) with the application
|
|
38
|
+
* state.
|
|
39
|
+
*
|
|
40
|
+
* @extends HtmlElement_t
|
|
41
|
+
*/
|
|
42
|
+
export class HtmlMedia_t extends HtmlElement_t
|
|
43
|
+
{
|
|
44
|
+
/**
|
|
45
|
+
* @see HtmlElement_t#constructor
|
|
46
|
+
*/
|
|
47
|
+
constructor(s_selector)
|
|
48
|
+
{
|
|
49
|
+
super(s_selector);
|
|
50
|
+
|
|
51
|
+
const b_valid = this.is_valid();
|
|
52
|
+
|
|
53
|
+
if (b_valid)
|
|
54
|
+
{
|
|
55
|
+
const o_element = this._o_element;
|
|
56
|
+
|
|
57
|
+
o_element.addEventListener("durationchange", HtmlMedia_on_durationchange);
|
|
58
|
+
o_element.addEventListener("timeupdate" , HtmlMedia_on_timeupdate);
|
|
59
|
+
o_element.addEventListener("ended" , HtmlMedia_on_ended);
|
|
60
|
+
o_element.addEventListener("loadedmetadata", HtmlMedia_on_loadedmetadata);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* @see HtmlMedia_loadedmetadata_manual
|
|
66
|
+
*/
|
|
67
|
+
loadedmetadata_manual()
|
|
68
|
+
{
|
|
69
|
+
const i_exe = HtmlMedia_loadedmetadata_manual(this._o_element);
|
|
70
|
+
|
|
71
|
+
return i_exe;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @see Observer_t#handle_retrieve
|
|
76
|
+
* @see HtmlMedia_handle_retrieve
|
|
77
|
+
*/
|
|
78
|
+
handle_retrieve(o_state)
|
|
79
|
+
{
|
|
80
|
+
HtmlMedia_handle_retrieve(this._o_element, o_state);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @see Observer_t#handle_initial_update
|
|
85
|
+
* @see HtmlMedia_handle_initial_update
|
|
86
|
+
*/
|
|
87
|
+
handle_initial_update(o_state)
|
|
88
|
+
{
|
|
89
|
+
HtmlMedia_handle_initial_update(this._o_element, o_state)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @see Observer_t#handle_update
|
|
94
|
+
* @see HtmlMedia_handle_update
|
|
95
|
+
*/
|
|
96
|
+
handle_update(o_state, o_chg, o_src)
|
|
97
|
+
{
|
|
98
|
+
HtmlMedia_handle_update(this._o_element, o_state, o_chg, o_src);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
/** ---------------------------------------------------------------------------
|
|
105
|
+
* Functions.
|
|
106
|
+
* --------------------------------------------------------------------------- */
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Event handler for the media element's 'loadedmetadata' event.
|
|
110
|
+
*
|
|
111
|
+
* @param {Event} o_event [in]
|
|
112
|
+
* The event object dispatched by the media element.
|
|
113
|
+
*
|
|
114
|
+
* @see HtmlMedia_loadedmetadata
|
|
115
|
+
*/
|
|
116
|
+
function HtmlMedia_on_loadedmetadata(o_event)
|
|
117
|
+
{
|
|
118
|
+
HtmlMedia_loadedmetadata(o_event.currentTarget);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Event handler for the media element's 'timeupdate' event.
|
|
124
|
+
*
|
|
125
|
+
* This function synchronizes the current playback time of the media element
|
|
126
|
+
* with the application state.
|
|
127
|
+
*
|
|
128
|
+
* @param {Event} o_event [in]
|
|
129
|
+
* The event object dispatched by the media element.
|
|
130
|
+
*/
|
|
131
|
+
function HtmlMedia_on_timeupdate(o_event)
|
|
132
|
+
{
|
|
133
|
+
const o_element = o_event.currentTarget;
|
|
134
|
+
const s_key = sj_element_key_get(o_element);
|
|
135
|
+
const o_Subject = sj_Subject_get(s_key);
|
|
136
|
+
let o_state = undefined;
|
|
137
|
+
|
|
138
|
+
if (o_Subject instanceof Subject_t)
|
|
139
|
+
{
|
|
140
|
+
o_state = o_Subject.data_get();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (o_state instanceof AvControllerState_t)
|
|
144
|
+
{
|
|
145
|
+
const d_start_sec = HtmlMedia_start_sec(o_element);
|
|
146
|
+
const d_end_sec = HtmlMedia_end_sec(o_element);
|
|
147
|
+
const o_chg = {};
|
|
148
|
+
|
|
149
|
+
sj_prop_chg_own(o_state, "currentTime", o_element.currentTime, o_chg);
|
|
150
|
+
sj_prop_chg_own(o_state, "d_start_sec", d_start_sec , o_chg);
|
|
151
|
+
sj_prop_chg_own(o_state, "d_end_sec" , d_end_sec , o_chg);
|
|
152
|
+
|
|
153
|
+
if (0 < Object.keys(o_chg).length)
|
|
154
|
+
{
|
|
155
|
+
o_Subject.observer_update(o_chg, o_element);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Handles the 'ended' event of the media element.
|
|
163
|
+
* This handler synchronizes the application state when the media reaches the end.
|
|
164
|
+
* Since browsers automatically pause the video/audio element when it finishes,
|
|
165
|
+
* this function explicitly updates the `paused` state to `true` in the subject's
|
|
166
|
+
* data to ensure consistency between the UI and the media element.
|
|
167
|
+
*
|
|
168
|
+
* @param {Event} o_event [in]
|
|
169
|
+
* The event object dispatched by the media element (HTMLMediaElement).
|
|
170
|
+
*/
|
|
171
|
+
function HtmlMedia_on_ended(o_event)
|
|
172
|
+
{
|
|
173
|
+
const o_element = o_event.currentTarget;
|
|
174
|
+
const s_key = sj_element_key_get(o_element);
|
|
175
|
+
const o_Subject = sj_Subject_get(s_key);
|
|
176
|
+
let o_state = undefined;
|
|
177
|
+
|
|
178
|
+
if (o_Subject instanceof Subject_t)
|
|
179
|
+
{
|
|
180
|
+
o_state = o_Subject.data_get();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (o_state instanceof AvControllerState_t)
|
|
184
|
+
{
|
|
185
|
+
const o_chg = {};
|
|
186
|
+
|
|
187
|
+
sj_prop_chg_own(o_state, "paused", true, o_chg);
|
|
188
|
+
|
|
189
|
+
if (0 < Object.keys(o_chg).length)
|
|
190
|
+
{
|
|
191
|
+
o_Subject.observer_update(o_chg, o_element);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Handles the 'durationchange' event for an HTML media element.
|
|
199
|
+
*
|
|
200
|
+
* @description
|
|
201
|
+
* This event handler synchronizes the state of an `AvControllerState_t` object with
|
|
202
|
+
* the updated timing information of the media element.
|
|
203
|
+
*
|
|
204
|
+
* @param {Event} o_event [in]
|
|
205
|
+
* The 'durationchange' event object. `o_event.currentTarget` is expected to be
|
|
206
|
+
* an `HTMLMediaElement`.
|
|
207
|
+
*
|
|
208
|
+
* @returns {void}
|
|
209
|
+
*/
|
|
210
|
+
function HtmlMedia_on_durationchange(o_event)
|
|
211
|
+
{
|
|
212
|
+
const o_element = o_event.currentTarget;
|
|
213
|
+
const s_key = sj_element_key_get(o_element);
|
|
214
|
+
const o_Subject = sj_Subject_get(s_key);
|
|
215
|
+
let o_state = undefined;
|
|
216
|
+
|
|
217
|
+
if (o_Subject instanceof Subject_t)
|
|
218
|
+
{
|
|
219
|
+
o_state = o_Subject.data_get();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (o_state instanceof AvControllerState_t)
|
|
223
|
+
{
|
|
224
|
+
const duration = HtmlMedia_duration(o_element);
|
|
225
|
+
const d_start_sec = HtmlMedia_start_sec(o_element);
|
|
226
|
+
const d_end_sec = HtmlMedia_end_sec(o_element);
|
|
227
|
+
const o_chg = {};
|
|
228
|
+
|
|
229
|
+
sj_prop_chg_own(o_state, "duration" , duration , o_chg);
|
|
230
|
+
sj_prop_chg_own(o_state, "d_start_sec", d_start_sec, o_chg);
|
|
231
|
+
sj_prop_chg_own(o_state, "d_end_sec" , d_end_sec , o_chg);
|
|
232
|
+
|
|
233
|
+
if (0 < Object.keys(o_chg).length)
|
|
234
|
+
{
|
|
235
|
+
o_Subject.observer_update(o_chg, o_element);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Retrieves the initial timing information from the media element.
|
|
243
|
+
*
|
|
244
|
+
* @param {HTMLMediaElement} o_element [in]
|
|
245
|
+
* The source media element to read timing data from.
|
|
246
|
+
*
|
|
247
|
+
* @param {AvControllerState_t} o_state [out]
|
|
248
|
+
* The state object to be populated with the retrieved timing values.
|
|
249
|
+
*/
|
|
250
|
+
function HtmlMedia_handle_retrieve(o_element, o_state)
|
|
251
|
+
{
|
|
252
|
+
if (o_element && (o_state instanceof AvControllerState_t))
|
|
253
|
+
{
|
|
254
|
+
o_state.duration = HtmlMedia_duration(o_element);
|
|
255
|
+
o_state.d_start_sec = HtmlMedia_start_sec(o_element);
|
|
256
|
+
o_state.d_end_sec = HtmlMedia_end_sec(o_element);
|
|
257
|
+
o_state.currentTime = o_state.d_start_sec;
|
|
258
|
+
o_state.playbackRate = 1.0;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Performs the initial setup and state synchronization for the media element.
|
|
265
|
+
*
|
|
266
|
+
* @param {HTMLMediaElement} o_element [in/out]
|
|
267
|
+
* The target media element to be initialized.
|
|
268
|
+
*
|
|
269
|
+
* @param {AvControllerState_t} o_state [in]
|
|
270
|
+
* The initial state object containing the desired playback configuration.
|
|
271
|
+
*/
|
|
272
|
+
function HtmlMedia_handle_initial_update(o_element, o_state)
|
|
273
|
+
{
|
|
274
|
+
if (o_element && (o_state instanceof AvControllerState_t))
|
|
275
|
+
{
|
|
276
|
+
o_element.removeAttribute("controls"); /* Hide default UI for playback */
|
|
277
|
+
|
|
278
|
+
if (o_state.paused)
|
|
279
|
+
{
|
|
280
|
+
o_element.pause();
|
|
281
|
+
}
|
|
282
|
+
else
|
|
283
|
+
{
|
|
284
|
+
o_element.play();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
o_element.playbackRate = o_state.playbackRate;
|
|
288
|
+
o_element.currentTime = o_state.d_start_sec;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Synchronizes the media element's playback state and rate based on state changes.
|
|
295
|
+
*
|
|
296
|
+
* @param {HTMLMediaElement} o_element [in/out]
|
|
297
|
+
* The target media element (video or audio) to be controlled.
|
|
298
|
+
*
|
|
299
|
+
* @param {AvControllerState_t} o_state [in]
|
|
300
|
+
* The current state of the AV controller.
|
|
301
|
+
*
|
|
302
|
+
* @param {Object} o_chg [in]
|
|
303
|
+
* An object containing only the properties that have changed since the last update.
|
|
304
|
+
* If a property is undefined here, no action is taken for that property.
|
|
305
|
+
*
|
|
306
|
+
* @param {Object} [o_src] [in]
|
|
307
|
+
* The object that originally triggered the update.
|
|
308
|
+
*/
|
|
309
|
+
function HtmlMedia_handle_update(o_element, o_state, o_chg, o_src)
|
|
310
|
+
{
|
|
311
|
+
const b_chg_obj = sj_is_object(o_chg);
|
|
312
|
+
|
|
313
|
+
if (o_element && (o_state instanceof AvControllerState_t) && b_chg_obj)
|
|
314
|
+
{
|
|
315
|
+
const b_self_update = Object.is(o_element, o_src);
|
|
316
|
+
|
|
317
|
+
if ("paused" in o_chg)
|
|
318
|
+
{
|
|
319
|
+
if (o_state.paused)
|
|
320
|
+
{
|
|
321
|
+
o_element.pause();
|
|
322
|
+
}
|
|
323
|
+
else
|
|
324
|
+
{
|
|
325
|
+
o_element.play();
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if ("playbackRate" in o_chg)
|
|
330
|
+
{
|
|
331
|
+
o_element.playbackRate = o_state.playbackRate;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if ((!b_self_update) && ("currentTime" in o_chg))
|
|
335
|
+
{
|
|
336
|
+
o_element.currentTime = o_state.currentTime;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Manually triggers the metadata loading logic if the media element is already
|
|
344
|
+
* initialized.
|
|
345
|
+
*
|
|
346
|
+
* This function checks the 'readyState' of the media element. If the metadata has
|
|
347
|
+
* already been loaded (i.e., readyState > HAVE_NOTHING), it manually invokes
|
|
348
|
+
* the 'HtmlMedia_loadedmetadata' handler to ensure state synchronization.
|
|
349
|
+
* This prevents initialization failures when the browser loads media before
|
|
350
|
+
* event listeners are attached.
|
|
351
|
+
*
|
|
352
|
+
* @param {HTMLMediaElement} o_element [in]
|
|
353
|
+
* The media element to check.
|
|
354
|
+
*
|
|
355
|
+
* @returns {number}
|
|
356
|
+
* 1 : Success. Metadata was already available, and the handler was executed.
|
|
357
|
+
* 0 : Pending. Metadata is not yet available; the system must wait for the event.
|
|
358
|
+
* -1 : Error. The provided element is invalid.
|
|
359
|
+
*/
|
|
360
|
+
function HtmlMedia_loadedmetadata_manual(o_element)
|
|
361
|
+
{
|
|
362
|
+
let i_exe = - 1;
|
|
363
|
+
|
|
364
|
+
if (o_element)
|
|
365
|
+
{
|
|
366
|
+
if (HTMLMediaElement.HAVE_NOTHING < o_element.readyState)
|
|
367
|
+
{
|
|
368
|
+
HtmlMedia_loadedmetadata(o_element);
|
|
369
|
+
i_exe = 1;
|
|
370
|
+
}
|
|
371
|
+
else
|
|
372
|
+
{
|
|
373
|
+
i_exe = 0;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
return i_exe;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Synchronizes the subject state and notifies observers when media metadata is loaded.
|
|
383
|
+
*
|
|
384
|
+
* This function acts as the core initialization logic for media-related state.
|
|
385
|
+
* It retrieves the current properties (e.g., duration, seekable ranges) from the
|
|
386
|
+
* media element to populate the Subject's data, and then triggers an initial
|
|
387
|
+
* update to synchronize all registered observers with this state.
|
|
388
|
+
*
|
|
389
|
+
* @param {HTMLMediaElement} o_element [in]
|
|
390
|
+
* The HTML media element (video or audio) that has loaded its metadata.
|
|
391
|
+
*/
|
|
392
|
+
function HtmlMedia_loadedmetadata(o_element)
|
|
393
|
+
{
|
|
394
|
+
const s_key = sj_element_key_get(o_element);
|
|
395
|
+
const o_Subject = sj_Subject_get(s_key);
|
|
396
|
+
|
|
397
|
+
if (o_Subject instanceof Subject_t)
|
|
398
|
+
{
|
|
399
|
+
o_Subject.observer_retrieve();
|
|
400
|
+
o_Subject.observer_initial_update();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Retrieves the starting time (in seconds) of the first seekable range of a media
|
|
407
|
+
* element.
|
|
408
|
+
*
|
|
409
|
+
* @description
|
|
410
|
+
* This function checks the `seekable` property of the provided HTMLMediaElement.
|
|
411
|
+
* If at least one seekable range exists and contains a valid finite number,
|
|
412
|
+
* it returns the start time of the first range. Otherwise, it defaults to 0.
|
|
413
|
+
* This ensures a safe numeric fallback even if the media is in an unstable
|
|
414
|
+
* state or is a live stream where the start point has shifted.
|
|
415
|
+
*
|
|
416
|
+
* @param {HTMLMediaElement} o_element [in]
|
|
417
|
+
* The HTML media element (e.g., <video> or <audio>) to check.
|
|
418
|
+
*
|
|
419
|
+
* @returns {number}
|
|
420
|
+
* The start time of the first seekable range in seconds, or 0 if no range
|
|
421
|
+
* is available or the value is non-finite (Infinity/NaN).
|
|
422
|
+
*/
|
|
423
|
+
function HtmlMedia_start_sec(o_element)
|
|
424
|
+
{
|
|
425
|
+
let d_start_sec;
|
|
426
|
+
|
|
427
|
+
if (0 < o_element.seekable.length)
|
|
428
|
+
{
|
|
429
|
+
d_start_sec = o_element.seekable.start(0);
|
|
430
|
+
|
|
431
|
+
const b_num = sj_is_number(d_start_sec);
|
|
432
|
+
|
|
433
|
+
if (!b_num)
|
|
434
|
+
{
|
|
435
|
+
d_start_sec = 0
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
else
|
|
439
|
+
{
|
|
440
|
+
d_start_sec = 0;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
return d_start_sec;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Retrieves the ending time (in seconds) of the last seekable range of a media element.
|
|
449
|
+
*
|
|
450
|
+
* @description
|
|
451
|
+
* This function determines the effectively playable end point of the media.
|
|
452
|
+
* If seekable time ranges are available, it returns the end time of the very last range.
|
|
453
|
+
* If the duration is indefinite (Infinity), such as in live streams, it returns -1.
|
|
454
|
+
*
|
|
455
|
+
* @param {HTMLMediaElement} o_element [in]
|
|
456
|
+
* The HTML media element (e.g., <video> or <audio>) to inspect.
|
|
457
|
+
*
|
|
458
|
+
* @returns {number}
|
|
459
|
+
* The end time in seconds, or -1 if the duration is infinite/indefinite.
|
|
460
|
+
*/
|
|
461
|
+
function HtmlMedia_end_sec(o_element)
|
|
462
|
+
{
|
|
463
|
+
let d_end_sec;
|
|
464
|
+
|
|
465
|
+
if (0 < o_element.seekable.length)
|
|
466
|
+
{
|
|
467
|
+
d_end_sec = o_element.seekable.end(o_element.seekable.length - 1);
|
|
468
|
+
|
|
469
|
+
const b_num = sj_is_number(d_end_sec);
|
|
470
|
+
|
|
471
|
+
if (!b_num)
|
|
472
|
+
{
|
|
473
|
+
d_end_sec = - 1.0;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
else
|
|
477
|
+
{
|
|
478
|
+
d_end_sec = HtmlMedia_duration(o_element);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return d_end_sec;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* Retrieves the duration of the media element in seconds.
|
|
487
|
+
*
|
|
488
|
+
* @description
|
|
489
|
+
* This function returns the total length of the media. If the duration is
|
|
490
|
+
* unavailable (NaN) or represents an infinite stream (Infinity), such as
|
|
491
|
+
* a live broadcast, it returns -1 to indicate an indefinite duration.
|
|
492
|
+
* This ensures the returned value is always a finite number, making it
|
|
493
|
+
* safe for serialization and consistent state management.
|
|
494
|
+
*
|
|
495
|
+
* @param {HTMLMediaElement} o_element [in]
|
|
496
|
+
* The HTML media element to inspect.
|
|
497
|
+
*
|
|
498
|
+
* @returns {number}
|
|
499
|
+
* The duration in seconds, or -1 if the duration is infinite or unavailable.
|
|
500
|
+
*/
|
|
501
|
+
function HtmlMedia_duration(o_element)
|
|
502
|
+
{
|
|
503
|
+
let duration = o_element.duration;
|
|
504
|
+
|
|
505
|
+
const b_num = sj_is_number(duration);
|
|
506
|
+
|
|
507
|
+
if (!b_num)
|
|
508
|
+
{
|
|
509
|
+
duration = - 1.0;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return duration;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
|