PageSourceSearch

https://sportingclubhuelva.com/js/wf_audio.js?v=1778666702

js sportingclubhuelva.com collected 2026-10-02 13:36:43 UTC 8,808 bytes, 323 lines download raw bytes

1/**
2 * wf_audio
3 * ----------------------------------------------------------------------------------------------------
4 * Plugin ligero en JS puro para reproducción de audio con comportamiento toggle (play/stop).
5 * 
6 * FUNCIONALIDAD EXTENDIDA
7 * ----------------------------------------------------------------------------------------------------
8 * - Permite reproducir audio desde:
9 *      1. URL definida en el script
10 *      2. Atributo data-url del botón
11 *      3. Atributo data-audio del botón
12 * 
13 * - Usa delegación de eventos (compatible con contenido dinámico AJAX).
14 * - Un único estado:
15 *      · Si está reproduciendo → lo para
16 *      · Si está parado → lo reproduce
17 * 
18 * - Sistema de depuración con console.group (estilo Webforever).
19 * - Soporte para múltiples botones.
20 * - Actualiza estado visual automáticamente (clases + texto).
21 * - No rompe si no hay URL → salida segura.
22 * 
23 * USO BÁSICO
24 * ----------------------------------------------------------------------------------------------------
25 * HTML:
26 * 
27 * <button 
28 *     class='wf_audio_play'
29 *     data-url='/data/dms/audio.mp3'
30 *     data-texto-play='Reproducir'
31 *     data-texto-stop='Parar'
32 * >
33 *     Reproducir
34 * </button>
35 * 
36 * JS:
37 * 
38 * document.addEventListener(`DOMContentLoaded`, () =>
39 * {
40 *     new wf_audio({
41 *         selector_boton : `.wf_audio_play`,
42 *         url            : ``,
43 *         debug          : true
44 *     });
45 * });
46 * 
47 * 
48 * OPCIONES
49 * ----------------------------------------------------------------------------------------------------
50 * @param string selector_boton  Selector CSS del botón (por defecto `.wf_audio_play`)
51 * @param string url             URL fija de audio (opcional)
52 * @param bool   debug           Activa logs en consola
53 * 
54 * 
55 * COMPORTAMIENTO
56 * ----------------------------------------------------------------------------------------------------
57 * - Click → toggle play/stop
58 * - Cambia texto del botón si existen:
59 *      data-texto-play
60 *      data-texto-stop
61 * 
62 * - Clases automáticas:
63 *      wf_audio_on
64 *      wf_audio_off
65 * 
66 * 
67 * EVENTOS INTERNOS
68 * ----------------------------------------------------------------------------------------------------
69 * play    → marca como reproduciendo
70 * pause   → marca como detenido
71 * ended   → reinicia estado
72 * error   → muestra error en consola
73 * 
74 * 
75 * SEGURIDAD
76 * ----------------------------------------------------------------------------------------------------
77 * - Si no hay URL válida → no hace nada
78 * - Evita múltiples instancias de audio innecesarias
79 * 
80 * 
81 * EJEMPLO AVANZADO (URL DESDE SCRIPT)
82 * ----------------------------------------------------------------------------------------------------
83 * new wf_audio({
84 *     selector_boton : `.play`,
85 *     url            : `/data/dms/8bit-title-screen.mp3`
86 * });
87 * 
88 * 
89 * ESTILOS OPCIONALES
90 * ----------------------------------------------------------------------------------------------------
91 * .wf_audio_on  { opacity: 1; }
92 * .wf_audio_off { opacity: .85; }
93 * 
94 * 
95 * REGISTRO DE CAMBIOS
96 * ----------------------------------------------------------------------------------------------------
97 * 2026-04-16  :  Versión inicial JS puro (sustituye plugin jQuery + Rythm parcial)
98 * 
99 * 
100 * REFERENCIAS
101 * ----------------------------------------------------------------------------------------------------
102 * wf.js / sistema Webforever
103 * 
104 * 
105 * DERECHOS
106 * ----------------------------------------------------------------------------------------------------
107 * @author Pablo Manuel Burrero Sánchez <[email protected]>
108 * @copyright Copyright (c) 2005-2026
109 */
110class wf_audio
111{
112	constructor(opciones = {})
113	{
114		// -------- Declaraciones --------
115		this.selector_boton 	= opciones.selector_boton || `.wf_audio_play`;
116		this.url 				= opciones.url || ``;
117		this.debug 				= opciones.debug ?? true;
118		this.audio 				= null;
119		this.reproduciendo 		= false;
120		this.inicializado 		= false;
121
122		// -------- Inicializaciones --------
123		this.init();
124	}
125
126	debug_group(titulo = `wf_audio`, datos = null)
127	{
128		if (!this.debug) return;
129
130		console.groupCollapsed(`%c${titulo}`, `color:#0d6efd;font-weight:bold;`);
131		if (datos !== null) console.log(datos);
132		console.groupEnd();
133	}
134
135	debug_log(texto = ``, valor = null)
136	{
137		if (!this.debug) return;
138
139		if (valor === null) console.log(`%c${texto}`, `color:#198754;`);
140		else console.log(`%c${texto}`, `color:#198754;`, valor);
141	}
142
143	debug_warn(texto = ``, valor = null)
144	{
145		if (!this.debug) return;
146
147		if (valor === null) console.warn(`%c${texto}`, `color:#dc3545;font-weight:bold;`);
148		else console.warn(`%c${texto}`, `color:#dc3545;font-weight:bold;`, valor);
149	}
150
151	init()
152	{
153		this.debug_group(`wf_audio.init()`, {
154			selector_boton 	: this.selector_boton,
155			url_script 		: this.url
156		});
157
158		document.addEventListener(`click`, ev =>
159		{
160			const boton = ev.target.closest(this.selector_boton);
161			if (!boton) return;
162
163			ev.preventDefault();
164			this.toggle(boton);
165		});
166
167		this.inicializado = true;
168		this.debug_log(`Plugin de audio inicializado correctamente.`);
169	}
170
171	obtener_url(boton = null)
172	{
173		// Prioridad:
174		// 1. URL pasada por script
175		// 2. data-url del botón pulsado
176		// 3. data-audio del botón pulsado
177
178		if (this.url && this.url.trim() !== ``)
179			return this.url.trim();
180
181		if (boton?.dataset?.url && boton.dataset.url.trim() !== ``)
182			return boton.dataset.url.trim();
183
184		if (boton?.dataset?.audio && boton.dataset.audio.trim() !== ``)
185			return boton.dataset.audio.trim();
186
187		return ``;
188	}
189
190	preparar_audio(url = ``)
191	{
192		this.debug_group(`wf_audio.preparar_audio()`, { url });
193
194		if (!url)
195		{
196			this.debug_warn(`No se ha indicado URL de audio. Salimos.`);
197			return false;
198		}
199
200		// Si no existe audio o la URL cambió, creamos uno nuevo
201		if (!this.audio || this.audio.src !== new URL(url, window.location.href).href)
202		{
203			if (this.audio)
204			{
205				this.audio.pause();
206				this.audio.src = ``;
207				this.audio.load();
208			}
209
210			this.audio = new Audio(url);
211			this.audio.preload = `auto`;
212
213			this.audio.addEventListener(`ended`, () =>
214			{
215				this.reproduciendo = false;
216				this.debug_log(`Audio finalizado.`);
217				this.actualizar_botones();
218			});
219
220			this.audio.addEventListener(`play`, () =>
221			{
222				this.reproduciendo = true;
223				this.debug_log(`Audio en reproducción.`);
224				this.actualizar_botones();
225			});
226
227			this.audio.addEventListener(`pause`, () =>
228			{
229				this.reproduciendo = false;
230				this.debug_log(`Audio pausado.`);
231				this.actualizar_botones();
232			});
233
234			this.audio.addEventListener(`error`, err =>
235			{
236				this.reproduciendo = false;
237				this.debug_warn(`Error al cargar o reproducir el audio.`, err);
238				this.actualizar_botones();
239			});
240
241			this.debug_log(`Objeto Audio creado.`, this.audio);
242		}
243
244		return true;
245	}
246
247	async reproducir(boton = null)
248	{
249		const url = this.obtener_url(boton);
250
251		this.debug_group(`wf_audio.reproducir()`, {
252			url,
253			reproduciendo: this.reproduciendo
254		});
255
256		if (!this.preparar_audio(url)) return false;
257
258		try
259		{
260			await this.audio.play();
261			this.reproduciendo = true;
262			this.actualizar_botones();
263			return true;
264		}
265		catch (error)
266		{
267			this.reproduciendo = false;
268			this.debug_warn(`No se pudo iniciar la reproducción.`, error);
269			this.actualizar_botones();
270			return false;
271		}
272	}
273
274	parar()
275	{
276		this.debug_group(`wf_audio.parar()`, {
277			hay_audio: !!this.audio,
278			reproduciendo: this.reproduciendo
279		});
280
281		if (!this.audio)
282		{
283			this.debug_warn(`No hay audio cargado. Salimos.`);
284			return false;
285		}
286
287		this.audio.pause();
288		this.audio.currentTime = 0;
289		this.reproduciendo = false;
290		this.actualizar_botones();
291
292		this.debug_log(`Audio detenido y reiniciado.`);
293		return true;
294	}
295
296	toggle(boton = null)
297	{
298		this.debug_group(`wf_audio.toggle()`, {
299			reproduciendo: this.reproduciendo,
300			boton
301		});
302
303		if (this.reproduciendo) this.parar();
304		else this.reproducir(boton);
305	}
306
307	actualizar_botones()
308	{
309		const botones = document.querySelectorAll(this.selector_boton);
310
311		botones.forEach(boton =>
312		{
313			boton.classList.toggle(`wf_audio_on`, this.reproduciendo);
314			boton.classList.toggle(`wf_audio_off`, !this.reproduciendo);
315			boton.setAttribute(`aria-pressed`, this.reproduciendo ? `true` : `false`);
316
317			if (boton.dataset.textoPlay || boton.dataset.textoStop)
318				boton.textContent = this.reproduciendo
319					? (boton.dataset.textoStop || `Parar`)
320					: (boton.dataset.textoPlay || `Reproducir`);
321		});
322	}
323}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.