UNPKG

summit-kit

Version:

A React component library for building modern web applications with with an earthy and outdoorsy flair.

1,050 lines 71.4 kB
import { jsxs as Q, Fragment as Y, jsx as x } from "react/jsx-runtime"; import { I as O } from "./index-DiM-Qsyc.js"; import { useEffect as C, useRef as q, useState as K, useCallback as F } from "react"; const Z = (v) => { C(() => { const m = new AbortController(); return window.addEventListener( "keydown", (n) => { for (const a of v) { const l = a.shortcutKey.includes("+"), f = a.shortcutKey.split("+"); if (l) { const c = f.includes("Shift"), y = f.includes("Control"), p = f.includes("Meta"), _ = f.includes("Alt"), A = f.find( (i) => i !== "Shift" && i !== "Control" && i !== "Meta" && i !== "Alt" ), e = n.key === A, t = n.shiftKey === c, r = n.ctrlKey === y, o = n.metaKey === p, u = n.altKey === _; e && t && r && o && u && a.action && a.action(); } else n.key === a.shortcutKey && a.action && a.action(); } }, { signal: m.signal } ), () => { m.abort(); }; }); }, E = { "page-slider": "_page-slider_1xrrr_1", "right-arrow": "_right-arrow_1xrrr_13", "left-arrow": "_left-arrow_1xrrr_20", "down-arrow": "_down-arrow_1xrrr_27", "up-arrow": "_up-arrow_1xrrr_34" }, te = ({ children: v, onNext: m, onPrev: n, onUp: a, onDown: l }) => (Z([ { shortcutKey: "Control+Shift+ArrowRight", action: m }, { shortcutKey: "Control+Shift+ArrowLeft", action: n }, { shortcutKey: "Control+Shift+ArrowUp", action: a }, { shortcutKey: "Control+Shift+ArrowDown", action: l } ]), /* @__PURE__ */ Q(Y, { children: [ /* @__PURE__ */ x("div", { className: E["page-slider"], children: v || "Slider" }), m && /* @__PURE__ */ x( "button", { className: E["right-arrow"], onClick: m, onKeyDown: (f) => f.key === "Enter" && m(), tabIndex: 0, type: "button", "aria-label": "Go to next page", children: /* @__PURE__ */ x(O, { name: "FiArrowRightCircle", size: 48, color: "white" }) } ), n && /* @__PURE__ */ x( "button", { className: E["left-arrow"], onClick: n, onKeyDown: (f) => f.key === "Enter" && n(), tabIndex: 0, type: "button", "aria-label": "Go to previous page", children: /* @__PURE__ */ x(O, { name: "FiArrowLeftCircle", size: 48, color: "white" }) } ), a && /* @__PURE__ */ x( "button", { className: E["up-arrow"], onClick: a, onKeyDown: (f) => f.key === "Enter" && a(), tabIndex: 0, type: "button", "aria-label": "Go up", children: /* @__PURE__ */ x(O, { name: "FiArrowUpCircle", size: 48, color: "white" }) } ), l && /* @__PURE__ */ x( "button", { className: E["down-arrow"], onClick: l, onKeyDown: (f) => f.key === "Enter" && l(), tabIndex: 0, type: "button", "aria-label": "Go down", children: /* @__PURE__ */ x(O, { name: "FiArrowDownCircle", size: 48, color: "white" }) } ) ] })); var P = typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : typeof global < "u" ? global : typeof self < "u" ? self : {}, B = {}; /*! * howler.js v2.2.4 * howlerjs.com * * (c) 2013-2020, James Simpson of GoldFire Studios * goldfirestudios.com * * MIT License */ var R; function j() { return R || (R = 1, function(v) { (function() { var m = function() { this.init(); }; m.prototype = { /** * Initialize the global Howler object. * @return {Howler} */ init: function() { var e = this || n; return e._counter = 1e3, e._html5AudioPool = [], e.html5PoolSize = 10, e._codecs = {}, e._howls = [], e._muted = !1, e._volume = 1, e._canPlayEvent = "canplaythrough", e._navigator = typeof window < "u" && window.navigator ? window.navigator : null, e.masterGain = null, e.noAudio = !1, e.usingWebAudio = !0, e.autoSuspend = !0, e.ctx = null, e.autoUnlock = !0, e._setup(), e; }, /** * Get/set the global volume for all sounds. * @param {Float} vol Volume from 0.0 to 1.0. * @return {Howler/Float} Returns self or current volume. */ volume: function(e) { var t = this || n; if (e = parseFloat(e), t.ctx || A(), typeof e < "u" && e >= 0 && e <= 1) { if (t._volume = e, t._muted) return t; t.usingWebAudio && t.masterGain.gain.setValueAtTime(e, n.ctx.currentTime); for (var r = 0; r < t._howls.length; r++) if (!t._howls[r]._webAudio) for (var o = t._howls[r]._getSoundIds(), u = 0; u < o.length; u++) { var s = t._howls[r]._soundById(o[u]); s && s._node && (s._node.volume = s._volume * e); } return t; } return t._volume; }, /** * Handle muting and unmuting globally. * @param {Boolean} muted Is muted or not. */ mute: function(e) { var t = this || n; t.ctx || A(), t._muted = e, t.usingWebAudio && t.masterGain.gain.setValueAtTime(e ? 0 : t._volume, n.ctx.currentTime); for (var r = 0; r < t._howls.length; r++) if (!t._howls[r]._webAudio) for (var o = t._howls[r]._getSoundIds(), u = 0; u < o.length; u++) { var s = t._howls[r]._soundById(o[u]); s && s._node && (s._node.muted = e ? !0 : s._muted); } return t; }, /** * Handle stopping all sounds globally. */ stop: function() { for (var e = this || n, t = 0; t < e._howls.length; t++) e._howls[t].stop(); return e; }, /** * Unload and destroy all currently loaded Howl objects. * @return {Howler} */ unload: function() { for (var e = this || n, t = e._howls.length - 1; t >= 0; t--) e._howls[t].unload(); return e.usingWebAudio && e.ctx && typeof e.ctx.close < "u" && (e.ctx.close(), e.ctx = null, A()), e; }, /** * Check for codec support of specific extension. * @param {String} ext Audio file extention. * @return {Boolean} */ codecs: function(e) { return (this || n)._codecs[e.replace(/^x-/, "")]; }, /** * Setup various state values for global tracking. * @return {Howler} */ _setup: function() { var e = this || n; if (e.state = e.ctx && e.ctx.state || "suspended", e._autoSuspend(), !e.usingWebAudio) if (typeof Audio < "u") try { var t = new Audio(); typeof t.oncanplaythrough > "u" && (e._canPlayEvent = "canplay"); } catch { e.noAudio = !0; } else e.noAudio = !0; try { var t = new Audio(); t.muted && (e.noAudio = !0); } catch { } return e.noAudio || e._setupCodecs(), e; }, /** * Check for browser support for various codecs and cache the results. * @return {Howler} */ _setupCodecs: function() { var e = this || n, t = null; try { t = typeof Audio < "u" ? new Audio() : null; } catch { return e; } if (!t || typeof t.canPlayType != "function") return e; var r = t.canPlayType("audio/mpeg;").replace(/^no$/, ""), o = e._navigator ? e._navigator.userAgent : "", u = o.match(/OPR\/(\d+)/g), s = u && parseInt(u[0].split("/")[1], 10) < 33, i = o.indexOf("Safari") !== -1 && o.indexOf("Chrome") === -1, d = o.match(/Version\/(.*?) /), h = i && d && parseInt(d[1], 10) < 15; return e._codecs = { mp3: !!(!s && (r || t.canPlayType("audio/mp3;").replace(/^no$/, ""))), mpeg: !!r, opus: !!t.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ""), ogg: !!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""), oga: !!t.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""), wav: !!(t.canPlayType('audio/wav; codecs="1"') || t.canPlayType("audio/wav")).replace(/^no$/, ""), aac: !!t.canPlayType("audio/aac;").replace(/^no$/, ""), caf: !!t.canPlayType("audio/x-caf;").replace(/^no$/, ""), m4a: !!(t.canPlayType("audio/x-m4a;") || t.canPlayType("audio/m4a;") || t.canPlayType("audio/aac;")).replace(/^no$/, ""), m4b: !!(t.canPlayType("audio/x-m4b;") || t.canPlayType("audio/m4b;") || t.canPlayType("audio/aac;")).replace(/^no$/, ""), mp4: !!(t.canPlayType("audio/x-mp4;") || t.canPlayType("audio/mp4;") || t.canPlayType("audio/aac;")).replace(/^no$/, ""), weba: !!(!h && t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, "")), webm: !!(!h && t.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, "")), dolby: !!t.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ""), flac: !!(t.canPlayType("audio/x-flac;") || t.canPlayType("audio/flac;")).replace(/^no$/, "") }, e; }, /** * Some browsers/devices will only allow audio to be played after a user interaction. * Attempt to automatically unlock audio on the first user interaction. * Concept from: http://paulbakaus.com/tutorials/html5/web-audio-on-ios/ * @return {Howler} */ _unlockAudio: function() { var e = this || n; if (!(e._audioUnlocked || !e.ctx)) { e._audioUnlocked = !1, e.autoUnlock = !1, !e._mobileUnloaded && e.ctx.sampleRate !== 44100 && (e._mobileUnloaded = !0, e.unload()), e._scratchBuffer = e.ctx.createBuffer(1, 1, 22050); var t = function(r) { for (; e._html5AudioPool.length < e.html5PoolSize; ) try { var o = new Audio(); o._unlocked = !0, e._releaseHtml5Audio(o); } catch { e.noAudio = !0; break; } for (var u = 0; u < e._howls.length; u++) if (!e._howls[u]._webAudio) for (var s = e._howls[u]._getSoundIds(), i = 0; i < s.length; i++) { var d = e._howls[u]._soundById(s[i]); d && d._node && !d._node._unlocked && (d._node._unlocked = !0, d._node.load()); } e._autoResume(); var h = e.ctx.createBufferSource(); h.buffer = e._scratchBuffer, h.connect(e.ctx.destination), typeof h.start > "u" ? h.noteOn(0) : h.start(0), typeof e.ctx.resume == "function" && e.ctx.resume(), h.onended = function() { h.disconnect(0), e._audioUnlocked = !0, document.removeEventListener("touchstart", t, !0), document.removeEventListener("touchend", t, !0), document.removeEventListener("click", t, !0), document.removeEventListener("keydown", t, !0); for (var w = 0; w < e._howls.length; w++) e._howls[w]._emit("unlock"); }; }; return document.addEventListener("touchstart", t, !0), document.addEventListener("touchend", t, !0), document.addEventListener("click", t, !0), document.addEventListener("keydown", t, !0), e; } }, /** * Get an unlocked HTML5 Audio object from the pool. If none are left, * return a new Audio object and throw a warning. * @return {Audio} HTML5 Audio object. */ _obtainHtml5Audio: function() { var e = this || n; if (e._html5AudioPool.length) return e._html5AudioPool.pop(); var t = new Audio().play(); return t && typeof Promise < "u" && (t instanceof Promise || typeof t.then == "function") && t.catch(function() { console.warn("HTML5 Audio pool exhausted, returning potentially locked audio object."); }), new Audio(); }, /** * Return an activated HTML5 Audio object to the pool. * @return {Howler} */ _releaseHtml5Audio: function(e) { var t = this || n; return e._unlocked && t._html5AudioPool.push(e), t; }, /** * Automatically suspend the Web Audio AudioContext after no sound has played for 30 seconds. * This saves processing/energy and fixes various browser-specific bugs with audio getting stuck. * @return {Howler} */ _autoSuspend: function() { var e = this; if (!(!e.autoSuspend || !e.ctx || typeof e.ctx.suspend > "u" || !n.usingWebAudio)) { for (var t = 0; t < e._howls.length; t++) if (e._howls[t]._webAudio) { for (var r = 0; r < e._howls[t]._sounds.length; r++) if (!e._howls[t]._sounds[r]._paused) return e; } return e._suspendTimer && clearTimeout(e._suspendTimer), e._suspendTimer = setTimeout(function() { if (e.autoSuspend) { e._suspendTimer = null, e.state = "suspending"; var o = function() { e.state = "suspended", e._resumeAfterSuspend && (delete e._resumeAfterSuspend, e._autoResume()); }; e.ctx.suspend().then(o, o); } }, 3e4), e; } }, /** * Automatically resume the Web Audio AudioContext when a new sound is played. * @return {Howler} */ _autoResume: function() { var e = this; if (!(!e.ctx || typeof e.ctx.resume > "u" || !n.usingWebAudio)) return e.state === "running" && e.ctx.state !== "interrupted" && e._suspendTimer ? (clearTimeout(e._suspendTimer), e._suspendTimer = null) : e.state === "suspended" || e.state === "running" && e.ctx.state === "interrupted" ? (e.ctx.resume().then(function() { e.state = "running"; for (var t = 0; t < e._howls.length; t++) e._howls[t]._emit("resume"); }), e._suspendTimer && (clearTimeout(e._suspendTimer), e._suspendTimer = null)) : e.state === "suspending" && (e._resumeAfterSuspend = !0), e; } }; var n = new m(), a = function(e) { var t = this; if (!e.src || e.src.length === 0) { console.error("An array of source files must be passed with any new Howl."); return; } t.init(e); }; a.prototype = { /** * Initialize a new Howl group object. * @param {Object} o Passed in properties for this group. * @return {Howl} */ init: function(e) { var t = this; return n.ctx || A(), t._autoplay = e.autoplay || !1, t._format = typeof e.format != "string" ? e.format : [e.format], t._html5 = e.html5 || !1, t._muted = e.mute || !1, t._loop = e.loop || !1, t._pool = e.pool || 5, t._preload = typeof e.preload == "boolean" || e.preload === "metadata" ? e.preload : !0, t._rate = e.rate || 1, t._sprite = e.sprite || {}, t._src = typeof e.src != "string" ? e.src : [e.src], t._volume = e.volume !== void 0 ? e.volume : 1, t._xhr = { method: e.xhr && e.xhr.method ? e.xhr.method : "GET", headers: e.xhr && e.xhr.headers ? e.xhr.headers : null, withCredentials: e.xhr && e.xhr.withCredentials ? e.xhr.withCredentials : !1 }, t._duration = 0, t._state = "unloaded", t._sounds = [], t._endTimers = {}, t._queue = [], t._playLock = !1, t._onend = e.onend ? [{ fn: e.onend }] : [], t._onfade = e.onfade ? [{ fn: e.onfade }] : [], t._onload = e.onload ? [{ fn: e.onload }] : [], t._onloaderror = e.onloaderror ? [{ fn: e.onloaderror }] : [], t._onplayerror = e.onplayerror ? [{ fn: e.onplayerror }] : [], t._onpause = e.onpause ? [{ fn: e.onpause }] : [], t._onplay = e.onplay ? [{ fn: e.onplay }] : [], t._onstop = e.onstop ? [{ fn: e.onstop }] : [], t._onmute = e.onmute ? [{ fn: e.onmute }] : [], t._onvolume = e.onvolume ? [{ fn: e.onvolume }] : [], t._onrate = e.onrate ? [{ fn: e.onrate }] : [], t._onseek = e.onseek ? [{ fn: e.onseek }] : [], t._onunlock = e.onunlock ? [{ fn: e.onunlock }] : [], t._onresume = [], t._webAudio = n.usingWebAudio && !t._html5, typeof n.ctx < "u" && n.ctx && n.autoUnlock && n._unlockAudio(), n._howls.push(t), t._autoplay && t._queue.push({ event: "play", action: function() { t.play(); } }), t._preload && t._preload !== "none" && t.load(), t; }, /** * Load the audio file. * @return {Howler} */ load: function() { var e = this, t = null; if (n.noAudio) { e._emit("loaderror", null, "No audio support."); return; } typeof e._src == "string" && (e._src = [e._src]); for (var r = 0; r < e._src.length; r++) { var o, u; if (e._format && e._format[r]) o = e._format[r]; else { if (u = e._src[r], typeof u != "string") { e._emit("loaderror", null, "Non-string found in selected audio sources - ignoring."); continue; } o = /^data:audio\/([^;,]+);/i.exec(u), o || (o = /\.([^.]+)$/.exec(u.split("?", 1)[0])), o && (o = o[1].toLowerCase()); } if (o || console.warn('No file extension was found. Consider using the "format" property or specify an extension.'), o && n.codecs(o)) { t = e._src[r]; break; } } if (!t) { e._emit("loaderror", null, "No codec support for selected audio sources."); return; } return e._src = t, e._state = "loading", window.location.protocol === "https:" && t.slice(0, 5) === "http:" && (e._html5 = !0, e._webAudio = !1), new l(e), e._webAudio && c(e), e; }, /** * Play a sound or resume previous playback. * @param {String/Number} sprite Sprite name for sprite playback or sound id to continue previous. * @param {Boolean} internal Internal Use: true prevents event firing. * @return {Number} Sound ID. */ play: function(e, t) { var r = this, o = null; if (typeof e == "number") o = e, e = null; else { if (typeof e == "string" && r._state === "loaded" && !r._sprite[e]) return null; if (typeof e > "u" && (e = "__default", !r._playLock)) { for (var u = 0, s = 0; s < r._sounds.length; s++) r._sounds[s]._paused && !r._sounds[s]._ended && (u++, o = r._sounds[s]._id); u === 1 ? e = null : o = null; } } var i = o ? r._soundById(o) : r._inactiveSound(); if (!i) return null; if (o && !e && (e = i._sprite || "__default"), r._state !== "loaded") { i._sprite = e, i._ended = !1; var d = i._id; return r._queue.push({ event: "play", action: function() { r.play(d); } }), d; } if (o && !i._paused) return t || r._loadQueue("play"), i._id; r._webAudio && n._autoResume(); var h = Math.max(0, i._seek > 0 ? i._seek : r._sprite[e][0] / 1e3), w = Math.max(0, (r._sprite[e][0] + r._sprite[e][1]) / 1e3 - h), T = w * 1e3 / Math.abs(i._rate), k = r._sprite[e][0] / 1e3, H = (r._sprite[e][0] + r._sprite[e][1]) / 1e3; i._sprite = e, i._ended = !1; var L = function() { i._paused = !1, i._seek = h, i._start = k, i._stop = H, i._loop = !!(i._loop || r._sprite[e][2]); }; if (h >= H) { r._ended(i); return; } var g = i._node; if (r._webAudio) { var D = function() { r._playLock = !1, L(), r._refreshBuffer(i); var I = i._muted || r._muted ? 0 : i._volume; g.gain.setValueAtTime(I, n.ctx.currentTime), i._playStart = n.ctx.currentTime, typeof g.bufferSource.start > "u" ? i._loop ? g.bufferSource.noteGrainOn(0, h, 86400) : g.bufferSource.noteGrainOn(0, h, w) : i._loop ? g.bufferSource.start(0, h, 86400) : g.bufferSource.start(0, h, w), T !== 1 / 0 && (r._endTimers[i._id] = setTimeout(r._ended.bind(r, i), T)), t || setTimeout(function() { r._emit("play", i._id), r._loadQueue(); }, 0); }; n.state === "running" && n.ctx.state !== "interrupted" ? D() : (r._playLock = !0, r.once("resume", D), r._clearTimer(i._id)); } else { var G = function() { g.currentTime = h, g.muted = i._muted || r._muted || n._muted || g.muted, g.volume = i._volume * n.volume(), g.playbackRate = i._rate; try { var I = g.play(); if (I && typeof Promise < "u" && (I instanceof Promise || typeof I.then == "function") ? (r._playLock = !0, L(), I.then(function() { r._playLock = !1, g._unlocked = !0, t ? r._loadQueue() : r._emit("play", i._id); }).catch(function() { r._playLock = !1, r._emit("playerror", i._id, "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."), i._ended = !0, i._paused = !0; })) : t || (r._playLock = !1, L(), r._emit("play", i._id)), g.playbackRate = i._rate, g.paused) { r._emit("playerror", i._id, "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."); return; } e !== "__default" || i._loop ? r._endTimers[i._id] = setTimeout(r._ended.bind(r, i), T) : (r._endTimers[i._id] = function() { r._ended(i), g.removeEventListener("ended", r._endTimers[i._id], !1); }, g.addEventListener("ended", r._endTimers[i._id], !1)); } catch (W) { r._emit("playerror", i._id, W); } }; g.src === "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA" && (g.src = r._src, g.load()); var N = window && window.ejecta || !g.readyState && n._navigator.isCocoonJS; if (g.readyState >= 3 || N) G(); else { r._playLock = !0, r._state = "loading"; var V = function() { r._state = "loaded", G(), g.removeEventListener(n._canPlayEvent, V, !1); }; g.addEventListener(n._canPlayEvent, V, !1), r._clearTimer(i._id); } } return i._id; }, /** * Pause playback and save current position. * @param {Number} id The sound ID (empty to pause all in group). * @return {Howl} */ pause: function(e) { var t = this; if (t._state !== "loaded" || t._playLock) return t._queue.push({ event: "pause", action: function() { t.pause(e); } }), t; for (var r = t._getSoundIds(e), o = 0; o < r.length; o++) { t._clearTimer(r[o]); var u = t._soundById(r[o]); if (u && !u._paused && (u._seek = t.seek(r[o]), u._rateSeek = 0, u._paused = !0, t._stopFade(r[o]), u._node)) if (t._webAudio) { if (!u._node.bufferSource) continue; typeof u._node.bufferSource.stop > "u" ? u._node.bufferSource.noteOff(0) : u._node.bufferSource.stop(0), t._cleanBuffer(u._node); } else (!isNaN(u._node.duration) || u._node.duration === 1 / 0) && u._node.pause(); arguments[1] || t._emit("pause", u ? u._id : null); } return t; }, /** * Stop playback and reset to start. * @param {Number} id The sound ID (empty to stop all in group). * @param {Boolean} internal Internal Use: true prevents event firing. * @return {Howl} */ stop: function(e, t) { var r = this; if (r._state !== "loaded" || r._playLock) return r._queue.push({ event: "stop", action: function() { r.stop(e); } }), r; for (var o = r._getSoundIds(e), u = 0; u < o.length; u++) { r._clearTimer(o[u]); var s = r._soundById(o[u]); s && (s._seek = s._start || 0, s._rateSeek = 0, s._paused = !0, s._ended = !0, r._stopFade(o[u]), s._node && (r._webAudio ? s._node.bufferSource && (typeof s._node.bufferSource.stop > "u" ? s._node.bufferSource.noteOff(0) : s._node.bufferSource.stop(0), r._cleanBuffer(s._node)) : (!isNaN(s._node.duration) || s._node.duration === 1 / 0) && (s._node.currentTime = s._start || 0, s._node.pause(), s._node.duration === 1 / 0 && r._clearSound(s._node))), t || r._emit("stop", s._id)); } return r; }, /** * Mute/unmute a single sound or all sounds in this Howl group. * @param {Boolean} muted Set to true to mute and false to unmute. * @param {Number} id The sound ID to update (omit to mute/unmute all). * @return {Howl} */ mute: function(e, t) { var r = this; if (r._state !== "loaded" || r._playLock) return r._queue.push({ event: "mute", action: function() { r.mute(e, t); } }), r; if (typeof t > "u") if (typeof e == "boolean") r._muted = e; else return r._muted; for (var o = r._getSoundIds(t), u = 0; u < o.length; u++) { var s = r._soundById(o[u]); s && (s._muted = e, s._interval && r._stopFade(s._id), r._webAudio && s._node ? s._node.gain.setValueAtTime(e ? 0 : s._volume, n.ctx.currentTime) : s._node && (s._node.muted = n._muted ? !0 : e), r._emit("mute", s._id)); } return r; }, /** * Get/set the volume of this sound or of the Howl group. This method can optionally take 0, 1 or 2 arguments. * volume() -> Returns the group's volume value. * volume(id) -> Returns the sound id's current volume. * volume(vol) -> Sets the volume of all sounds in this Howl group. * volume(vol, id) -> Sets the volume of passed sound id. * @return {Howl/Number} Returns self or current volume. */ volume: function() { var e = this, t = arguments, r, o; if (t.length === 0) return e._volume; if (t.length === 1 || t.length === 2 && typeof t[1] > "u") { var u = e._getSoundIds(), s = u.indexOf(t[0]); s >= 0 ? o = parseInt(t[0], 10) : r = parseFloat(t[0]); } else t.length >= 2 && (r = parseFloat(t[0]), o = parseInt(t[1], 10)); var i; if (typeof r < "u" && r >= 0 && r <= 1) { if (e._state !== "loaded" || e._playLock) return e._queue.push({ event: "volume", action: function() { e.volume.apply(e, t); } }), e; typeof o > "u" && (e._volume = r), o = e._getSoundIds(o); for (var d = 0; d < o.length; d++) i = e._soundById(o[d]), i && (i._volume = r, t[2] || e._stopFade(o[d]), e._webAudio && i._node && !i._muted ? i._node.gain.setValueAtTime(r, n.ctx.currentTime) : i._node && !i._muted && (i._node.volume = r * n.volume()), e._emit("volume", i._id)); } else return i = o ? e._soundById(o) : e._sounds[0], i ? i._volume : 0; return e; }, /** * Fade a currently playing sound between two volumes (if no id is passed, all sounds will fade). * @param {Number} from The value to fade from (0.0 to 1.0). * @param {Number} to The volume to fade to (0.0 to 1.0). * @param {Number} len Time in milliseconds to fade. * @param {Number} id The sound id (omit to fade all sounds). * @return {Howl} */ fade: function(e, t, r, o) { var u = this; if (u._state !== "loaded" || u._playLock) return u._queue.push({ event: "fade", action: function() { u.fade(e, t, r, o); } }), u; e = Math.min(Math.max(0, parseFloat(e)), 1), t = Math.min(Math.max(0, parseFloat(t)), 1), r = parseFloat(r), u.volume(e, o); for (var s = u._getSoundIds(o), i = 0; i < s.length; i++) { var d = u._soundById(s[i]); if (d) { if (o || u._stopFade(s[i]), u._webAudio && !d._muted) { var h = n.ctx.currentTime, w = h + r / 1e3; d._volume = e, d._node.gain.setValueAtTime(e, h), d._node.gain.linearRampToValueAtTime(t, w); } u._startFadeInterval(d, e, t, r, s[i], typeof o > "u"); } } return u; }, /** * Starts the internal interval to fade a sound. * @param {Object} sound Reference to sound to fade. * @param {Number} from The value to fade from (0.0 to 1.0). * @param {Number} to The volume to fade to (0.0 to 1.0). * @param {Number} len Time in milliseconds to fade. * @param {Number} id The sound id to fade. * @param {Boolean} isGroup If true, set the volume on the group. */ _startFadeInterval: function(e, t, r, o, u, s) { var i = this, d = t, h = r - t, w = Math.abs(h / 0.01), T = Math.max(4, w > 0 ? o / w : o), k = Date.now(); e._fadeTo = r, e._interval = setInterval(function() { var H = (Date.now() - k) / o; k = Date.now(), d += h * H, d = Math.round(d * 100) / 100, h < 0 ? d = Math.max(r, d) : d = Math.min(r, d), i._webAudio ? e._volume = d : i.volume(d, e._id, !0), s && (i._volume = d), (r < t && d <= r || r > t && d >= r) && (clearInterval(e._interval), e._interval = null, e._fadeTo = null, i.volume(r, e._id), i._emit("fade", e._id)); }, T); }, /** * Internal method that stops the currently playing fade when * a new fade starts, volume is changed or the sound is stopped. * @param {Number} id The sound id. * @return {Howl} */ _stopFade: function(e) { var t = this, r = t._soundById(e); return r && r._interval && (t._webAudio && r._node.gain.cancelScheduledValues(n.ctx.currentTime), clearInterval(r._interval), r._interval = null, t.volume(r._fadeTo, e), r._fadeTo = null, t._emit("fade", e)), t; }, /** * Get/set the loop parameter on a sound. This method can optionally take 0, 1 or 2 arguments. * loop() -> Returns the group's loop value. * loop(id) -> Returns the sound id's loop value. * loop(loop) -> Sets the loop value for all sounds in this Howl group. * loop(loop, id) -> Sets the loop value of passed sound id. * @return {Howl/Boolean} Returns self or current loop value. */ loop: function() { var e = this, t = arguments, r, o, u; if (t.length === 0) return e._loop; if (t.length === 1) if (typeof t[0] == "boolean") r = t[0], e._loop = r; else return u = e._soundById(parseInt(t[0], 10)), u ? u._loop : !1; else t.length === 2 && (r = t[0], o = parseInt(t[1], 10)); for (var s = e._getSoundIds(o), i = 0; i < s.length; i++) u = e._soundById(s[i]), u && (u._loop = r, e._webAudio && u._node && u._node.bufferSource && (u._node.bufferSource.loop = r, r && (u._node.bufferSource.loopStart = u._start || 0, u._node.bufferSource.loopEnd = u._stop, e.playing(s[i]) && (e.pause(s[i], !0), e.play(s[i], !0))))); return e; }, /** * Get/set the playback rate of a sound. This method can optionally take 0, 1 or 2 arguments. * rate() -> Returns the first sound node's current playback rate. * rate(id) -> Returns the sound id's current playback rate. * rate(rate) -> Sets the playback rate of all sounds in this Howl group. * rate(rate, id) -> Sets the playback rate of passed sound id. * @return {Howl/Number} Returns self or the current playback rate. */ rate: function() { var e = this, t = arguments, r, o; if (t.length === 0) o = e._sounds[0]._id; else if (t.length === 1) { var u = e._getSoundIds(), s = u.indexOf(t[0]); s >= 0 ? o = parseInt(t[0], 10) : r = parseFloat(t[0]); } else t.length === 2 && (r = parseFloat(t[0]), o = parseInt(t[1], 10)); var i; if (typeof r == "number") { if (e._state !== "loaded" || e._playLock) return e._queue.push({ event: "rate", action: function() { e.rate.apply(e, t); } }), e; typeof o > "u" && (e._rate = r), o = e._getSoundIds(o); for (var d = 0; d < o.length; d++) if (i = e._soundById(o[d]), i) { e.playing(o[d]) && (i._rateSeek = e.seek(o[d]), i._playStart = e._webAudio ? n.ctx.currentTime : i._playStart), i._rate = r, e._webAudio && i._node && i._node.bufferSource ? i._node.bufferSource.playbackRate.setValueAtTime(r, n.ctx.currentTime) : i._node && (i._node.playbackRate = r); var h = e.seek(o[d]), w = (e._sprite[i._sprite][0] + e._sprite[i._sprite][1]) / 1e3 - h, T = w * 1e3 / Math.abs(i._rate); (e._endTimers[o[d]] || !i._paused) && (e._clearTimer(o[d]), e._endTimers[o[d]] = setTimeout(e._ended.bind(e, i), T)), e._emit("rate", i._id); } } else return i = e._soundById(o), i ? i._rate : e._rate; return e; }, /** * Get/set the seek position of a sound. This method can optionally take 0, 1 or 2 arguments. * seek() -> Returns the first sound node's current seek position. * seek(id) -> Returns the sound id's current seek position. * seek(seek) -> Sets the seek position of the first sound node. * seek(seek, id) -> Sets the seek position of passed sound id. * @return {Howl/Number} Returns self or the current seek position. */ seek: function() { var e = this, t = arguments, r, o; if (t.length === 0) e._sounds.length && (o = e._sounds[0]._id); else if (t.length === 1) { var u = e._getSoundIds(), s = u.indexOf(t[0]); s >= 0 ? o = parseInt(t[0], 10) : e._sounds.length && (o = e._sounds[0]._id, r = parseFloat(t[0])); } else t.length === 2 && (r = parseFloat(t[0]), o = parseInt(t[1], 10)); if (typeof o > "u") return 0; if (typeof r == "number" && (e._state !== "loaded" || e._playLock)) return e._queue.push({ event: "seek", action: function() { e.seek.apply(e, t); } }), e; var i = e._soundById(o); if (i) if (typeof r == "number" && r >= 0) { var d = e.playing(o); d && e.pause(o, !0), i._seek = r, i._ended = !1, e._clearTimer(o), !e._webAudio && i._node && !isNaN(i._node.duration) && (i._node.currentTime = r); var h = function() { d && e.play(o, !0), e._emit("seek", o); }; if (d && !e._webAudio) { var w = function() { e._playLock ? setTimeout(w, 0) : h(); }; setTimeout(w, 0); } else h(); } else if (e._webAudio) { var T = e.playing(o) ? n.ctx.currentTime - i._playStart : 0, k = i._rateSeek ? i._rateSeek - i._seek : 0; return i._seek + (k + T * Math.abs(i._rate)); } else return i._node.currentTime; return e; }, /** * Check if a specific sound is currently playing or not (if id is provided), or check if at least one of the sounds in the group is playing or not. * @param {Number} id The sound id to check. If none is passed, the whole sound group is checked. * @return {Boolean} True if playing and false if not. */ playing: function(e) { var t = this; if (typeof e == "number") { var r = t._soundById(e); return r ? !r._paused : !1; } for (var o = 0; o < t._sounds.length; o++) if (!t._sounds[o]._paused) return !0; return !1; }, /** * Get the duration of this sound. Passing a sound id will return the sprite duration. * @param {Number} id The sound id to check. If none is passed, return full source duration. * @return {Number} Audio duration in seconds. */ duration: function(e) { var t = this, r = t._duration, o = t._soundById(e); return o && (r = t._sprite[o._sprite][1] / 1e3), r; }, /** * Returns the current loaded state of this Howl. * @return {String} 'unloaded', 'loading', 'loaded' */ state: function() { return this._state; }, /** * Unload and destroy the current Howl object. * This will immediately stop all sound instances attached to this group. */ unload: function() { for (var e = this, t = e._sounds, r = 0; r < t.length; r++) t[r]._paused || e.stop(t[r]._id), e._webAudio || (e._clearSound(t[r]._node), t[r]._node.removeEventListener("error", t[r]._errorFn, !1), t[r]._node.removeEventListener(n._canPlayEvent, t[r]._loadFn, !1), t[r]._node.removeEventListener("ended", t[r]._endFn, !1), n._releaseHtml5Audio(t[r]._node)), delete t[r]._node, e._clearTimer(t[r]._id); var o = n._howls.indexOf(e); o >= 0 && n._howls.splice(o, 1); var u = !0; for (r = 0; r < n._howls.length; r++) if (n._howls[r]._src === e._src || e._src.indexOf(n._howls[r]._src) >= 0) { u = !1; break; } return f && u && delete f[e._src], n.noAudio = !1, e._state = "unloaded", e._sounds = [], e = null, null; }, /** * Listen to a custom event. * @param {String} event Event name. * @param {Function} fn Listener to call. * @param {Number} id (optional) Only listen to events for this sound. * @param {Number} once (INTERNAL) Marks event to fire only once. * @return {Howl} */ on: function(e, t, r, o) { var u = this, s = u["_on" + e]; return typeof t == "function" && s.push(o ? { id: r, fn: t, once: o } : { id: r, fn: t }), u; }, /** * Remove a custom event. Call without parameters to remove all events. * @param {String} event Event name. * @param {Function} fn Listener to remove. Leave empty to remove all. * @param {Number} id (optional) Only remove events for this sound. * @return {Howl} */ off: function(e, t, r) { var o = this, u = o["_on" + e], s = 0; if (typeof t == "number" && (r = t, t = null), t || r) for (s = 0; s < u.length; s++) { var i = r === u[s].id; if (t === u[s].fn && i || !t && i) { u.splice(s, 1); break; } } else if (e) o["_on" + e] = []; else { var d = Object.keys(o); for (s = 0; s < d.length; s++) d[s].indexOf("_on") === 0 && Array.isArray(o[d[s]]) && (o[d[s]] = []); } return o; }, /** * Listen to a custom event and remove it once fired. * @param {String} event Event name. * @param {Function} fn Listener to call. * @param {Number} id (optional) Only listen to events for this sound. * @return {Howl} */ once: function(e, t, r) { var o = this; return o.on(e, t, r, 1), o; }, /** * Emit all events of a specific type and pass the sound id. * @param {String} event Event name. * @param {Number} id Sound ID. * @param {Number} msg Message to go with event. * @return {Howl} */ _emit: function(e, t, r) { for (var o = this, u = o["_on" + e], s = u.length - 1; s >= 0; s--) (!u[s].id || u[s].id === t || e === "load") && (setTimeout(function(i) { i.call(this, t, r); }.bind(o, u[s].fn), 0), u[s].once && o.off(e, u[s].fn, u[s].id)); return o._loadQueue(e), o; }, /** * Queue of actions initiated before the sound has loaded. * These will be called in sequence, with the next only firing * after the previous has finished executing (even if async like play). * @return {Howl} */ _loadQueue: function(e) { var t = this; if (t._queue.length > 0) { var r = t._queue[0]; r.event === e && (t._queue.shift(), t._loadQueue()), e || r.action(); } return t; }, /** * Fired when playback ends at the end of the duration. * @param {Sound} sound The sound object to work with. * @return {Howl} */ _ended: function(e) { var t = this, r = e._sprite; if (!t._webAudio && e._node && !e._node.paused && !e._node.ended && e._node.currentTime < e._stop) return setTimeout(t._ended.bind(t, e), 100), t; var o = !!(e._loop || t._sprite[r][2]); if (t._emit("end", e._id), !t._webAudio && o && t.stop(e._id, !0).play(e._id), t._webAudio && o) { t._emit("play", e._id), e._seek = e._start || 0, e._rateSeek = 0, e._playStart = n.ctx.currentTime; var u = (e._stop - e._start) * 1e3 / Math.abs(e._rate); t._endTimers[e._id] = setTimeout(t._ended.bind(t, e), u); } return t._webAudio && !o && (e._paused = !0, e._ended = !0, e._seek = e._start || 0, e._rateSeek = 0, t._clearTimer(e._id), t._cleanBuffer(e._node), n._autoSuspend()), !t._webAudio && !o && t.stop(e._id, !0), t; }, /** * Clear the end timer for a sound playback. * @param {Number} id The sound ID. * @return {Howl} */ _clearTimer: function(e) { var t = this; if (t._endTimers[e]) { if (typeof t._endTimers[e] != "function") clearTimeout(t._endTimers[e]); else { var r = t._soundById(e); r && r._node && r._node.removeEventListener("ended", t._endTimers[e], !1); } delete t._endTimers[e]; } return t; }, /** * Return the sound identified by this ID, or return null. * @param {Number} id Sound ID * @return {Object} Sound object or null. */ _soundById: function(e) { for (var t = this, r = 0; r < t._sounds.length; r++) if (e === t._sounds[r]._id) return t._sounds[r]; return null; }, /** * Return an inactive sound from the pool or create a new one. * @return {Sound} Sound playback object. */ _inactiveSound: function() { var e = this; e._drain(); for (var t = 0; t < e._sounds.length; t++) if (e._sounds[t]._ended) return e._sounds[t].reset(); return new l(e); }, /** * Drain excess inactive sounds from the pool. */ _drain: function() { var e = this, t = e._pool, r = 0, o = 0; if (!(e._sounds.length < t)) { for (o = 0; o < e._sounds.length; o++) e._sounds[o]._ended && r++; for (o = e._sounds.length - 1; o >= 0; o--) { if (r <= t) return; e._sounds[o]._ended && (e._webAudio && e._sounds[o]._node && e._sounds[o]._node.disconnect(0), e._sounds.splice(o, 1), r--); } } }, /** * Get all ID's from the sounds pool. * @param {Number} id Only return one ID if one is passed. * @return {Array} Array of IDs. */ _getSoundIds: function(e) { var t = this; if (typeof e > "u") { for (var r = [], o = 0; o < t._sounds.length; o++) r.push(t._sounds[o]._id); return r; } else return [e]; }, /** * Load the sound back into the buffer source. * @param {Sound} sound The sound object to work with. * @return {Howl} */ _refreshBuffer: function(e) { var t = this; return e._node.bufferSource = n.ctx.createBufferSource(), e._node.bufferSource.buffer = f[t._src], e._panner ? e._node.bufferSource.connect(e._panner) : e._node.bufferSource.connect(e._node), e._node.bufferSource.loop = e._loop, e._loop && (e._node.bufferSource.loopStart = e._start || 0, e._node.bufferSource.loopEnd = e._stop || 0), e._node.bufferSource.playbackRate.setValueAtTime(e._rate, n.ctx.currentTime), t; }, /** * Prevent memory leaks by cleaning up the buffer source after playback. * @param {Object} node Sound's audio node containing the buffer source. * @return {Howl} */ _cleanBuffer: function(e) { var t = this, r = n._navigator && n._navigator.vendor.indexOf("Apple") >= 0; if (!e.bufferSource) return t; if (n._scratchBuffer && e.bufferSource && (e.bufferSource.onended = null, e.bufferSource.disconnect(0), r)) try { e.bufferSource.buffer = n._scratchBuffer; } catch { } return e.bufferSource = null, t; }, /** * Set the source to a 0-second silence to stop any downloading (except in IE). * @param {Object} node Audio node to clear. */ _clearSound: function(e) { var t = /MSIE |Trident\//.test(n._navigator && n._navigator.userAgent); t || (e.src = "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA"); } }; var l = function(e) { this._parent = e, this.init(); }; l.prototype = { /** * Initialize a new Sound object. * @return {Sound} */ init: function() { var e = this, t = e._parent; return e._muted = t._muted, e._loop = t._loop, e._volume = t._volume, e._rate = t._rate, e._seek = 0, e._paused = !0, e._ended = !0, e._sprite = "__default", e._id = ++n._counter, t._sounds.push(e), e.create(), e; }, /** * Create and setup a new sound object, whether HTML5 Audio or Web Audio. * @return {Sound} */ create: function() { var e = this, t = e._parent, r = n._muted || e._muted || e._parent._muted ? 0 : e._volume; return t._webAudio ? (e._node = typeof n.ctx.createGain > "u" ? n.ctx.createGainNode() : n.ctx.createGain(), e._node.gain.setValueAtTime(r, n.ctx.currentTime), e._node.paused = !0, e._node.connect(n.masterGain)) : n.noAudio || (e._node = n._obtainHtml5Audio(), e._errorFn = e._errorListener.bind(e), e._node.addEventListener("error", e._errorFn, !1), e._loadFn = e._loadListener.bind(e), e._node.addEventListener(n._canPlayEvent, e._loadFn, !1), e._endFn = e._endListener.bind(e), e._node.addEventListener("ended", e._endFn, !1), e._node.src = t._src, e._node.preload = t._preload === !0 ? "auto" : t._preload, e._node.volume = r * n.volume(), e._node.load()), e; }, /** * Reset the parameters of this sound to the original state (for recycle). * @return {Sound} */ reset: function() { var e = this, t = e._parent; return e._muted = t._muted, e._loop = t._loop, e._volume = t._volume, e._rate = t._rate, e._seek = 0, e._rateSeek = 0, e._paused = !0, e._ended = !0, e._sprite = "__default", e._id = ++n._counter, e; }, /** * HTML5 Audio error listener callback. */ _errorListener: function() { var e = this; e._parent._emit("loaderror", e._id, e._node.error ? e._node.error.code : 0), e._node.removeEventListener("error", e._errorFn, !1); }, /** * HTML5 Audio canplaythrough listener callback. */ _loadListener: function() { var e = this, t = e._parent; t._duration = Math.ceil(e._node.duration * 10) / 10,