1(function () { 2 window.helpers.onPageLoadUnload(function () { 3 var player = document.querySelector('.player') 4 5 if (player) { 6 return attachPlayer(player) 7 } 8 }) 9 10 function attachPlayer (player) { 11 var controls = player.querySelector('.player__controls') 12 var listeners = window.helpers.listeners() 13 14 if (!player || !controls) { 15 return 16 } 17 18 var previous = player.querySelector('.player__nav__item--previous') 19 var next = player.querySelector('.player__nav__item--next') 20 var progress = player.querySelector('.player__progress') 21 var progressBar = player.querySelector('.player__progress__bar') 22 var progressDisplay = player.querySelector('.player__progress__display') 23 24 player.getState = getState 25 26 listeners.add(window, 'keydown', function (event) { 27 switch (event.keyCode) { 28 case 37: 29 return player.previous() 30 case 39: 31 return player.next() 32 case 32: 33 if (player.getState('play')) { 34 player.dispatchEvent(new window.Event('pause')) 35 player.updatePlayStatus(false) 36 } else { 37 player.dispatchEvent(new window.Event('play')) 38 player.updatePlayStatus(true) 39 } 40 } 41 }) 42 43 player.updateTime = function (time, duration) { 44 progressDisplay.textContent = [time, duration] 45 .filter(isNumber) 46 .map(formatTime) 47 .join(' / ') 48 49 if (isNumber(time) && isNumber(duration)) { 50 var percentage = ((time / duration) * 100) 51 52 progressBar.style.width = percentage.toFixed(1) + '%' 53 54 player.dispatchEvent(new window.CustomEvent('progress', { 55 detail: { 56 progress: time / duration 57 } 58 })) 59 60 if (percentage === 100 && next) { 61 player.next() 62 } 63 } 64 } 65 66 player.updatePlayStatus = function (status) { 67 player.classList[status ? 'add' : 'remove']('player--playing') 68 setState('play', status) 69 } 70 71 player.updateAudibleStatus = function (status) { 72 player.classList[status ? 'add' : 'remove']('player--audible') 73 setState('audible', status) 74 } 75 76 player.previous = function () { 77 if (previous) { 78 player.dispatchEvent(new window.Event('previous')) 79 previous.click() 80 return true 81 } 82 } 83 84 player.next = function () { 85 if (next) { 86 player.dispatchEvent(new window.Event('next')) 87 next.click() 88 return true 89 } 90 } 91 92 var navigation = { 93 next: player.querySelector('.player__nav__item--next'), 94 previous: player.querySelector('.player__nav__item--previous') 95 } 96 97 if (navigation.next) { 98 listeners.add(navigation.next, 'click', function () { 99 player.dispatchEvent(new window.Event('next')) 100 }) 101 } 102 103 if (navigation.previous) { 104 listeners.add(navigation.previous, 'click', function () { 105 player.dispatchEvent(new window.Event('previous')) 106 }) 107 } 108 109 player.updatePlayStatus(getState('play')) 110 111 const audibleState = player.getState('audible') 112 113 if (audibleState === null) { 114 player.updateAudibleStatus(true) 115 } else { 116 player.updateAudibleStatus(audibleState) 117 } 118 119 var buttons = { 120 play: player.querySelector('.player__button--play'), 121 pause: player.querySelector('.player__button--pause'), 122 mute: player.querySelector('.player__button--mute'), 123 unmute: player.querySelector('.player__button--unmute'), 124 fullscreen: player.querySelector('.player__button--fullscreen'), 125 exitFullscreen: player.querySelector('.player__button--exit-fullscreen') 126 } 127 128 listeners.add(buttons.play, 'click', function () { 129 player.dispatchEvent(new window.Event('play')) 130 player.updatePlayStatus(true) 131 }) 132 133 listeners.add(buttons.pause, 'click', function () { 134 player.dispatchEvent(new window.Event('pause')) 135 player.updatePlayStatus(false) 136 }) 137 138 listeners.add(buttons.mute, 'click', function () { 139 player.dispatchEvent(new window.Event('mute')) 140 player.updateAudibleStatus(false) 141 }) 142 143 listeners.add(buttons.unmute, 'click', function () {
144 player.dispatchEvent(new window.Event('unmute')) 145 player.updateAudibleStatus(true) 146 }) 147 148 listeners.add(buttons.fullscreen, 'click', function () { 149 if (window.screenfull.isEnabled) { 150 window.screenfull.request().then(function () { 151 player.dispatchEvent(new window.Event('fullscreen')) 152 }) 153 } 154 }) 155 156 listeners.add(buttons.exitFullscreen, 'click', function () { 157 if (window.screenfull.isEnabled) { 158 window.screenfull.exit().then(function () { 159 player.dispatchEvent(new window.Event('exit-fullscreen')) 160 }) 161 } 162 }) 163 164 if (!window.screenfull.isEnabled) { 165 buttons.fullscreen.classList.add('player__button--unavailable') 166 buttons.exitFullscreen.classList.add('player__button--unavailable') 167 } 168 169 updateFullscreenStatus() 170 171 if (window.screenfull.isEnabled) { 172 window.screenfull.on('change', updateFullscreenStatus) 173 } 174 175 function getSeekPosition (event) { 176 var pointer = 'changedTouches' in event ? event.changedTouches[0] : event 177 var rect = progress.getBoundingClientRect() 178 return (pointer.clientX - rect.left) / rect.width 179 } 180 181 function startSeeking (event) { 182 event.preventDefault() 183 184 var scrubbing = false 185 var startSeekPosition = getSeekPosition(event) 186 187 var scrub = window.helpers.throttle(function (event) { 188 if (!scrubbing) { 189 var change = Math.abs(getSeekPosition(event) - startSeekPosition) 190 var threshold = 0.025 191 192 if (change > threshold) { 193 scrubbing = true 194 player.dispatchEvent(new window.Event('scrubstart')) 195 } else { 196 return 197 } 198 } 199 200 player.dispatchEvent(new window.CustomEvent('seek', { 201 detail: getSeekPosition(event) 202 })) 203 }, 100) 204 205 function end () { 206 listeners.remove(document, 'mousemove', scrub) 207 listeners.remove(document, 'mouseup', end) 208 listeners.remove(document, 'touchmove', scrub) 209 listeners.remove(document, 'touchend', end) 210 211 if (scrubbing) { 212 player.dispatchEvent(new window.Event('scrubend')) 213 } 214 } 215 216 listeners.add(document, 'mousemove', scrub) 217 listeners.add(document, 'mouseup', end) 218 listeners.add(document, 'touchmove', scrub) 219 listeners.add(document, 'touchend', end) 220 221 player.dispatchEvent(new window.CustomEvent('seek', { 222 detail: startSeekPosition 223 })) 224 } 225 226 listeners.add(progress, 'mousedown', startSeeking) 227 listeners.add(progress, 'touchstart', startSeeking) 228 229 function updateFullscreenStatus () { 230 if (window.screenfull.isEnabled) { 231 var fullscreen = window.screenfull.isFullscreen 232 player.classList[fullscreen ? 'add' : 'remove']('player--fullscreen') 233 } 234 } 235 236 function formatTime (totalSeconds) { 237 var minutes = Math.floor(totalSeconds / 60) 238 var seconds = Math.round(totalSeconds - (minutes * 60)) 239 var segments = [minutes, seconds.toString().padStart(2, '0')] 240 return segments.join(':') 241 } 242 243 function isNumber (value) { 244 return typeof value === 'number' && !Number.isNaN(value) 245 } 246 247 return function detachPlayer () { 248 if (window.screenfull.isEnabled) { 249 window.screenfull.off('change', updateFullscreenStatus) 250 } 251 252 listeners.clear() 253 } 254 } 255 256 function setState (key, value) { 257 // console.log('Set state', key, value) 258 window.localStorage.setItem(getStateKey(key), JSON.stringify(value)) 259 } 260 261 function getState (key) { 262 try { 263 var value = JSON.parse(window.localStorage.getItem(getStateKey(key))) 264 // console.log('Get state', key, value) 265 return value 266 } catch (error) { 267 if (error) { 268 console.warn('Could not get state', key) 269 } 270 271 return null 272 } 273 } 274 275 function getStateKey (key) { 276 return `player-${key}` 277 } 278})()
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.