PageSourceSearch

https://oncue.nu/wp-content/themes/oncue-2026-wordpress-theme-v9-1/assets/js/demo-sounds.js?ver=1.10.1

js oncue.nu collected 2026-10-02 01:06:28 UTC 11,113 bytes, 228 lines download raw bytes

1(function(){
2  function formatTime(seconds){
3    if(!isFinite(seconds) || seconds < 0) return '00:00';
4    var m = Math.floor(seconds / 60);
5    var s = Math.floor(seconds % 60);
6    return String(m).padStart(2,'0') + ':' + String(s).padStart(2,'0');
7  }
8  function triggerDownload(url){
9    var a = document.createElement('a');
10    a.href = url;
11    a.setAttribute('download', '');
12    a.style.display = 'none';
13    document.body.appendChild(a);
14    a.click();
15    setTimeout(function(){ a.remove(); }, 1000);
16  }
17  function initDemoSounds(){
18    var filters = Array.prototype.slice.call(document.querySelectorAll('[data-demo-filter]'));
19    var cards = Array.prototype.slice.call(document.querySelectorAll('.demo-sound-card'));
20    var search = document.querySelector('#demo-sound-search');
21    var empty = document.querySelector('.demo-empty-state');
22    var activeFilter = 'all';
23
24    function applyFilters(){
25      var q = search ? search.value.trim().toLowerCase() : '';
26      var visible = 0;
27      cards.forEach(function(card){
28        var type = card.getAttribute('data-demo-type') || '';
29        var text = card.getAttribute('data-demo-search') || card.textContent.toLowerCase();
30        var matchesFilter = activeFilter === 'all' || type === activeFilter;
31        var matchesSearch = !q || text.indexOf(q) !== -1;
32        var show = matchesFilter && matchesSearch;
33        card.hidden = !show;
34        if(show) visible++;
35      });
36      if(empty) empty.hidden = visible !== 0;
37    }
38    filters.forEach(function(btn){
39      btn.addEventListener('click', function(){
40        activeFilter = btn.getAttribute('data-demo-filter') || 'all';
41        filters.forEach(function(b){ b.classList.remove('is-active'); });
42        btn.classList.add('is-active');
43        applyFilters();
44      });
45    });
46    if(search) search.addEventListener('input', applyFilters);
47
48    var players = Array.prototype.slice.call(document.querySelectorAll('.demo-mini-player'));
49    var audios = players.map(function(player){ return player.querySelector('audio'); }).filter(Boolean);
50    players.forEach(function(player){
51      var audio = player.querySelector('audio');
52      var btn = player.querySelector('.demo-play-toggle');
53      var time = player.querySelector('.demo-time');
54      var waveform = player.querySelector('.demo-waveform');
55      if(!audio || !btn) return;
56      function setProgress(){
57        var pct = audio.duration ? (audio.currentTime / audio.duration) * 100 : 0;
58        player.style.setProperty('--progress', pct + '%');
59        if(time) time.textContent = formatTime(audio.currentTime || audio.duration || 0);
60      }
61      btn.addEventListener('click', function(){
62        if(audio.paused){ audios.forEach(function(other){ if(other !== audio) other.pause(); }); audio.play(); }
63        else audio.pause();
64      });
65      if(waveform){ waveform.addEventListener('click', function(e){
66        if(!audio.duration) return;
67        var rect = waveform.getBoundingClientRect();
68        var pct = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
69        audio.currentTime = audio.duration * pct;
70        setProgress();
71      }); }
72      audio.addEventListener('loadedmetadata', function(){ if(time) time.textContent = formatTime(audio.duration); });
73      audio.addEventListener('timeupdate', setProgress);
74      audio.addEventListener('play', function(){ player.classList.add('is-playing'); });
75      audio.addEventListener('pause', function(){ player.classList.remove('is-playing'); });
76      audio.addEventListener('ended', function(){ player.classList.remove('is-playing'); player.style.setProperty('--progress', '0%'); });
77    });
78
79    var config = window.OnCueDemoDownloads || {};
80    var modal = document.querySelector('.oncue-download-modal');
81    var form = modal ? modal.querySelector('.oncue-download-form') : null;
82    var close = modal ? modal.querySelector('.oncue-download-modal__close') : null;
83    var emailInput = form ? form.querySelector('input[name="email"]') : null;
84    var consentInput = form ? form.querySelector('input[name="consent"]') : null;
85    var honeypotInput = form ? form.querySelector('input[name="website"]') : null;
86    var submitBtn = form ? form.querySelector('button[type="submit"]') : null;
87    var pendingRequest = false;
88    var consentLabel = form ? form.querySelector('.oncue-consent span') : null;
89    var text = modal ? modal.querySelector('.oncue-download-modal__text') : null;
90    var selectionText = modal ? modal.querySelector('.oncue-download-modal__selection') : null;
91    var error = form ? form.querySelector('.oncue-download-error') : null;
92    var pending = null;
93
94    if(consentLabel && config.consentText) consentLabel.textContent = config.consentText;
95    if(text && config.permissionText) text.textContent = config.permissionText;
96
97    // Multi-select
98    var selectionBar = document.querySelector('.demo-selection-bar');
99    var selectionCount = selectionBar ? selectionBar.querySelector('.demo-selection-count') : null;
100    var selectionClear = selectionBar ? selectionBar.querySelector('.demo-selection-clear') : null;
101    var selectionDownload = selectionBar ? selectionBar.querySelector('.demo-selection-download') : null;
102
103    function selectedItems(){
104      return Array.prototype.slice.call(document.querySelectorAll('.demo-select-box:checked')).map(function(box){
105        var card = box.closest('.demo-sound-card');
106        var btn = card ? card.querySelector('.demo-download') : null;
107        if(!btn) return null;
108        return { url: btn.getAttribute('data-download-url'), soundId: btn.getAttribute('data-sound-id') || '', title: btn.getAttribute('data-sound-title') || '' };
109      }).filter(Boolean);
110    }
111    function updateSelectionBar(){
112      if(!selectionBar) return;
113      var n = document.querySelectorAll('.demo-select-box:checked').length;
114      selectionBar.hidden = n === 0;
115      if(selectionCount) selectionCount.textContent = n + ' selected';
116      if(selectionDownload) selectionDownload.textContent = n > 1 ? 'Download ' + n + ' sounds' : 'Download selected';
117    }
118    function clearSelection(){
119      Array.prototype.slice.call(document.querySelectorAll('.demo-select-box:checked')).forEach(function(box){
120        box.checked = false;
121        var card = box.closest('.demo-sound-card');
122        if(card) card.classList.remove('is-selected');
123      });
124      updateSelectionBar();
125    }
126    document.addEventListener('change', function(e){
127      if(!e.target.classList || !e.target.classList.contains('demo-select-box')) return;
128      var card = e.target.closest('.demo-sound-card');
129      if(card) card.classList.toggle('is-selected', e.target.checked);
130      updateSelectionBar();
131    });
132    if(selectionClear) selectionClear.addEventListener('click', clearSelection);
133    if(selectionDownload) selectionDownload.addEventListener('click', function(){
134      var items = selectedItems();
135      if(items.length) openModal({ multi: items });
136    });
137
138    function openModal(data){
139      pending = data;
140      if(!modal || !form || config.requireEmail === false){ registerAndDownload('', false, data); return; }
141      if(error){ error.hidden = true; error.textContent = ''; }
142      if(emailInput) emailInput.value = '';
143      if(consentInput) consentInput.checked = false;
144      if(selectionText){
145        if(data.multi && data.multi.length > 1){
146          var titles = data.multi.map(function(it){ return it.title; }).filter(Boolean);
147          var shown = titles.slice(0, 4).join(', ') + (titles.length > 4 ? ' +' + (titles.length - 4) + ' more' : '');
148          selectionText.textContent = data.multi.length + ' sounds: ' + shown;
149          selectionText.hidden = false;
150        } else {
151          selectionText.hidden = true;
152        }
153      }
154      modal.hidden = false;
155      modal.setAttribute('aria-hidden','false');
156      setTimeout(function(){ if(emailInput) emailInput.focus(); }, 50);
157    }
158    function closeModal(){
159      if(!modal) return;
160      modal.hidden = true;
161      modal.setAttribute('aria-hidden','true');
162      pending = null;
163    }
164    if(close) close.addEventListener('click', closeModal);
165    if(modal) modal.addEventListener('click', function(e){ if(e.target === modal) closeModal(); });
166
167    function setPending(state){
168      pendingRequest = state;
169      if(submitBtn){
170        submitBtn.disabled = state;
171        if(state){ submitBtn.dataset.label = submitBtn.textContent; submitBtn.textContent = 'Preparing…'; }
172        else if(submitBtn.dataset.label){ submitBtn.textContent = submitBtn.dataset.label; }
173      }
174    }
175    function registerOne(email, consent, item){
176      if(!config.ajaxUrl || !config.nonce) return Promise.resolve(item.url);
177      var body = new FormData();
178      body.append('action','oncue_register_download');
179      body.append('nonce',config.nonce);
180      body.append('email',email || '');
181      body.append('consent',consent ? '1' : '0');
182      body.append('website', honeypotInput ? honeypotInput.value : '');
183      body.append('url',item.url);
184      body.append('sound_id',item.soundId || '');
185      body.append('sound_title',item.title || '');
186      return fetch(config.ajaxUrl, { method:'POST', credentials:'same-origin', body:body })
187        .then(function(r){ return r.json(); })
188        .then(function(json){
189          if(!json || !json.success) throw new Error((json && json.data && json.data.message) || 'Download failed');
190          return (json.data && json.data.url) || item.url;
191        });
192    }
193    function registerAndDownload(email, consent, data){
194      if(!data || pendingRequest) return;
195      var items = (data.multi ? data.multi.slice() : [data]).filter(function(it){ return it && it.url; });
196      if(!items.length) return;
197      setPending(true);
198      var chain = Promise.resolve();
199      items.forEach(function(item, i){
200        chain = chain.then(function(){ return registerOne(email, consent, item); })
201          .then(function(url){
202            triggerDownload(url);
203            if(i < items.length - 1) return new Promise(function(res){ setTimeout(res, 600); });
204          });
205      });
206      chain
207        .then(function(){ closeModal(); clearSelection(); })
208        .catch(function(err){
209          if(error && modal && !modal.hidden){ error.textContent = err.message || 'Download failed'; error.hidden = false; }
210        })
211        .finally(function(){ setPending(false); });
212    }
213    if(form){ form.addEventListener('submit', function(e){
214      e.preventDefault();
215      registerAndDownload(emailInput ? emailInput.value : '', consentInput && consentInput.checked, pending);
216    }); }
217
218    Array.prototype.slice.call(document.querySelectorAll('.demo-download')).forEach(function(btn){
219      btn.addEventListener('click', function(){
220        openModal({ url: btn.getAttribute('data-download-url') || btn.getAttribute('href'), soundId: btn.getAttribute('data-sound-id') || '', title: btn.getAttribute('data-sound-title') || '' });
221      });
222    });
223
224    applyFilters();
225  }
226  if(document.readyState === 'loading') document.addEventListener('DOMContentLoaded', initDemoSounds);
227  else initDemoSounds();
228})();

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.