Skip to content

Commit 776e37f

Browse files
committed
Start with redoing the speedcode, based upon the existing speed code / quality code.
1 parent 802436b commit 776e37f

1 file changed

Lines changed: 286 additions & 0 deletions

File tree

src/speed/speed2.js

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,286 @@
1+
'use strict';
2+
3+
/**
4+
* Speed button
5+
*
6+
* This feature creates a button to speed media in different levels.
7+
*/
8+
9+
// Translations (English required)
10+
mejs.i18n.en['mejs.speed-rate'] = 'Speed Rate';
11+
12+
// Feature configuration
13+
Object.assign(mejs.MepDefaults, {
14+
/**
15+
* The speeds media can be accelerated
16+
*
17+
* Supports an array of float values or objects with format
18+
* [{name: 'Slow', value: '0.75'}, {name: 'Normal', value: '1.00'}, ...]
19+
* @type {{String[]|Object[]}}
20+
*/
21+
speeds: ['2.00', '1.50', '1.25', '1.00', '0.75'],
22+
/**
23+
* @type {String}
24+
*/
25+
defaultSpeed: '1.00',
26+
/**
27+
* @type {String}
28+
*/
29+
speedChar: 'x',
30+
/**
31+
* @type {?String}
32+
*/
33+
speedText: null
34+
});
35+
36+
Object.assign(MediaElementPlayer.prototype, {
37+
38+
/**
39+
* Feature constructor.
40+
*
41+
* Always has to be prefixed with `build` and the name that will be used in MepDefaults.features list
42+
* @param {MediaElementPlayer} player
43+
* @param {HTMLElement} controls
44+
* @param {HTMLElement} layers
45+
* @param {HTMLElement} media
46+
*/
47+
buildspeed (player, controls, layers, media) {
48+
const
49+
t = this,
50+
isNative = t.media.rendererName !== null && /(native|html5)/i.test(t.media.rendererName)
51+
;
52+
53+
if (!isNative) {
54+
return;
55+
}
56+
57+
const
58+
speeds = [],
59+
speedTitle = mejs.Utils.isString(t.options.speedText) ? t.options.speedText : mejs.i18n.t('mejs.speed-rate'),
60+
;
61+
62+
// define the current speed.
63+
let currentPlaybackSpeed = t.options.defaultSpeed,
64+
defaultSpeedInSpeedsArray = false
65+
66+
// Convert t.options.speeds into the following format:
67+
// [{name: '2x label', value: 2}, {name: '1.5 label', value: 1.5}]
68+
// And always include the defaultSpeed
69+
{
70+
const length = t.options.speeds.length;
71+
for(let i = 0; i < length; i++) {
72+
const speed = t.options.speeds[i];
73+
74+
if (typeof speed === 'string') {
75+
76+
speeds.push({
77+
name: speed + t.options.speedChar,
78+
value: speed
79+
});
80+
81+
if (Number(speed) === Number(t.options.defaultSpeed)) {
82+
defaultSpeedInSpeedsArray = true;
83+
}
84+
}
85+
else {
86+
speeds.push(speed);
87+
if (Number(speed.value) === Number(t.options.defaultSpeed)) {
88+
defaultInArray = true;
89+
}
90+
}
91+
92+
}
93+
94+
if (!defaultInArray) {
95+
speeds.push({
96+
name: t.options.defaultSpeed + t.options.speedChar,
97+
value: t.options.defaultSpeed
98+
});
99+
}
100+
101+
}
102+
103+
104+
// Sort the speeds based on their values
105+
speeds.sort((a, b) => {
106+
return Number(b.value) - Number(a.value);
107+
});
108+
109+
110+
// Before doing any DOM work, clean up.
111+
t.cleanspeed(player);
112+
113+
114+
// Build up the main button and the <div><ul></ul></div> next to it within the player bar.
115+
{
116+
player.speedButton = document.createElement('div');
117+
player.speedButton.className = `${t.options.classPrefix}button ${t.options.classPrefix}speed-button`;
118+
119+
player.speedButton.innerHTML =
120+
'<button ' +
121+
'type="button" ' +
122+
`aria-controls="${t.id}" `+
123+
`title="${speedTitle}" ` +
124+
`aria-label="${speedTitle}" ` +
125+
'tabindex="0"' +
126+
'>'+
127+
getSpeedNameFromValue(t.options.defaultSpeed) +
128+
'</button>' +
129+
`<div class="${t.options.classPrefix}speed-selector ${t.options.classPrefix}offscreen">` +
130+
`<ul class="${t.options.classPrefix}speed-selector-list"></ul>` +
131+
'</div>';
132+
133+
// Add this button into the DOM
134+
t.addControlElement(player.speedButton, 'speed');
135+
136+
137+
// Add speed li items.
138+
let ulHTML = ''
139+
const length = speeds.length;
140+
for(let i = 0; i < length; i++) {
141+
const speed = speeds[i]
142+
143+
const inputId = `${t.id}-speed-${speeds[i].value}`;
144+
145+
const speedIsDefaultSpeed = Number(speed.value) === Number(t.options.defaultSpeed)
146+
147+
const liHTML =
148+
`<li class="${t.options.classPrefix}speed-selector-list-item">` +
149+
`<input `+
150+
`class="${t.options.classPrefix}speed-selector-input" `+
151+
`type="radio" `+
152+
`name="${t.id}_speed"` +
153+
`disabled="disabled" `+
154+
`value="${speed.value}" `+
155+
`id="${inputId}"` +
156+
`${(speedIsDefaultSpeed ? ' checked="checked"' : '')}` +
157+
'/>' +
158+
'<label ' +
159+
`for="${inputId}" `+
160+
`class="${t.options.classPrefix}speed-selector-label` +
161+
`${(speedIsDefaultSpeed ? ` ${t.options.classPrefix}speed-selected` : '')}"`+
162+
'>' +
163+
`${speed.name}`+
164+
'</label>' +
165+
'</li>';
166+
167+
}
168+
169+
player.speedButton.querySelector('ul').innerHTML = ulHTML
170+
}
171+
172+
player.speedSelector = player.speedButton.querySelector(`.${t.options.classPrefix}speed-selector`)
173+
174+
// Enable inputs after they have been appended to controls to avoid tab and up/down arrow focus issues
175+
const
176+
radios = player.speedButton.querySelectorAll('input[type="radio"]'),
177+
labels = player.speedButton.querySelectorAll(`.${t.options.classPrefix}speed-selector-label`)
178+
;
179+
180+
181+
// Handle the events.
182+
let menuIsHidden = true;
183+
184+
function showMenu() {
185+
mejs.Utils.removeClass(player.speedSelector, `${t.options.classPrefix}offscreen`);
186+
player.speedSelector.style.height = player.speedSelector.querySelector('ul').offsetHeight;
187+
player.speedSelector.style.top = `${(-1 * Number(player.speedSelector.offsetHeight))}px`;
188+
189+
menuIsHidden = false;
190+
}
191+
192+
function hideMenu() {
193+
mejs.Utils.addClass(this, `${t.options.classPrefix}offscreen`);
194+
195+
menuIsHidden = true;
196+
}
197+
198+
function hideShowMenu() {
199+
// Ideally, we check for the ${t.options.classPrefix}offscreen class, and if it's not there, it should be visible.
200+
if (menuIsHidden === true) {
201+
showMenu();
202+
} else {
203+
hideMenu();
204+
}
205+
}
206+
207+
player.speedButton.addEventListener('mouseenter', showMenu);
208+
player.speedButton.addEventListener('focusin', showMenu);
209+
210+
player.speedButton.addEventListener('mouseleave', hideMenu);
211+
player.speedButton.addEventListener('focusout', hideMenu);
212+
213+
player.speedButton.addEventListener('click', hideShowMenu);
214+
215+
216+
217+
218+
219+
// Code stolen from quality.js
220+
for (let i = 0, total = radios.length; i < total; i++) {
221+
const radio = radios[i];
222+
radio.disabled = false;
223+
radio.addEventListener('change', function () {
224+
debugger
225+
// t.changeSpeed(this, player, )
226+
});
227+
}
228+
229+
230+
for (let i = 0, total = labels.length; i < total; i++) {
231+
labels[i].addEventListener('click', function () {
232+
const
233+
radio = mejs.Utils.siblings(this, (el) => el.tagName === 'INPUT')[0],
234+
event = mejs.Utils.createEvent('click', radio)
235+
;
236+
radio.dispatchEvent(event);
237+
});
238+
}
239+
240+
241+
242+
243+
244+
245+
246+
// gets the speed name from a speed value.
247+
function getSpeedNameFromValue(speedValue) {
248+
const numSpeedValue = Number(speedValue)
249+
const length = speeds.length;
250+
for(let i = 0; i < length; i++) {
251+
const speed = speeds[i]
252+
if(Number(speed.value) === numSpeedValue) {
253+
return speed.name;
254+
}
255+
}
256+
257+
return speedValue
258+
}
259+
},
260+
261+
262+
changeSpeed(self, player) {
263+
264+
265+
266+
},
267+
268+
269+
/**
270+
* Feature destructor.
271+
*
272+
* Always has to be prefixed with `clean` and the name that was used in MepDefaults.features list
273+
* @param {MediaElementPlayer} player
274+
*/
275+
cleanspeed (player) {
276+
if (player) {
277+
if (player.speedButton) {
278+
player.speedButton.parentNode.removeChild(player.speedButton);
279+
}
280+
if (player.speedSelector) {
281+
player.speedSelector.parentNode.removeChild(player.speedSelector);
282+
}
283+
}
284+
}
285+
286+
});

0 commit comments

Comments
 (0)