-
Notifications
You must be signed in to change notification settings - Fork 1
/
cpu-audio.direct-download.js.map
1 lines (1 loc) · 195 KB
/
cpu-audio.direct-download.js.map
1
{"version":3,"sources":["webpack://cpu-audio/./src/primitives/utils.js","webpack://cpu-audio/./src/primitives/filters.js","webpack://cpu-audio/./src/primitives/events.js","webpack://cpu-audio/./src/primitives/checkers.js","webpack://cpu-audio/./src/primitives/console.js","webpack://cpu-audio/./src/primitives/i18n.js","webpack://cpu-audio/./src/locales/fr.js","webpack://cpu-audio/./src/locales/en.js","webpack://cpu-audio/./src/component/planename.js","webpack://cpu-audio/./src/primitives/convert.js","webpack://cpu-audio/./src/component/show.js","webpack://cpu-audio/./src/primitives/translate_vtt.js","webpack://cpu-audio/./src/mediatag/time.js","webpack://cpu-audio/./src/mediatag/tracks.js","webpack://cpu-audio/./src/primitives/operators.js","webpack://cpu-audio/./src/trigger/cue.js","webpack://cpu-audio/./src/build_chapters.js","webpack://cpu-audio/./src/component_cpu/planes_draw.js","webpack://cpu-audio/./src/build_playlist.js","webpack://cpu-audio/./src/mediatag/actions.js","webpack://cpu-audio/./src/trigger/throbber.js","webpack://cpu-audio/./src/trigger/key.js","webpack://cpu-audio/./src/trigger/fine_nav.js","webpack://cpu-audio/./src/trigger/hash_order.js","webpack://cpu-audio/./src/trigger/track.js","webpack://cpu-audio/./src/trigger/update.js","webpack://cpu-audio/./src/mediatag/extension.js","webpack://cpu-audio/./src/trigger/trigger.js","webpack://cpu-audio/./src/component/timebar_finger_manager.js","webpack://cpu-audio/./src/component/finenav_finger_manager.js","webpack://cpu-audio/./src/build_interface.js","webpack://cpu-audio/./src/bydefault/dataset.js","webpack://cpu-audio/./src/component_cpu/utils.js","webpack://cpu-audio/./src/component_cpu/status.js","webpack://cpu-audio/./src/component_cpu/updates.js","webpack://cpu-audio/./src/component_cpu/throbber.js","webpack://cpu-audio/./src/component_cpu/show.js","webpack://cpu-audio/./src/component_cpu/planes.js","webpack://cpu-audio/./src/component/relative_focus.js","webpack://cpu-audio/./src/component_cpu/planes_focus.js","webpack://cpu-audio/./src/component_cpu/constructor.js","webpack://cpu-audio/./src/cpu_controller.class.js","webpack://cpu-audio/./tmp/insert_template.js","webpack://cpu-audio/./src/cpu_audio.class.js","webpack://cpu-audio/./src/primitives/head_parameters.js","webpack://cpu-audio/./src/mediatag/jump.js","webpack://cpu-audio/./src/mediatag/seek.js","webpack://cpu-audio/./src/document_cpu.js","webpack://cpu-audio/./src/bydefault/parameters.js","webpack://cpu-audio/./src/mediatag/status.js","webpack://cpu-audio/./src/index.js"],"names":["CpuAudioTagName","CpuControllerTagName","selectorAcceptable","selectorAudioInComponent","querySelectorDo","selector","callback","subtree","document","Array","from","querySelectorAll","forEach","findCPU","child","includes","tagName","CPU","closest_cpuaudio","closest","getRootNode","host","escapeHtml","text","burn_after_reading","createElement","innerText","innerHTML","absolutizeUrl","url","test_element","href","split","passiveEvent","passive","oncePassiveEvent","once","preventLinkToSamePage","event","window","location","target","preventDefault","browserIsDecent","undefined","customElements","notScreenContext","matchMedia","matches","warn","message","console","sources_i18n","fr","loading","pause","play","canonical","moment","untitled","cover","more","share","twitter","facebook","e_mail","download","back","chapters","playlist","media_err_aborted","media_err_network","media_err_decode","media_err_src_not_supported","media_err_unknow","prefered_language","out","querySelector","lang","toLowerCase","languages","navigator","language","browserLanguage","line","code","guess_preferable_language","__","planePointNamesFromId","validId","planeAndPointNamesFromId","element_id","planeName","pointName","match","getPointId","panel","units_scale","d","h","m","s","scale","_is_only_numeric","_any_not_numeric","timeInSeconds","givenTime","seconds","test","Number","convert","colontimeInSeconds","subunittimeInSeconds","secondsInTime","givenSeconds","Infinity","converted","inned","key","hasOwnProperty","multiply","digits","Math","floor","secondsInColonTime","length","durationIso","toUpperCase","atom","replace","atoms","pos","secondsInPaddledColonTime","colon_time","substr","previewContainerHover","id","highlightPoint","showElement","classList","show","remove","add","acceptables_tags_normal","i","em","b","bold","u","acceptables_tags_revert","strong","acceptables_tags","vtt_opentag","vtt_closetag","vtt_cr","vtt_br","not_acceptable_tag","name","opentag","tag","class_name","attribute","$_attr","trim","closetag","vtt_taged","normal","isAudiotagStreamed","audiotag","duration","dataset","streamed","uncertainPosition","time","isNaN","uncertainDuration","audiotagDuration","_natural","_forced","normalizeSeekTime","time_seeked","get_chapter_tracks","chapter_track","textTracks","tracks","kind","adjacentArrayValue","arr","value","offset","indexOf","index","body_className_playing_cue","playRelativeCueInPlayer","container","points","planePoints","go","pointList","Object","values","reverse","currentTime","cue","end","start","jumpIdAt","cuechange","active_cue","body","plane_chapters","async","build_chapters","elCPU","isController","has","pointDataGroup","cues","addPlane","title","track","cuechange_event_this","cuechange_event","removeEventListener","addEventListener","point","startTime","link","endTime","bulkPoints","activeCues","body_class","body_classlist","removePlane","cue_line","_activecue_id","removeHighlightsPoints","activecueClassname","emitEvent","previewClassname","planes_draw","drawPlane","this","planeTrack","planePanel","planeData","plane","doRemoveHighlightsPoints","assignEventsOnPlanes","element","plane_track","shadowId","appendChild","plane_panel","open","mirroredInController","globalController","drawPoint","pointData","image","use_link","elementPointTrack","pointTrack","tabIndex","html","removeHtml","track_img","src","positionTimeElement","planeNav","elementPointPanel","pointPanel","time_element","dateTime","refreshPlane","planeSort","planePointNames","redrawAllPlanes","keys","_planes","_CPU_planes","className","mirror","highlight","plane_playlist","removeOfPlaylists","playlists","currentPlaylistID","redraw","previous_length","filter","entry_id","getElementById","buildPlaylist","rePointsPlaylist","current_playlist","clearPlane","audiotag_id","shadowRoot","insertAdjacentElement","wasFocusedId","previous_playlist","currentPlaylist","_comp","focusPoint","lastPlayError","timecodeStart","timecodeEnd","currentAudiotagPlaying","localStorage","removeItem","currentSrc","at","promised","then","hadPlayed","catch","error","unlock","autoplay","playOnceUnlock","_CPU_played","CPU_api","glowBeforePlay","setAct","switchControllerTo","toggleplay","paused","throbble","offsetX","DocumentCPU","seekElementAt","ratio","clientWidth","isAudiotagPlaying","updateLoading","hover","clientX","targetTouches","audiotagPreloadMetadata","x","width","getBoundingClientRect","showThrobberAt","mult","altKey","ctrlKey","metaKey","shiftKey","seek_relative","hideThrobberLater","keyCode","focused","restart","keymove","prevFocus","nextFocus","hashOrder","hashcode","callback_fx","at_start","hash","timecode","parameter","p_key","p_value","timecode_start","timecode_end","_timecodeStart","_timecodeEnd","setTimecodes","scrollTo","scrollIntoView","playRelativeTrackInPlaylist","playlist_name","playlist_index","next_id","next_audiotag","update","updateAudiotag","setItem","String","reward","foward","fastreward","fastFactor","fastfoward","hideThrobber","prevcue","nextcue","prevtrack","nexttrack","playOnce","document_cpu","lastUsed","_end","recallStoredPlay","lasttimecode","getItem","HTMLAudioElement","prototype","count_element","readyState","HAVE_NOTHING","load","attach_events_audiotag","on","getAttribute","connectAudiotag","hidden","removeAttribute","push","addToPlaylist","ev","down","setTimeout","act","alternateDelay","showHandheldNav","up","clearTimeout","pressing","acceptable_press_actions","press","repeat","repeatDelay","repeatFactor","release","nativeShare","audiotagDataset","focus","cliquables","actions","showActions","showMain","poster","elementId","elementAction","entries","el","button_element","timeline_element","canonical_element","repositionTracks","this_build_chapters","track_element","_CPU_load_ev","buildChaptersLoader","updatePlayButton","updateLinks","head","domain","header_element","content","attr","waveform","attributesChanges","mode","hasAttribute","mode_still","mode_play","mode_when_play","setMode","setHide","isEqualNode","event_name","detail","dispatchEvent","CustomEvent","bubbles","cancelable","composed","shadow","acceptableHideAtttributes","mode_was","act_was","classes","hide_elements","container_class","hide_this","completeTemplate","element_canonical","classlist","style","backgroundImage","attachAudiotagToInterface","IDPrefix","addIdToAudiotag","injectCss","styleName","css","removeCss","planeNameBorders","updates","_attr","control_button","aria","_preload","HAVE_CURRENT_DATA","setAttribute","label","will_act","hide_panels_except_play_mark","updateLine","loadingline_element","updateTime","_is_at","elapse_element","duration_element","updateTimeBorders","isAudiotagGlobal","check","addPoint","updateError","error_object","error_message","MediaError","MEDIA_ERR_ABORTED","MEDIA_ERR_NETWORK","MEDIA_ERR_DECODE","MEDIA_ERR_SRC_NOT_SUPPORTED","pageerror","timepos","tag_id","_url","encodeURIComponent","_twitter","substring","links","email","seconds_begin","seconds_end","isSeconds","sec","left","right","seeked_time","phylactere","opacity","_hider","toggle","checkPointData","planeNames","concat","old_points","fromEntries","sort","point_a","point_b","_st_max","panelReorder","previous_element","nav","editPoint","original_data","will_refresh","removePoint","that_start","self","go_foward","validPlane","clientHeight","wasFocused","fromPlane","scanToNextPlane","scanToPrevPlane","planes_focus","focusedId","translateVTT","media_tagname","previous_audiotag","modifiedController","component","audio_element","info","copyAttributesToMediaDataset","CpuControllerElement","HTMLElement","constructor","super","observer","attachShadow","connectedCallback","MutationObserver","observe","childList","attributes","disconnectedCallback","disconnect","modifiedAudio","CpuAudioElement","defaultDataset","playlist_id","doNeedleMove","secs","mocked_event","HAVE_FUTURE_DATA","doElementPlay","fastSeek","settime","e","playStopOthers","globalCss","advanceInPlaylist","JSON","parse","trigger","adjacentKey","obj","current_audiotag","main","global_class_indicator","insert_style","define","get","HTMLDocument"],"mappings":"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","file":"cpu-audio.direct-download.js","sourcesContent":["/** @license\nCpu-Audio: an extension to the hash system to address timecode into audio/video elements and a player WebComponent\nVersion 7.1\nCopyright (C) 2014-2022 Xavier \"dascritch\" Mouton-Dubosc & contributors.\nLicense LGPL 3\n\n- project mini-site https://dascritch.github.io/cpu-audio/\n- project repository : https://github.com/dascritch/cpu-audio\n- use case : http://cpu.pm\n- blog post : https://dascritch.net/post/2018/11/06/Reconstruire-son-lecteur-audio-pour-le-web\n**/\n\nexport const CpuAudioTagName = 'CPU-AUDIO';\nexport const CpuControllerTagName = 'CPU-CONTROLLER';\nexport const selectorAcceptable = 'audio[controls]';\nexport const selectorAudioInComponent = `${CpuAudioTagName} audio`; // should be 'audio[controls]' but PHRACK APPLE !\n\n\n/**\n * @summary Process a function on each matched CSS selector found in a DOM tree\n *\n * @param {string} selector The css selector\n * @param {Function} callback The callback function, its 1st parameter will be the matching DOM element\n * @param {Element|HTMLDocument|ShadowRoot} [subtree=document] The subtree, by default the whole hosting document\n */\nexport function querySelectorDo(selector, callback, subtree=document) {\n\tArray.from(\n\t\tsubtree.querySelectorAll(selector)\n\t).forEach(callback);\n}\n\n/**\n * @summary For any <audio> tag or its child tag or shadowDOM element, returns the element `CPU` API\n * @public via document.CPU.findCPU\n *\n * @param {Element} child The child\n * @return {CPU_element_api} Element.CPU\n */\nexport function findCPU(child) {\n\tif ([CpuAudioTagName, CpuControllerTagName].includes(child.tagName)) {\n\t\treturn child.CPU;\n\t}\n\n\tlet closest_cpuaudio = child.closest(CpuAudioTagName) ?? child.closest(CpuControllerTagName);\n\tif (closest_cpuaudio) {\n\t\treturn closest_cpuaudio.CPU;\n\t}\n\n\treturn child.getRootNode().host.CPU;\n}\n\n","/**\n * @summary Escape a text. Will truly escape HTML tags and entities. No hazardous regexes or replaces\n *\n * @param {string} text The text\n * @return {string} HTML escaped text\n */\nexport function escapeHtml(text) {\n\tconst burn_after_reading = document.createElement('p');\n\tburn_after_reading.innerText = text;\n\tconst { innerHTML } = burn_after_reading;\n\t// burn_after_reading.remove(); implicit\n\treturn innerHTML;\n}\n\n/**\n * @summary Remove HTML elements and entities from a text.\n *\n * @param {string} html HTML source\n * @return {string} text\n */\nexport function removeHtml(html) {\n\tconst burn_after_reading = document.createElement('p');\n\tburn_after_reading.innerHTML = html;\n\tconst { innerText } = burn_after_reading;\n\t// burn_after_reading.remove(); implicit\n\treturn innerText;\n}\n\n/**\n * @summary Transform a possibily relative URL to an absolute URL, including server name, but removing hash part\n *\n * @param {string} url The url\n * @return {string} url Absolute url\n */\nexport function absolutizeUrl(url) {\n\tconst test_element = document.createElement('a');\n\ttest_element.href = (typeof url !== 'string') ? url : url.split('#')[0];\n\treturn test_element.href;\n}","import { absolutizeUrl } from './filters.js';\n\n// Parameters for addEventListener\n// @private\nexport const passiveEvent = { passive: true };\n// @private\nexport const oncePassiveEvent = { ...passiveEvent, once: true };\n\n\n/**\n * @summary Will prevent a link in a page if linked to the same absolute URL\n *\n * @param {Event} event The event\n */\nfunction preventLinkToSamePage(event) {\n\tif (absolutizeUrl(window.location.href) === absolutizeUrl(event.target.href)) {\n\t\tevent.preventDefault();\n\t}\n}\n\n/**\n * @summary Cancel any action on this link if its href is in this page\n *\n * @param {Element} element The <A> DOM element\n */\nexport function preventLinkOnSamePage(element) {\n\telement.addEventListener('click', preventLinkToSamePage);\n}\n","// Determines if the hosting browser can use webcomponents.\nexport const browserIsDecent = window.customElements !== undefined;\n\n// Checks if we are in a screen context, and not a vocal or braille interface\nexport const notScreenContext = !window.matchMedia('screen').matches;\n","import { CpuAudioTagName } from './utils.js';\n\n/**\n * @summary Shortcut for console info\n *\n * @param {string} message The message\n */\nexport const info = (message) => window.console.info(`${CpuAudioTagName}▷ `,message);\n\n/**\n * @summary Shortcut for console warning\n *\n * @param {string} message The message\n */\nexport const warn = (message) => window.console.warn(`${CpuAudioTagName}▷ `,message);\n\n/**\n * @summary Shortcut for console error\n *\n * @param {string} message The message\n */\nexport const error = (message) => window.console.error(`${CpuAudioTagName}▷ `,message);\n","import fr from '../locales/fr.js';\nimport en from '../locales/en.js';\n\nconst sources_i18n = {\n\tfr, en\n};\n\n/**\n * @summary Guess usable language (returned in ISO 2 letters code) from browser preferences and host page mark-up\n * @private\n * \n */\nfunction guess_preferable_language() {\n\t// First, we'll try to guess the hosting page language\n\tconst out = document.querySelector('html').lang;\n\tif ((out.length) && (out.toLowerCase() in sources_i18n)) {\n\t\treturn out;\n\t}\n\n\t// trying to find the browser preferences\n\tconst languages = window.navigator.languages ?? [(navigator.language || navigator.browserLanguage)];\n\tfor (const line of languages) {\n\t\tif (line.split) {\n\t\t\t// we will only look (yes, this is bad) at the first level xx of any locale xx-YY code\n\t\t\tconst [code] = line.split('-');\n\t\t\tif (code in sources_i18n) {\n\t\t\t\t// we still don't have a locale selected and this one is in our register, we can use it\n\t\t\t\treturn code;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Inexisting ? We will use english in last resort\t\n\treturn 'en';\n}\n\nexport let prefered_language = guess_preferable_language();\nexport const __ = sources_i18n[prefered_language];\nexport default __;\n","const fr = {\n\tloading : `Chargement en cours…`,\n\tpause : `Pause`,\n\tplay : `Lecture`,\n\tcanonical : `Lien vers la fiche du sonore`,\n\tmoment : `Lien vers ce moment`,\n\n\tuntitled : `(sans titre)`,\n\tcover : `pochette`,\n\tmore : `Actions`,\n\tshare : `Partager`,\n\ttwitter : `Partager sur Twitter`,\n\tfacebook : `Partager sur Facebook`,\n\te_mail : `Partager par e-mail`,\n\tdownload : `Télécharger`,\n\tback : `Annuler`,\n\n\tchapters : `Chapitres`,\n\tplaylist : `Playlist`,\n\n\tmedia_err_aborted : `Vous avez annulé la lecture.`,\n\tmedia_err_network : `Une erreur réseau a causé l'interruption du téléchargement.`,\n\tmedia_err_decode : `La lecture du sonore a été annulée suite à des problèmes de corruption ou de fonctionnalités non supportés par votre navigateur.`,\n\tmedia_err_src_not_supported : `Le sonore n'a pu être chargé, soit à cause de sourcis sur le serveur, le réseau ou parce que le format n'est pas supporté.`,\n\tmedia_err_unknow : `Erreur due à une raison inconnue.`\n};\n\nexport default fr;","const en = {\n\tloading : `Loading…`,\n\tpause : `Pause`,\n\tplay : `Play`,\n\tcanonical : `Link to the sound's page`,\n\tmoment : `Link to this time`,\n\n\tuntitled : `(untitled)`,\n\tcover : `cover`,\n\tmore : `Actions`,\n\tshare : `Share`,\n\ttwitter : `Share on Twitter`,\n\tfacebook : `Share on Facebook`,\n\te_mail : `Share via e-mail`,\n\tdownload : `Download`,\n\tback : `Back`,\n\n\tchapters : `Chapters`,\n\tplaylist : `Playlist`,\n\n\tmedia_err_aborted : `You have aborted the play.`,\n\tmedia_err_network : `A network error broke the download.`,\n\tmedia_err_decode : `Play was canceled due to file corruption or a not supported function in your browser.`,\n\tmedia_err_src_not_supported : `The media cannot be downloaded due to server problems, network problems or unsupported by your browser.`,\n\tmedia_err_unknow : `Error of unknown cause.`\n};\n\nexport default en;","\n// Regex for extracting plane and point names from an id\nexport const planePointNamesFromId = /^[\\w-]+_«([\\w-]+)(»_.*_«([\\w-]+))?»$/;\n\n// Regex used to validate planes, points and injected css names\n// NOTE : [\\w-] === [a-zA-Z0-9_\\-]\nexport const validId = /^[\\w-]+$/;\n\n/**\n * @summary Gets the plane point names from an id on a ShadowDOM element.\n * @package\n\n * repeated in the class for testing purposes\n *\n * @param {string} element_id \tThe element identifier\n * @return {Object} \t\t\t\tAn object with two strings : planeName and pointName\n */\nexport function planeAndPointNamesFromId(element_id) {\n\tlet planeName, pointName;\n\tif (typeof element_id == 'string') {\n\t\t[, planeName, , pointName] = element_id?.match(planePointNamesFromId) || [];\n\t}\n\treturn {\n\t\tplaneName : planeName??'',\n\t\tpointName : pointName??''\n\t};\n}\n\n/**\n * @summary Gets the point track identifier\n *\n * @param {string} planeName The plane name\n * @param {string} pointName The point name\n * @param {boolean} panel Is panel (true) or track (false)\n * @return {string} The point track identifier.\n */\nexport function getPointId(planeName, pointName, panel) {\n\treturn `${ panel?'panel':'track' }_«${planeName}»_point_«${pointName}»`;\n}\n\n","const units_scale = {\n\td : 86400,\n\th : 3600,\n\tm : 60,\n\ts : 1\n};\nconst scale = [1, 60, 3600, 86400]; \n\nconst _is_only_numeric = /^\\d+$/;\nconst _any_not_numeric = /\\D*/g;\n\n// How Inifity (streamed live media with unspecified duration) should be humanly expressed\nconst Infinity_representation = '?';\n\n/**\n * @summary convert a string empty, with a number, with a colon-coded or an human-coded timecode in seconds\n * @public\n *\n * @class timeInSeconds (name)\n * @param {string} givenTime The given time\n * @return {number} time in seconds\n */\nexport const timeInSeconds = (givenTime) => {\n\tlet seconds = 0;\n\tif (givenTime !== '') {\n\t\tif (_is_only_numeric.test(givenTime)) {\n\t\t\tseconds = Number(givenTime);\n\t\t} else {\n\t\t\tseconds = givenTime.includes(':') ?\n\t\t\t\tconvert.colontimeInSeconds(givenTime) :\n\t\t\t\tconvert.subunittimeInSeconds(givenTime) ;\n\t\t}\n\t}\n\treturn seconds;\n};\n\n/**\n * @summary convert a human-coded (`1h2m3s`) time in seconds\n * @public\n *\n * @class subunittimeInSeconds (name)\n * @param {string} givenTime The given time\n * @return {number} seconds\n */\nexport const subunittimeInSeconds = (givenTime) => {\n\tlet seconds = 0;\n\tlet atom;\n\tfor(let key in units_scale) {\n\t\tif ( (units_scale.hasOwnProperty(key)) && (givenTime.includes(key)) ) {\n\t\t\t[atom, givenTime] = givenTime.split(key);\n\t\t\tseconds += Number(atom.replace(_any_not_numeric,'' )) * units_scale[key];\n\t\t}\n\t}\n\treturn seconds;\n};\n\n/**\n * @summary convert a colon-coded (`01:02:03`) time in seconds\n * @public\n *\n * @class colontimeInSeconds (name)\n * @param {string} givenTime The given time\n * @return {number} Time in seconds\n */\nexport const colontimeInSeconds = (givenTime) => {\n\tlet seconds = 0;\n\tconst atoms = givenTime.split(':');\n\tfor (let pos = 0 ; pos < atoms.length ; pos++) {\n\t\tseconds += Number(atoms[pos]) * scale[((atoms.length-1) - pos)];\n\t}\n\treturn seconds;\n};\n\n/**\n * @summary convert a time in seconds in a human-coded time (`1h2m3s`). Zero is `0s`.\n * @public\n *\n * @class secondsInTime (name)\n * @param {number} givenSeconds The given seconds\n * @return {string} Converted time\n */\nexport const secondsInTime = (givenSeconds) => {\n\tif (givenSeconds === Infinity) {\n\t\treturn Infinity_representation;\n\t}\n\tlet converted = '';\n\tlet inned = false;\n\tfor (const key in units_scale) {\n\t\tif (units_scale.hasOwnProperty(key)) {\n\t\t\tlet multiply = units_scale[key];\n\t\t\tif ((givenSeconds >= multiply) || (inned)) {\n\t\t\t\tinned = true;\n\t\t\t\tlet digits = Math.floor(givenSeconds / multiply);\n\t\t\t\tconverted += digits + key;\n\t\t\t\tgivenSeconds -= digits * multiply;\n\t\t\t}\n\t\t}\n\t}\n\treturn converted === '' ? '0s' : converted;\n};\n\n/**\n * @summary convert a time in seconds in a colon-coded time (`1:02:03s`). Zero is `0:00`.\n * @public\n *\n * @class secondsInColonTime (name)\n * @param {number} givenSeconds The given seconds\n * @return {string} Converted time\n */\nexport const secondsInColonTime = (givenSeconds) => {\n\tif (givenSeconds === Infinity) {\n\t\treturn Infinity_representation;\n\t}\n\tlet converted = '';\n\tlet inned = false;\n\tfor (let key in units_scale) {\n\t\tif (units_scale.hasOwnProperty(key)) {\n\t\t\tlet multiply = units_scale[key];\n\t\t\tif ((givenSeconds >= multiply) || (inned)) {\n\t\t\t\tinned = true;\n\t\t\t\tlet digits = Math.floor(givenSeconds / multiply);\n\t\t\t\tconverted += (converted === '' ? '' : ':');\n\t\t\t\tconverted += ( ((digits<10) && (converted !== '')) ? '0' : '') + digits ;\n\t\t\t\tgivenSeconds -= digits * multiply;\n\t\t\t}\n\t\t}\n\t}\n\tif (converted.length === 1) {\n\t\t// between 0 and 9 seconds\n\t\treturn `0:0${converted}`;\n\t}\n\tif (converted.length === 2) {\n\t\t// between 10 and 59 seconds\n\t\treturn `0:${converted}`;\n\t}\n\n\treturn converted === '' ? '0:00' : converted;\n};\n\n/**\n * @summary same as `secondsInColonTime`, but suited for `<input type=\"time\"\n * />`. Zero is `00:00:00`.\n *\n * @public\n *\n * @class secondsInPaddledColonTime (name)\n * @param {number} givenSeconds The given seconds\n * @return {string} Converted time\n */\nexport const secondsInPaddledColonTime = (givenSeconds) => {\n\tif (givenSeconds === Infinity) {\n\t\treturn Infinity_representation;\n\t}\n\t// principaly needed by <input type=\"time\"> whom needs a really precise HH:MM:SS format\n\tlet colon_time = convert.secondsInColonTime(givenSeconds);\n\treturn '00:00:00'.substr(0, 8 - colon_time.length ) + colon_time;\n};\n\n/**\n * @summary convert a duration in an ISO 8601 string suitable for `datetime=\"\"` attribute in <time>\n * See spec in https://www.w3.org/TR/html51/infrastructure.html#durations\n * @public\n *\n * @class durationIso (name)\n * @param {number} givenSeconds Duration, in seconds\n * @return {string} Converted duration\n */\nexport const durationIso = (givenSeconds) => {\n\treturn `P${convert.secondsInTime(givenSeconds).toUpperCase()}`;\n};\n\nexport const convert = {\n\ttimeInSeconds,\n\tsubunittimeInSeconds,\n\tcolontimeInSeconds,\n\tsecondsInTime,\n\tsecondsInColonTime,\n\tsecondsInPaddledColonTime,\n\tdurationIso\n};\n\nexport default convert;\n\n","import { findCPU } from '../primitives/utils.js';\n\nimport { planeAndPointNamesFromId } from './planename.js';\n\nconst hidingClassname = 'no';\n\n/**\n * @summary Highlight the playable positions when hovering a marked link\n *\n * @param {Object} event An hover event\n */\nexport function previewContainerHover({target}) {\n\tif (!target.id) {\n\t\ttarget = target.closest('[id]');\n\t}\n\tif (!target) {\n\t\treturn;\n\t}\n\n\tconst {planeName, pointName} = planeAndPointNamesFromId(target.id);\n\tfindCPU(target).highlightPoint(planeName, pointName);\n}\n\n\n/**\n * @summary Show or hide an element\n *\n * @param {Element} element \tThe element to show or hide\n * @param {boolean} show \t\tShow if true, hide if false\n */\nexport function showElement({classList}, show) {\n\tif (show) {\n\t\tclassList.remove(hidingClassname);\n\t} else {\n\t\tclassList.add(hidingClassname);\n\t}\n}","import { escapeHtml } from './filters.js';\n\nconst acceptables_tags_normal = {\n\ti : 'i',\n\tem : 'i',\n\tb : 'b',\n\tbold : 'strong', // (declared in the MDN page, but never seen it in standard pages)\n\tu : 'u',\n\tlang : 'i' \t\t// emphasis for typographic convention\n};\n\nconst acceptables_tags_revert = {\n\ti : 'i',\n\tem : 'i',\n\tb : 'b',\n\tstrong: 'b',\n\tu : 'u',\n};\n\nlet acceptables_tags = acceptables_tags_normal;\n\n/**\n *\n * NEVER EVER BELIEVE you can parse HTML with regexes ! This function works because we just do minimalistic changes\n * By the way, regexes are really time consuming, both for you and your computer.\n * And, sincerely, I love playing on https://regexcrossword.com/\n */\n\n// regexes used for WebVTT tag validation\nconst vtt_opentag = /<(\\w+)(\\.[^>]+)?( [^>]+)?>/gi;\nconst vtt_closetag = /<\\/(\\w+)( [^>]*)?>/gi;\nconst vtt_cr = /\\n/gi;\nconst vtt_br = /<br\\s*[^>]*>/gi;\n\n/**\n * Checks if a WebVTT candidate tag name is acceptable or not\n *\n * @param {string} name Tag name\n * @return {boolean} not accepted (inverted logic)\n */\nfunction not_acceptable_tag(name) {\n\treturn !(name in acceptables_tags);\n}\n\n/**\n * @param {string} \t\t tag \t\t\tUnused regex capture\n * @param {string} \t\t name \t\tName of the tag\n * @param {string} \t\t class_name \tattribute key, unused\n * @param {string} \t\t attribute \tattribute value, may be language code\n * @return {string}\n */\nfunction opentag(tag, name, class_name, attribute) {\n\tname = name.toLowerCase();\n\tif (not_acceptable_tag(name)) {\n\t\treturn '';\n\t}\n\tlet $_attr = '';\n\tif (name == 'lang') {\n\t\t$_attr = ` lang=\"${attribute.trim()}\"`;\n\t}\n\treturn `<${acceptables_tags[name]}${$_attr}>`;\n}\n\n/**\n * @param {string} \t\t tag \t\t\tUnused regex capture\n * @param {string} \t\t name \t\tName of the tag\n * @return {string}\n */\nfunction closetag(tag, name) {\n\tname = name.toLowerCase();\n\tif (not_acceptable_tag(name)) {\n\t\treturn '';\n\t}\n\treturn `</${acceptables_tags[name]}>`;\n}\n\n/**\n * @summary Transform WebVTT tag langage into HTML tags, filtering out some\n * (needed @public mainly for tests. Moving it up and do those tests in CLI will make it @private-izable)\n *\n * @param {string} vtt_taged The vtt tagged\n * @param {boolean} normal \t Mode HTML→VTT if true, VTT→HTML if false (true by default)\n * @return string HTML tagged string\n */\nexport function translateVTT(vtt_taged, normal = true) {\n\tacceptables_tags = normal ? acceptables_tags_normal : acceptables_tags_revert;\n\n\tif ((vtt_taged.split('<').length) !== (vtt_taged.split('>').length)) {\n\t\t// unmatching < and >, probably badly written tags, or in full text\n\t\t// unsurprisingly, (vtt_taged.split('<').length) is a lot faster than using regex. JS needs a native property for counting substring occurences in a string\n\t\treturn escapeHtml(vtt_taged);\n\t}\n\n\tconst out = vtt_taged.\n\t\t\treplace(vtt_opentag, opentag).\n\t\t\treplace(vtt_closetag, closetag);\n\n\treturn normal ? out.replace(vtt_cr, '<br/>') : out.replace(vtt_br, '\\n');\n}\n\nexport default translateVTT;\n","/**\n * @summary Determines if audiotag source is streamed, and so unactivate reposition, position memory, length display…\n *\n * @param {HTMLAudioElement|null} audiotag The audiotag\n * @return {boolean} \tTrue if audiotag streamed, False otherwise.\n */\nexport function isAudiotagStreamed(audiotag) {\n\treturn ((audiotag == null) || (audiotag.duration === Infinity) || (audiotag.dataset.streamed != null));\n}\n\n\n/**\n * @summary Checks if a time position is seekabe into an audiotag \n * @private\n *\n * @param {number|null} \ttime \tExpected time to seek in an audiotag\n * @return {boolean} \t\t\tUnusable time\n */\nexport function uncertainPosition(time) {\n\n\treturn (time === Infinity) || (time === null) || (isNaN(time));\n}\n\n\n/**\n * @summary Checks if an audiotag's duration is suitable for ratio maths\n * A media may have unusable duration for ratio because \n * - media is unreadable\n * - media is streamed\n * - even if it is a finished file, its duration is still unknown (Chrome may be late)\n * @private\n *\n * @param {number|null} \tduration \t`duration` of an audiotag, or result of `audiotagDuration(audiotag)`\n * @return {boolean} \t\t\t\tUnusable duration\n */\nexport function uncertainDuration(duration) {\n\n\treturn (duration === 0) || (uncertainPosition(duration));\n}\n\n/**\n * @summary Try to find audiotag duration, or its manually declared duration\n * @private\n *\n * @param {HTMLAudioElement} \taudiotag \tAudio to check length\n * @return {Number|null} \t\t\tResult in seconds. Null if non applicable\n */\nexport function audiotagDuration({duration, dataset}) {\n\tlet out = null;\n\tconst _natural = Number(duration);\n\tif (!uncertainDuration(_natural)) {\n\t\tout = _natural;\n\t} else {\n\t\tconst _forced = Number(dataset.duration);\n\t\tif (!uncertainDuration(_forced)) { // yes, because isNaN(Number('Infinity')) !\n\t\t\tout = _forced;\n\t\t}\n\t}\n\treturn out;\n}\n\n/**\n * @summary Normalize a seeked time between limits of an audiotag\n * @private\n *\n * @param {HTMLAudioElement} \taudiotag \t\tAudio to check length\n * @param {Number}\t\t\t \ttime_seeked\t\tTime position to check\n * @return {Number|null} \t \t\t \t\tResult in seconds, null if totally innaplicable\n */\nexport function normalizeSeekTime(audiotag, time_seeked) {\n\tif (uncertainPosition(time_seeked)) {\n\t\treturn null;\n\t}\n\ttime_seeked = time_seeked < 0 ? 0 : time_seeked;\n\tconst duration = audiotagDuration(audiotag);\n\tif (!uncertainDuration(duration)) {\n\t\ttime_seeked = time_seeked < duration ? time_seeked : duration ;\n\t}\n\treturn time_seeked;\n}\n","import { prefered_language } from '../primitives/i18n.js';\n\n/**\n * @summary Extract usable chapter tracks from audiotag\n * @private\n *\n * @param {HTMLAudioElement} \taudiotag\tThe <audio> supposed to have a chapter tracj\n * @return {TextTrack|null} \t\t\t\tThe TextTrack, or null if not applicable\n */\nexport function get_chapter_tracks(audiotag) {\n\tif (!audiotag) {\n\t\treturn null;\n\t}\n\n\tlet chapter_track = null;\n\tif (audiotag.textTracks?.length > 0) {\n\t\tfor (const tracks of audiotag.textTracks) {\n\t\t\tif (\n\t\t\t\t\t(tracks.kind.toLowerCase() === 'chapters') &&\n\t\t\t\t\t(tracks.cues) && // linked to default=\"\" attribute, only one per set !\n\t\t\t\t\t(\n\t\t\t\t\t\t(!chapter_track) /* still no active track */\n\t\t\t\t\t\t|| (tracks.language.toLowerCase() === prefered_language) /* correspond to <html lang> */\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\tchapter_track = tracks;\n\t\t\t}\n\t\t}\n\t}\n\treturn chapter_track;\n}","/**\n * @summary Find adjacent key to a key in object, previous or next one\n * @public via document.CPU for tests purposes\n *\n * @param \t{object} \tobject \tObject to analyze\n * @param string \t\t\t\t\tkey \t\tKey where to position\n * @param number \t\t\t\t\toffset \t\toffset to reposition. -1 for previous, +1 for next\n * @return \tstring|null|undefined \t\tfound key, null or undefined if inapplicable\n */\nexport function adjacentKey(obj, key, offset) {\n\tif (!obj?.hasOwnProperty) {\n\t\treturn null;\n\t}\n\tconst keys = Object.keys(obj);\n\treturn keys[keys.indexOf(key) + offset];\n}\n\n/**\n * @summary Find adjacent value to a value in an array, previous or next one\n *\n * @param \tarray \t\tarray \tArray to analyse\n * @param string \t\t\t\t\tvalue \t\tValue where to position\n * @param number \t\t\t\t\toffset \t\toffset to reposition. -1 for previous, +1 for next\n * @return \tstring|null|undefined \t\tfound key, null or undefined if inapplicable\n */\nexport function adjacentArrayValue(arr, value, offset) {\n\tif (!arr?.indexOf) {\n\t\treturn null;\n\t}\n\tconst index = arr.indexOf(value);\n\tif (index === -1) {\n\t\treturn null;\n\t}\n\treturn arr[index + offset];\n}\n","import { findCPU } from '../primitives/utils.js';\nimport { adjacentArrayValue } from '../primitives/operators.js';\n\nimport { planeAndPointNamesFromId } from '../component/planename.js';\n\n\n// actual active elements\n// @type {string|null}\nlet\tbody_className_playing_cue = null;\n\n/**\n * @summary Common code for trigger.prevcue and trigger.nextcue\n *\n * @param {HTMLAudioElement} \taudiotag \tThe audiotag we're leaving\n * @param {Number}\t\t\t \toffset \tThe offset to apply on the index\n */\nfunction playRelativeCueInPlayer(container, offset) {\n\tconst audiotag = container.audiotag;\n\tconst points = container.planePoints('_chapters');\n\tif (!points) {\n\t\treturn;\n\t}\n\tconst {pointName} = planeAndPointNamesFromId( body_className_playing_cue );\n\tlet go = adjacentArrayValue(points, pointName, offset);\n\tlet pointList = Object.values(points);\n\tif (offset < 0) {\n\t\tpointList = pointList.reverse();\n\t}\n\tconst {currentTime} = audiotag;\n\tif (!go) {\n\t\tfor (const cue of pointList) {\n\t\t\tif ( (!go) && (\n\t\t\t\t((offset < 0) && (cue.end <= currentTime)) || \n\t\t\t\t(((offset > 0) && (cue.start >= currentTime)) )\n\t\t\t) ) {\n\t\t\t\tgo = cue;\n\t\t\t}\n\t\t}\n\t}\n\tif (go) {\n\t\tdocument.CPU.jumpIdAt(audiotag.id, go.start);\n\t}\n}\n\n/**\n * @summary Refresh document body when changing chapter\n *\n * @param {Object} active_cue \t\tThe TextTrack actived\n * @param {HTMLAudioElement} audiotag Audiotag relative to TextTrack\n *\n * To not warns on classList.remove()\n * @suppress {checkTypes}\n */\nexport function cuechange(active_cue, audiotag) {\n\tconst { classList } = document.body;\n\tclassList.remove(body_className_playing_cue);\n\t// giving a class to document.body, with a syntax according to https://www.w3.org/TR/CSS21/syndata.html#characters\n\tbody_className_playing_cue = `cpu_playing_tag_«${audiotag.id}»_cue_«${active_cue.id}»`;\n\tclassList.add(body_className_playing_cue);\n}\n\nexport const cue = {\n\n\tcuechange,\n\n\t/**\n\t * @summary Pressing prevcue button\n\t *\n\t * @param {Object} event The event\n\t */\n\tprevcue : function({target}) {\n\t\tplayRelativeCueInPlayer(findCPU(target), -1);\n\t},\n\n\t/**\n\t * @summary Pressing nextcue button\n\t *\n\t * @param {Object} event The event\n\t */\n\tnextcue : function({target}) {\n\t\tplayRelativeCueInPlayer(findCPU(target), 1);\n\t},\n\n\n};\n\nexport default cue;","import { oncePassiveEvent, passiveEvent } from './primitives/events.js';\nimport __ from './primitives/i18n.js';\nimport translateVTT from './primitives/translate_vtt.js';\n\nimport { normalizeSeekTime } from './mediatag/time.js';\nimport { get_chapter_tracks } from './mediatag/tracks.js';\n\nimport { cuechange } from './trigger/cue.js';\nimport { activecueClassname } from './component_cpu/planes_draw.js';\n\nconst plane_chapters = '_chapters';\n\n/**\n * @summary Add listeners on tracks to build chapters when loaded\n * @private\n * \n * @param {Object} elCPU <cpu-audio>.CPU\n */\nexport function buildChaptersLoader(elCPU) {\n\tconst this_build_chapters = () => { build_chapters(elCPU); };\n\tthis_build_chapters();\n\tconst { audiotag } = elCPU;\n\n\t// sometimes, we MAY have loose loading\n\taudiotag.addEventListener('loadedmetadata', this_build_chapters, oncePassiveEvent);\n\n\tconst track_element = audiotag.querySelector('track[kind=\"chapters\"]');\n\tif ((track_element) && (!track_element._CPU_load_ev)) {\n\t\ttrack_element._CPU_load_ev = track_element.addEventListener('load', this_build_chapters, passiveEvent);\n\t}\n}\n\n/**\n * @summary Builds or refresh chapters interface.\n * @private was public\n *\n * @param {Object} \t\t\telCPU <cpu-audio>.CPU\n * @param {Object|undefined} \tevent The event\n */\nexport async function build_chapters(elCPU) {\n\t// this functions is called THREE times at load : at build, at loadedmetada event and at load event\n\t// and afterwards, we have to reposition track points on duractionchange\n\n\tif (elCPU.isController) {\n\t\t// not your job, CPUController\n\t\treturn;\n\t}\n\n\tconst audiotag = elCPU.audiotag;\n\tlet has = false;\n\tconst pointDataGroup = {};\n\n\tif (audiotag) {\n\t\tconst chapter_track = get_chapter_tracks(audiotag);\n\n\t\tif (chapter_track?.cues.length > 0) {\n\t\t\telCPU.addPlane(plane_chapters, {\n\t\t\t\ttitle : __['chapters'],\n\t\t\t\ttrack : 'chapters'\n\t\t\t});\n\n\t\t\tconst cuechange_event_this = () => {cuechange_event(elCPU);};\n\t\t\t// ugly, but best way to catch the DOM element, as the `cuechange` event won't give it to you via `this` or `event`\n\t\t\t// adding/reinstall chapter changing event\n\t\t\tchapter_track.removeEventListener('cuechange', cuechange_event_this);\n\t\t\tchapter_track.addEventListener('cuechange', cuechange_event_this, passiveEvent);\n\n\t\t\tfor (const cue of chapter_track.cues) {\n\t\t\t\tif (!elCPU.point(plane_chapters, cue.id)) {\n\t\t\t\t\tpointDataGroup[cue.id] = {\n\t\t\t\t\t\tstart : normalizeSeekTime(audiotag, Math.floor(cue.startTime)),\n\t\t\t\t\t\ttext : translateVTT(cue.text),\n\t\t\t\t\t\tlink : true, \t\t\t\t\t\t\t\t// point the link to start time position\n\t\t\t\t\t\tend : normalizeSeekTime(audiotag, Math.floor(cue.endTime)) // end timecode of the cue\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (chapter_track.cues.length > 0) {\n\t\t\t\thas = true;\n\t\t\t}\n\t\t\telCPU.bulkPoints(plane_chapters, pointDataGroup);\n\t\t\tcuechange_event(elCPU, {\n\t\t\t\ttarget : {\n\t\t\t\t\tactiveCues : chapter_track.cues\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tconst body_class = `cpu_tag_«${audiotag.id}»_chaptered`;\n\tconst body_classlist = document.body.classList;\n\tif (has) {\n\t\t// indicate in host page that audio tag chapters are listed\n\t\t// see https://github.com/dascritch/cpu-audio/issues/36\n\t\tbody_classlist.add(body_class);\n\t} else {\n\t\telCPU.removePlane(plane_chapters);\n\t\tbody_classlist.remove(body_class);\n\t}\n\n\t/*\n\tif ((active_cue) && (id_in_hash(this.audiotag.id)) ) {\n\t\t// shoud be set ONLY if audiotag is alone in page or if audiotag.id named in hash\n\t\tcuechange(active_cue, this.audiotag);\n\t\tthis.emitEvent('chapterChanged', {\n\t\t\tcue : active_cue\n\t\t});\n\t\t// and so, shall we scroll ?\n\t}\n\t*/\n\n}\n\n/**\n * @summary Call when a chapter is changed, to trigger the changes\n * @private\n *\n * @param {Object} elCPU Element.CPU\n * @param {Object} event \tThe event\n */\nexport function cuechange_event(elCPU, event = null) {\n\t// TODO : if not event, based on '_chapters' information from audio\n\n\tconst activeCues = event ? event.target.activeCues : get_chapter_tracks(elCPU.audiotag)?.activeCues;\n\t\n\tlet cue;\n\t// Chrome may put more than one activeCue. That's a stupid regression from them, but alas… I have to deal with it\n\tconst currentTime = elCPU.audiotag.currentTime;\n\t\n\tif (activeCues?.length > 0) {\n\t\tfor (const cue_line of activeCues) {\n\t\t\tif ((cue_line.startTime <= currentTime) && (currentTime < cue_line.endTime)) {\n\t\t\t\tcue = cue_line;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (cue?.id === elCPU._activecue_id) {\n\t\treturn ;\n\t}\n\n\telCPU.removeHighlightsPoints(plane_chapters, activecueClassname);\n\telCPU._activecue_id = cue?.id;\n\n\tif (cue) {\n\t\tcuechange(cue, elCPU.audiotag);\n\t\telCPU.emitEvent('chapterChanged', { cue });\n\t\telCPU.highlightPoint(plane_chapters, cue.id, activecueClassname);\n\t}\n}","import { passiveEvent } from '../primitives/events.js';\nimport { escapeHtml, removeHtml } from '../primitives/filters.js';\nimport { secondsInColonTime, durationIso } from '../primitives/convert.js';\nimport { findCPU, querySelectorDo } from '../primitives/utils.js';\n\nimport { getPointId } from '../component/planename.js';\nimport { previewContainerHover, showElement } from '../component/show.js';\n\nimport { cuechange_event } from '../build_chapters.js';\n\n\nconst previewClassname = 'with-preview';\nexport const activecueClassname = 'active-cue';\n\n\n/**\n * @summary Clean up DOM elements of any annotations, before rebuild them\n * @private\n *\n * @param {Element} container The webcontainer to clean-up\n */\nfunction undrawAllPlanes(container) {\n\tquerySelectorDo('aside, details.panel', (element) => element.remove(), container);\n}\n\nexport const planes_draw = {\n\n\t/**\n\t * @summary Draws a plane\n\t * @private\n\t *\n\t * @param {string} planeName The plane name\n\t */\n\tdrawPlane: function(planeName) {\n\t\tthis.planeTrack(planeName)?.remove();\n\t\tthis.planePanel(planeName)?.remove();\n\n\t\tconst planeData = this.plane(planeName);\n\t\tif (!planeData) {\n\t\t\treturn ;\n\t\t}\n\t\tconst { track, panel, title } = planeData;\n\t\tconst doRemoveHighlightsPoints = () => this.removeHighlightsPoints(planeName, previewClassname, true);\n\n\t\tconst assignEventsOnPlanes = (element) => {\n\t\t\telement.addEventListener('mouseover', previewContainerHover, passiveEvent);\n\t\t\telement.addEventListener('focusin', previewContainerHover, passiveEvent);\n\t\t\telement.addEventListener('mouseleave', doRemoveHighlightsPoints, passiveEvent);\n\t\t\telement.addEventListener('focusout', doRemoveHighlightsPoints, passiveEvent);\n\t\t};\n\n\t\tif (track !== false) {\n\t\t\t// we have to create the track timeline\n\t\t\tconst plane_track = document.createElement('aside');\n\t\t\tplane_track.id = `track_«${planeName}»`;\n\t\t\tif (track !== true) {\n\t\t\t\t// …with a class list, space separated\n\t\t\t\tplane_track.classList.add(track.split(' '));\n\t\t\t}\n\n\t\t\tthis.shadowId('line').appendChild(plane_track);\n\t\t\tassignEventsOnPlanes(plane_track);\n\t\t}\n\n\t\tif (panel !== false) {\n\t\t\t// we have to create the panel area\n\t\t\tconst plane_panel = document.createElement('details');\n\t\t\t// TODO #180 : We may be able to hide by default, or have de details closed\n\t\t\tplane_panel.open = true;\n\t\t\tplane_panel.id = `panel_«${planeName}»`;\n\t\t\tif (panel !== true) {\n\t\t\t\t// …with a class list\n\t\t\t\tplane_panel.classList.add(panel.split(' '));\n\t\t\t}\n\t\t\tplane_panel.classList.add('panel');\n\t\t\tplane_panel.innerHTML = `<summary>${escapeHtml(title)}</summary><nav><ul></ul></nav>`;\n\t\t\tthis.container.appendChild(plane_panel);\n\t\t\tshowElement( plane_panel.querySelector('summary') , title);\n\t\t\tassignEventsOnPlanes(plane_panel);\n\t\t}\n\n\t\tif ( (!this.isController) && (this.mirroredInController()) ) {\n\t\t\tdocument.CPU.globalController.drawPlane(planeName);\n\t\t}\n\n\t},\n\n\t\t/**\n\t * @summary Draws a plane point\n\t * @private\n\t *\n\t * @param {string} planeName The plane name\n\t * @param {string} pointName The point name\n\t */\n\tdrawPoint: function(planeName, pointName) {\n\t\tconst audiotag = this.audiotag ?? document.CPU.globalController.audiotag;\n\t\tconst pointData = this.point(planeName, pointName);\n\t\tconst {start, link, text, image, end} = pointData;\n\n\t\tlet use_link = '#';\n\t\tif (link === true) {\n\t\t\t// automated link to the audio tag.\n\t\t\tuse_link = `#${audiotag.id}&t=${start}`;\n\t\t}\n\t\tif (typeof(link) === 'string') {\n\t\t\t// Integrator of the page wants a specific url (hoping he know what he do with a \"javascript:\")\n\t\t\tuse_link = link;\n\t\t}\n\n\t\tconst track = this.planeTrack(planeName);\n\t\tlet elementPointTrack;\n\t\tif (track) {\n\t\t\telementPointTrack = this.pointTrack(planeName, pointName);\n\t\t\tif (!elementPointTrack) {\n\t\t\t\telementPointTrack = document.createElement('a');\n\t\t\t\telementPointTrack.id = getPointId(planeName, pointName, false);\n\t\t\t\t// TODO : how to do chose index of a point track if there is no link, or a panel but no track??\n\t\t\t\telementPointTrack.tabIndex = -1; \n\t\t\t\telementPointTrack.innerHTML = '<img alt=\"\" /><span></span>';\n\t\t\t\ttrack.appendChild(elementPointTrack);\n\t\t\t}\n\t\t\telementPointTrack.href = use_link;\n\t\t\telementPointTrack.title = removeHtml(text);\n\t\t\tconst track_img = elementPointTrack.querySelector('img');\n\t\t\tshowElement(track_img, image);\n\t\t\ttrack_img.src = image || '';\n\t\t\telementPointTrack.querySelector('img').innerHTML = text ;\n\t\t\tthis.positionTimeElement(elementPointTrack, start, end);\n\t\t}\n\n\t\tconst panel = this.planeNav(planeName);\n\t\tlet elementPointPanel;\n\t\tif (panel) {\n\t\t\telementPointPanel = this.pointPanel(planeName, pointName);\n\t\t\tif (!elementPointPanel) {\n\t\t\t\telementPointPanel = document.createElement('li');\n\t\t\t\telementPointPanel.id = getPointId(planeName, pointName, true);\n\t\t\t\telementPointPanel.innerHTML = '<a href=\"#\" class=\"cue\"><strong></strong><time></time></a>';\n\t\t\t\tpanel.appendChild(elementPointPanel);\n\t\t\t}\n\t\t\telementPointPanel.querySelector('a').href = use_link;\n\t\t\telementPointPanel.querySelector('strong').innerHTML = text;\n\t\t\tconst time_element = elementPointPanel.querySelector('time');\n\t\t\ttime_element.dateTime = durationIso(start);\n\t\t\ttime_element.innerText = secondsInColonTime(start);\n\t\t}\n\n\t\tthis.emitEvent('drawPoint', {\n\t\t\tplaneName,\n\t\t\tpointName,\n\t\t\tpointData,\n\t\t\telementPointTrack,\n\t\t\telementPointPanel,\n\t\t});\n\n\t\tif ( (!this.isController) && (this.mirroredInController()) ) {\n\t\t\tdocument.CPU.globalController.drawPoint(planeName, pointName);\n\t\t}\n\t},\n\n\t/**\n\t * @summary Refresh a plane. a panelReorder may be enough\n\t * @public\n\t *\n\t * @param {string} planeName The plane name\n\t */\n\trefreshPlane: function(planeName) {\n\t\tthis.planeSort(planeName);\n\t\tfor (const pointName of this.planePointNames(planeName)) {\n\t\t\tthis.drawPoint(planeName, pointName);\n\t\t}\n\t},\n\n\t/**\n\t * @summary Clear and redraw all planes\n\t * Mainly when cpu-controller is changing targeted audio tag\n\t * @public\n\t */\n\tredrawAllPlanes: function() {\n\t\tundrawAllPlanes(this.container);\n\n\t\tfor (const planeName of Object.keys({...this._planes, ...this.audiotag._CPU_planes})) {\n\t\t\tthis.drawPlane(planeName);\n\t\t\tthis.refreshPlane(planeName);\n\t\t}\n\n\t\t// due to a Chrome glitch on chapters panel in cpu-controller while changing playing cpu-audio, we have to refresh a cuechange_event \n\t\tcuechange_event(this);\n\t},\n\n\t/**\n\t * @summary Remove any previewes on plane points\n\t * @public\n\t *\n\t * @param\t\t\t {string} planeName The plane name to operate\n\t * @param {string} className Targeted class name, 'with-preview' by default\n\t * @param {boolean} mirror Also act on linked cpu-controller/cpu-audio\n\t */\n\tremoveHighlightsPoints: function(planeName, className=previewClassname, mirror=true) {\n\t\tquerySelectorDo(\n\t\t\t`#track_«${planeName}» .${className}, #panel_«${planeName}» .${className}`,\n\t\t\t(element) => element.classList.remove(className),\n\t\t\tthis.container);\n\t\tif ( (mirror) && (this.mirroredInController()) ) {\n\t\t\tconst globalController = document.CPU.globalController;\n\t\t\tconst on = this.isController ? findCPU(globalController.audiotag) : globalController;\n\t\t\ton.removeHighlightsPoints(planeName, className, false);\n\t\t}\n\t},\n\n\t/**\n\t * @summary Sets a preview on a plane point\n\t * @public\n\t *\n\t * @param {string} planeName The plane name\n\t * @param {string} pointName The point name\n\t * @param {string} className class name, 'with-preview' by default\n\t * @param {boolean} mirror Also act on linked cpu-controller/cpu-audio, true by default\n\t */\n\thighlightPoint: function(planeName, pointName, className=previewClassname, mirror=true) {\n\t\tthis.removeHighlightsPoints(planeName, className, mirror);\n\n\t\tif (! this.plane(planeName)?.highlight) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.pointTrack(planeName, pointName)?.classList.add(className);\n\t\tthis.pointPanel(planeName, pointName)?.classList.add(className);\n\n\t\tif ( (mirror) && (this.mirroredInController()) ) {\n\t\t\tconst globalController = document.CPU.globalController;\n\t\t\tconst on = this.isController ? findCPU(globalController.audiotag) : globalController;\n\t\t\ton.highlightPoint(planeName, pointName, className, false);\n\t\t}\n\t},\n\n};\n\nexport default planes_draw;","import __ from './primitives/i18n.js';\nimport { planeAndPointNamesFromId } from './component/planename.js';\nimport { activecueClassname } from './component_cpu/planes_draw.js';\n\n// plane for _playlist. Only used in <CPU-Controller>\nexport const plane_playlist = '_playlist';\n\n/**\n * @private\n */\nexport function addToPlaylist(audiotag) {\n\tif (typeof(audiotag.dataset.playlist) === 'string') {\n\t\tconst playlist_name = audiotag.dataset.playlist;\n\t\tif (!(playlist_name in document.CPU.playlists)) {\n\t\t\tdocument.CPU.playlists[playlist_name] = [];\n\t\t}\n\t\tdocument.CPU.playlists[playlist_name].push(audiotag.id);\n\n\t\t// refresh controller playlist if any\n\t\tconst globalController = document.CPU.globalController;\n\t\tif ((globalController) && (playlist_name === document.CPU.currentPlaylistID())) {\n\t\t\tbuildPlaylist();\n\t\t}\n\t}\n}\n\n/**\n * @private\n */\nexport function removeOfPlaylists({id}) {\n\t// Is it the good place to remove the playlist reference ?\n\tconst playlists = document.CPU.playlists;\n\tconst currentPlaylistID = document.CPU.currentPlaylistID();\n\tlet redraw = false;\n\t// remove reference in playlists\n\tfor (const index in playlists) {\n\t\tconst previous_length = playlists[index].length;\n\t\tconst out = playlists[index].filter(entry_id => ((entry_id !== id) && (document.getElementById(entry_id)) ));\n\t\tif ( (previous_length !== out.length) && (index === currentPlaylistID)) {\n\t\t\tredraw = true;\n\t\t}\n\t\tdocument.CPU.playlists[index] = out;\n\t\tif (out.length === 0) {\n\t\t\tdelete document.CPU.playlists[index];\n\t\t}\n\t}\n\tif (redraw) {\n\t\tbuildPlaylist();\n\t}\n}\n\n/**\n * @private\n */\nexport function rePointsPlaylist() {\n// TODO check if focus in playlist pane\n\tconst globalController = document.CPU.globalController;\n\tif (!globalController) {\n\t\treturn;\n\t}\n\tconst current_playlist = globalController.current_playlist;\n\tconst pointDataGroup = {};\n\tglobalController.clearPlane(plane_playlist);\n\tif (globalController.current_playlist.length === 0) {\n\t\t// remove plane to hide panel. Yes, overkill\n\t\tglobalController.removePlane(plane_playlist);\n\t\treturn;\n\t}\n\n\tfor (const audiotag_id of current_playlist) {\n\t\tpointDataGroup[audiotag_id] = {\n\t\t\ttext : document.getElementById(audiotag_id)?.dataset.title, // TODO \"untitled\"\n\t\t\tlink : `#${audiotag_id}&t=0`\n\t\t};\n\t}\n\tglobalController.bulkPoints(plane_playlist, pointDataGroup);\n\t// move _playlist on top. Hoping it will insert it RIGHT AFTER the main element.\n\tglobalController.element.shadowRoot.querySelector('main').insertAdjacentElement(\n\t\t'afterend', globalController.planePanel(plane_playlist) );\n// TODO restore focus if was in playlist pane\n}\n\n/**\n * @summary Builds or refresh the playlist panel.\n Should be called only for <cpu-controller>\n * @private was public\n *\n * @param {Object} \tcontainer \t\t<cpu-controller>.CPU\n */\nexport function buildPlaylist(wasFocusedId) {\n\tconst globalController = document.CPU.globalController;\n\tif ((!globalController) || (!globalController.isController)) {\n\t\t// Note that ONLY the global controller will display the playlist. For now.\n\t\treturn;\n\t}\n\n\tconst previous_playlist = globalController.current_playlist;\n\tglobalController.current_playlist = document.CPU.currentPlaylist();\n\n\tif (! globalController.plane(plane_playlist)) {\n\t\tglobalController.addPlane(plane_playlist, {\n\t\t\ttitle \t\t: __['playlist'],\n\t\t\ttrack \t\t: false,\n\t\t\tpanel \t\t: 'nocuetime',\n\t\t\thighlight \t: true,\n\t\t\t_comp \t\t: true \t\t\t\t// data stored on CPU-Controller ONLY\n\t\t});\n\t}\n\n\tif (previous_playlist !== globalController.current_playlist) {\n\t\trePointsPlaylist();\n\t}\n\n\tglobalController.highlightPoint(plane_playlist, globalController.audiotag.id, activecueClassname);\n\n\tif (wasFocusedId) {\n\t\t// we need to give back focus to the points, as they disapeared\n\t\tconst {planeName, pointName} = planeAndPointNamesFromId(wasFocusedId);\n\t\tglobalController.focusPoint(planeName, pointName);\n\t}\n}","import { findCPU } from '../primitives/utils.js';\nimport { oncePassiveEvent } from '../primitives/events.js';\nimport { warn } from '../primitives/console.js';\n\nimport { switchControllerTo } from '../cpu_controller.class.js';\n\n// @private\nexport let lastPlayError = false;\n// @private\nexport let timecodeStart = 0;\n// @private \nexport let timecodeEnd = false;\n\nconst NotAllowedError = 'Auto-play prevented : Browser requires a manual interaction first.';\nconst NotSupportedError = 'The browser refuses the audio source, probably due to audio format.';\n\n/**\n * @summary Store last audiotag error\n */\nexport function setPlayError(message) {\n\tlastPlayError = message;\n}\n\n/**\n * @summary Do pause\n *\n * @param {Object|undefined|null} event The event, may be omitted\n * @param {Element|undefined|null} audiotag The audiotag, if omitted, will be event's target\n */\nexport function pause(event = null, audiotag = null) {\n\tif (!audiotag) {\n\t\tconst {target} = event;\n\t\taudiotag = (target.tagName == 'AUDIO') ? target : findCPU(target).audiotag;\n\t}\n\taudiotag.pause();\n\tdocument.CPU.currentAudiotagPlaying = null;\n\twindow.localStorage.removeItem(audiotag.currentSrc);\n}\n\n/**\n * @summary Change referenced playing audio, pause the previous one\n *\n * @param {Object} event The event\n */\nexport function playOnce({target}) {\n\tconst document_cpu = document.CPU;\n\t// target, aka audiotag\n\tdocument_cpu.lastUsed = target;\n\n\tif ( \n\t\t(document_cpu.playStopOthers) && \n\t\t(document_cpu.currentAudiotagPlaying) && \n\t\t(!document_cpu.isAudiotagPlaying(target)) \n\t\t) {\n\t\tpause(undefined, document_cpu.currentAudiotagPlaying);\n\t}\n\tdocument_cpu.currentAudiotagPlaying = target;\n}\n\n/**\n * @summary If playing media was prevented by browser due to missing focus, event on focus does unlock player\n * @private\n *\n * @param {Object|undefined} \t\tevent \tUnlocking event\n * @param {HTMLAudioElement|null} audiotag \tThe audiotag to start playing, event's target if not defined\n */\nfunction playOnceUnlock(event, audiotag) {\n\tlastPlayError = false;\n\tif (document.CPU.autoplay) {\n\t\tplay(event, audiotag);\n\t}\n}\n\n/**\n * @summary Do play an audio tag\n *\n * @param {Object|undefined|null} event The event, may be mocked or ommitted\n * @param {Element|undefined|null} audiotag The audiotag\n */\nexport function play(event=null, audiotag=null) {\n\tif ( (!event) && (lastPlayError)) {\n\t\twarn(`play() prevented because already waiting for focus`);\n\t\treturn;\n\t}\n\taudiotag = audiotag ?? findCPU(event.target).audiotag;\n\tlastPlayError = false;\n\tremoveTimecodeOutOfBorders(audiotag.currentTime);\n\tlet promised = audiotag.play();\n\tif (promised) {\n\t\tpromised.then(\n\t\t\t() => {\n\t\t\t\t// we have a successful play occured, we can display wait event later\n\t\t\t\tdocument.CPU.hadPlayed = true;\n\t\t\t}\n\t\t).catch(\n\t\t\terror => {\n\t\t\t\tlastPlayError = true;\n\t\t\t\tconst unlock = () => { playOnceUnlock(event, audiotag); };\n\t\t\t\tswitch (error.name) {\n\t\t\t\t\tcase 'NotAllowedError':\n\t\t\t\t\t\twarn(NotAllowedError);\n\t\t\t\t\t\tdocument.addEventListener('focus', unlock, oncePassiveEvent);\n\t\t\t\t\t\tdocument.addEventListener('click', unlock, oncePassiveEvent);\n\n\t\t\t\t\t\tif (audiotag._CPU_played != null) {\n\t\t\t\t\t\t\tlet CPU_api = findCPU(audiotag);\n\t\t\t\t\t\t\tCPU_api.glowBeforePlay = true;\n\t\t\t\t\t\t\tCPU_api.setAct('glow');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'NotSupportedError':\n\t\t\t\t\t\terror(NotSupportedError);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t);\n\t}\n\tswitchControllerTo(audiotag);\n}\n\n/**\n * @summary Switch a mediatag between playing or paused\n * @private\n *\n * @param {number} at timecode position\n */\nexport function toggleplay({target}) {\n\tconst { audiotag } = findCPU(target);\n\taudiotag.paused ?\n\t\tplay(null, audiotag) :\n\t\tpause(null, audiotag);\n}\n\n/**\n * @summary If audio position out of begin/end borders, remove borders\n * @private\n *\n * @param {number} at timecode position\n */\nfunction removeTimecodeOutOfBorders(at) {\n\tif (\n\t\t(at < timecodeStart)\n\t\t|| ((timecodeEnd !== false) && (at > timecodeEnd)) \n\t\t) {\n\t\ttimecodeStart = 0;\n\t\ttimecodeEnd = false;\n\t}\n}\n\n/**\n * @summary Timecode border setter\n * @private\n *\n * @param {number} _timecodeStart timecode start position\n * @param {number} _timecodeEnd timecode end position\n */\nexport function setTimecodes(_timecodeStart, _timecodeEnd) {\n\ttimecodeStart = _timecodeStart;\n\ttimecodeEnd = _timecodeEnd;\n}","import { findCPU } from '../primitives/utils.js';\n\nimport { isAudiotagStreamed, audiotagDuration, uncertainDuration, normalizeSeekTime } from '../mediatag/time.js';\nimport { audiotagPreloadMetadata } from '../mediatag/extension.js';\nimport { pause, play } from '../mediatag/actions.js';\n\n\n/**\n * @summary Change play position of a audio tag\n *\n * @param {Object} event The calling event, may be mocked\n */\nexport function throbble(event) {\n\tconst {target, offsetX, at} = event;\n\tconst DocumentCPU = document.CPU;\n\tconst elCPU = findCPU(target);\n\tconst audiotag = elCPU.audiotag;\n\t// We know the media length, because the event is faked → normal execution. \n\tif (at >= 0) {\n\t\tDocumentCPU.seekElementAt(audiotag, at);\n\t\treturn;\n\t}\n\t// Else : normal trigger usage, via an event\n\n\tconst ratio = offsetX / target.clientWidth;\n\tconst duration = audiotagDuration(audiotag); // we get the real or supposed duration\n\n\tif ((DocumentCPU.currentAudiotagPlaying) && (!DocumentCPU.isAudiotagPlaying(audiotag))) {\n\t\t// Chrome needs to STOP any other playing tag before seeking\n\t\t// Very slow seeking on Chrome #89\n\t\tpause(null, DocumentCPU.currentAudiotagPlaying);\n\t}\n\n\t// we may have improper duration due to a streamed media, so let's start directly !\n\tplay(event, audiotag);\n\tif (uncertainDuration(duration)) {\n\t\t// Correct play from position on the timeline when metadata not preloaded #88\n\t\t// indicate we are loading something. We set a full width bar\n\t\telCPU.updateLoading(undefined, 100);\n\t\treturn;\n\t}\n\tDocumentCPU.seekElementAt(audiotag, ratio * duration);\n}\n\n/**\n * @summary Update throbber position when hovering the timeline interface\n *\n * @param {Object} event The calling event\n */\nexport function hover(event) {\n\tconst {target, clientX, targetTouches} = event;\n\tif (!target) {\n\t\t// pointerenter event may be fired without target. Strange for a pointer\n\t\treturn;\n\t}\n\tconst container = findCPU(target);\n\tconst audiotag = container.audiotag;\n\tconst duration = audiotagDuration(audiotag);\n\tif (uncertainDuration(duration)) {\n\t\tif (!isAudiotagStreamed(audiotag)) {\n\t\t\taudiotagPreloadMetadata(audiotag, hover, event);\n\t\t}\n\t\treturn;\n\t}\n\tconst {x, width} = container.shadowId('time').getBoundingClientRect();\n\t// clientX - x ⇒ x position of cursor in the #time element \n\t// Xoffset / width ⇒ ratio in the timeline\n\tconst ratio = ((clientX ?? targetTouches?.[0]?.clientX) - x) / width;\n\t// ratio * duration = time position in the audio\n\tcontainer.showThrobberAt(normalizeSeekTime(audiotag, ratio * duration));\n}\n\n/**\n * @summary Hide the throbber when leaving the timeline interface\n *\n * @param {Object} event The calling event\n */\nfunction out({target}) {\n\tfindCPU(target).hideThrobber();\n}\n\nexport const throbber = {\n\tthrobble,\n\thover,\n\tout\n};\n\nexport default throbber;","import { findCPU } from '../primitives/utils.js';\n\nimport { normalizeSeekTime } from '../mediatag/time.js';\nimport { pause, toggleplay } from '../mediatag/actions.js';\n\nimport { throbble } from './throbber.js';\nimport { restart } from './fine_nav.js';\n\n\nexport const KEY_LEFT_ARROW = 37;\nexport const KEY_RIGHT_ARROW = 39;\n\n/**\n * @summary Interprets pressed key\n *\n * @param {Object} event The event\n * @param {number} mult Multiply the keypressed act, 1 by default\n */\nexport function key(event, mult=1) {\n\t// do not interpret key when there is a modifier, for not preventing browsers shortcuts\n\tif (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {\n\t\treturn;\n\t}\n\n\tconst container = findCPU(event.target);\n\tconst { audiotag } = container;\n\t/** @param {number} seconds Relative position fowards */\n\tfunction seek_relative(seconds) {\n\t\tevent.at = normalizeSeekTime(audiotag, audiotag.currentTime + seconds);\n\t\tcontainer.showThrobberAt(event.at);\n\t\tthrobble(event);\n\t\tcontainer.hideThrobberLater();\n\t}\n\n\tswitch (event.keyCode) {\n\t\tcase 13 : // enter : standard usage, except if focus is #control\n\t\t\tif (container.focused()?.id.toLowerCase() !== 'control') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\ttoggleplay(event);\n\t\t\tbreak;\n\t\tcase 27 : // esc\n\t\t\trestart(event);\n\t\t\tpause(null, audiotag);\n\t\t\tbreak;\n\t\tcase 32 : // space\n\t\t\ttoggleplay(event);\n\t\t\tbreak;\n\t\t// pageUp 33\n\t\t// pageDown 34\n\t\tcase 35 : // end\n\t\t\tdocument.CPU.seekElementAt(audiotag, audiotag.duration);\n\t\t\tbreak;\n\t\tcase 36 : // home\n\t\t\trestart(event);\n\t\t\tbreak;\n\t\tcase KEY_LEFT_ARROW : // ←\n\t\t\tseek_relative(- (document.CPU.keymove * mult));\n\t\t\tbreak;\n\t\tcase KEY_RIGHT_ARROW : // →\n\t\t\tseek_relative(+ (document.CPU.keymove * mult));\n\t\t\tbreak;\n\t\tcase 38 : // ↑\n\t\t\tcontainer.prevFocus(); // ≠ trigger.prevcue(event);\n\t\t\tbreak;\n\t\tcase 40 : // ↓ \n\t\t\tcontainer.nextFocus(); // ≠ trigger.nextcue(event);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\treturn ;\n\t}\n\tevent.preventDefault?.();\n}\n\n\nexport const trigger_key = { key };\n\nexport default trigger_key;","import { findCPU } from '../primitives/utils.js';\n\nimport { key, KEY_LEFT_ARROW, KEY_RIGHT_ARROW } from './key.js';\n\n\n/**\n * @summary Pressing restart button, Rewind at start the audio tag\n *\n * @param {Object} event The event\n */\nexport function restart({target}) {\n\tconst container = findCPU(target);\n\tdocument.CPU.seekElementAt(container.audiotag, 0);\n}\n\n\nexport const fine_nav = {\n\n\trestart,\n\n\t/**\n\t * @summary Pressing reward button\n\t *\n\t * @param {Object} event The event\n\t */\n\treward : function(event) {\n\t\t// NEVER try to use a {...event, keyCode:} notation for extending an event : it kills the event.target\n\t\tevent.keyCode = KEY_LEFT_ARROW;\n\t\tkey(event);\n\t},\n\t/**\n\t * @summary Pressing foward button\n\t * Function associated, see below, DO NOT RENAME\n\t *\n\t * @param {Object} event The event\n\t */\n\tfoward : function(event) {\n\t\tevent.keyCode = KEY_RIGHT_ARROW;\n\t\tkey(event);\n\t},\n\t/**\n\t * @summary Pressing fastreward button\n\t * Function associated, see below, DO NOT RENAME\n\t *\n\t * @param {Object} event The event\n\t */\n\tfastreward : function(event) {\n\t\tevent.keyCode = KEY_LEFT_ARROW;\n\t\tkey(event, document.CPU.fastFactor);\n\t},\n\t/**\n\t * @summary Pressing fastfoward button\n\t * Function associated, see below, DO NOT RENAME\n\t *\n\t * @param {Object} event The event\n\t */\n\tfastfoward : function(event) {\n\t\tevent.keyCode = KEY_RIGHT_ARROW;\n\t\tkey(event, document.CPU.fastFactor);\n\t},\n};\n\nexport default fine_nav;","import { timeInSeconds } from '../primitives/convert.js';\n\nimport { setTimecodes } from '../mediatag/actions.js';\n\nimport { buildPlaylist } from '../build_playlist.js';\n\n\n/**\n * @summary Interprets the hash part of the URL, when loaded or changed\n * @package\n *\n * still exposed in public for tests\n *\n * @param {string|Object} hashcode Called hashcode\n * @param {Function|null} callback_fx When done, call a function (optional, to end the tests).\n */\nexport async function hashOrder(hashcode, callback_fx = null) {\n\tlet at_start = true;\n\tif (typeof hashcode !== 'string') {\n\t\tat_start = 'at_start' in hashcode;\n\t\thashcode = location.hash.substr(1);\n\t}\n\tlet hash = null;\n\tlet timecode = '';\n\tlet autoplay = false;\n\n\t/*\n\t// watch out to NOT use URLSearchParams too fast ! \n\tfor (const [p_key, p_value] of URLSearchParams.searchParams.entries(hashcode) ) {\n\t\tif (p_value === '') {\n\t\t\t// should reference to the ID of the element\n\t\t\thash = hash ?? p_key;\n\t\t} else {\n\t\t\tswitch (p_key.toLowerCase()) {\n\t\t\t\tcase 't':\n\t\t\t\t\t// is a time index\n\t\t\t\t\ttimecode = p_value || '0';\n\t\t\t\t\t// we make autoplay at requested timecode, simplier of the user\n\t\t\t\t\tautoplay = true;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'autoplay':\n\t\t\t\t\t// is a card from a social network, run now\n\t\t\t\t\tautoplay = p_value === '1';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'auto_play':\n\t\t\t\t\t// is a card from a social network, run now\n\t\t\t\t\tautoplay = p_value.toLowerCase() === 'true';\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t*/\n\t\n\t// legacy\n\tfor (const parameter of hashcode.split('&')) {\n\t\tif (!parameter.includes('=')) {\n\t\t\t// should reference to the ID of the element\n\t\t\thash = hash ?? parameter;\n\t\t} else {\n\t\t\t// should be a key=value parameter\n\t\t\tconst [p_key, p_value] = parameter.split('=');\n\t\t\tswitch (p_key.toLowerCase()) {\n\t\t\t\tcase 't':\n\t\t\t\t\t// is a time index\n\t\t\t\t\ttimecode = p_value || '0';\n\t\t\t\t\t// we make autoplay at requested timecode, simplier of the user\n\t\t\t\t\tautoplay = true;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'autoplay':\n\t\t\t\t\t// is a card from a social network, run now\n\t\t\t\t\tautoplay = p_value === '1';\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'auto_play':\n\t\t\t\t\t// is a card from a social network, run now\n\t\t\t\t\tautoplay = p_value.toLowerCase() === 'true';\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif ((timecode === '') || ((at_start) && (!autoplay))) {\n\t\t// this is a normal anchor call. Go back to normal behaviour\n\t\tcallback_fx?.();\n\t\treturn /* false */;\n\t}\n\n\t// we may have a begin,end notation\n\tconst [timecode_start, timecode_end] = timecode.split(',');\n\tlet _timecodeStart = timeInSeconds(timecode_start);\n\tlet _timecodeEnd = timecode_end !== undefined ? timeInSeconds(timecode_end) : false;\n\tif (_timecodeEnd !== false) {\n\t\t_timecodeEnd = (_timecodeEnd > _timecodeStart) ?\n\t\t\t_timecodeEnd :\n\t\t\tfalse;\n\t}\n\tsetTimecodes(_timecodeStart, _timecodeEnd);\n\n\t// scroll to the audio element. Should be reworked, or parametrable , see issue #60\n\tif (document.CPU.scrollTo) {\n\t\t// if the hash was not found, rely on the actual player\n\t\t( \n\t\t\t(hash?.length > 0) ? document.querySelector(`#${hash}`) : document.CPU.currentAudiotagPlaying\n\t\t)?.closest('cpu-audio, cpu-controller').scrollIntoView();\n\t}\n\n\tawait document.CPU.jumpIdAt( hash??'', timecode_start, callback_fx);\n\n\t// not in document.CPU (yet) to avoid unuseful repaint\n\tbuildPlaylist();\n}\n\nexport const hash_order = {\n\thashOrder\n};\n\nexport default hash_order;","import { findCPU } from '../primitives/utils.js';\nimport { warn } from '../primitives/console.js';\n\nimport { play } from '../mediatag/actions.js';\n\n\n/**\n * @summary Common code for trigger.prevtrack and trigger.nexttrack\n *\n * @param {HTMLAudioElement} \taudiotag \tThe audiotag we're leaving\n * @param {Number}\t\t\t \toffset \tThe offset to apply on the index\n */\nfunction playRelativeTrackInPlaylist(audiotag, offset) {\n\tconst {id} = audiotag;\n\n\tconst playlist_name = audiotag.dataset.playlist;\n\tif (!playlist_name) {\n\t\t// should I test strict ? We may have a funnily 'undefined' named playlist ;)\n\t\treturn;\n\t}\n\n\t// and is in a declarated playlist\n\tconst playlist = document.CPU.playlists[playlist_name];\n\tif (!playlist) { \n\t\twarn(`Named playlist ${playlist_name} not created. WTF ?`);\n\t\treturn;\n\t}\n\tconst playlist_index = playlist.indexOf(id);\n\tif (playlist_index < 0) {\n\t\twarn(`Audiotag ${id} not in playlist ${playlist_name}. WTF ?`);\n\t\treturn;\n\t}\n\n\tconst next_id = playlist[playlist_index + offset];\n\tif (!next_id) {\n\t\t// out of playlist\n\t\treturn;\n\t}\n\n\tconst next_audiotag = /** @type {HTMLAudioElement} */ (document.getElementById(next_id));\n\tif (!next_audiotag) {\n\t\twarn(`Audiotag #${next_id} doesn't exists. WTF ?`);\n\t\treturn;\n\t}\n\t// Play the next media in playlist, starting at zero\n\tdocument.CPU.seekElementAt(next_audiotag, 0);\n\tplay(null, next_audiotag);\n}\n\nexport const track = {\n\t/**\n\t * @summary When #prevtrack button is clicked, go back in playlist\n\t *\n\t * @param {Object} \t\t\t\t\t\t\tevent The event\n\t * @param {HTMLAudioElement|null|undefined} \taudiotag The audiotag, mays be omitted, will be calculated from event\n\t */\n\tprevtrack : function({target}, audiotag = null) {\n\t\tplayRelativeTrackInPlaylist(audiotag ?? findCPU(target).audiotag, -1);\n\t},\n\n\t/**\n\t * @summary When an audiotag is ended, advance in playlist. Also when #nexttrack button clicked\n\t *\n\t * @param {Object} \t\t\t\t\t\t\tevent The event\n\t * @param {HTMLAudioElement|null|undefined} \taudiotag The audiotag, mays be omitted, will be calculated from event\n\t */\n\tnexttrack : function({target}, audiotag = null) {\n\t\tplayRelativeTrackInPlaylist(audiotag ?? findCPU(target).audiotag, +1);\n\t},\t\n};\n\nexport default track;","import { isAudiotagStreamed } from '../mediatag/time.js';\nimport { pause, timecodeEnd } from '../mediatag/actions.js';\n\nimport { updateAudiotag } from '../mediatag/extension.js';\n\n/**\n * @summary Updatting time position. Pause the playing element if a end position was defined\n *\n * @param {Object} event The event\n */\nexport function update({target:audiotag}) {\n\tif ((timecodeEnd !== false) && (audiotag.currentTime > timecodeEnd)) {\n\t\tpause(undefined, audiotag);\n\t}\n\n\tupdateAudiotag(audiotag);\n\tif ((!audiotag.paused) && (!isAudiotagStreamed(audiotag))) {\n\t\twindow.localStorage.setItem(audiotag.currentSrc, String(audiotag.currentTime));\n\t}\n}\n\nexport const trigger_update = {\n\tupdate\n};\n\n\nexport default trigger_update;","import { findCPU } from '../primitives/utils.js';\nimport { passiveEvent, oncePassiveEvent } from '../primitives/events.js';\nimport { browserIsDecent } from '../primitives/checkers.js';\n\nimport { isAudiotagStreamed } from './time.js';\nimport { lastPlayError } from './actions.js';\n\nimport trigger from '../trigger/trigger.js';\nimport { addToPlaylist } from '../build_playlist.js';\n\n// Indicate if media element was already played, and so is prone to re-autoplay later\n// null or undefined if not yet connected to cpu-audio.js\n// false if connected but not played yet\n// true if connected and already played once\nHTMLAudioElement.prototype._CPU_played = null;\n\n// Support for planes and points. Changed to {} at webcomponent instantiation\nHTMLAudioElement.prototype._CPU_planes = null;\n\n\n/**\n * @summary At start, will start the last playing <audio> tag at its last known position\n *\n * @param {Object} event The event\n */\nfunction recallStoredPlay(event) {\n\tlet audiotag = event.target;\n\tif ((document.CPU.currentAudiotagPlaying !== null) || (isAudiotagStreamed(audiotag))) {\n\t\treturn;\n\t}\n\tlet lasttimecode = Number(window.localStorage.getItem(audiotag.currentSrc));\n\t// TODO and no hashed time\n\tif ((lasttimecode > 0) && (!lastPlayError)) {\n\t\tdocument.CPU.seekElementAt(audiotag, lasttimecode);\n\t\ttrigger.play(null, audiotag);\n\t}\n}\n\n// used for addIdToAudiotag , when tag was not named in HTML or DOM\nlet\tcount_element = 0;\n\n/**\n * @summary Adds an identifier to audiotag at build time.\n * @private\n */\nexport function\taddIdToAudiotag(audiotag) {\n\taudiotag.id = audiotag.id || `${document.CPU.IDPrefix}${count_element++}`;\n}\n\n/**\n * @summary Force <audio> to preload its metadata, and so its duration, then call the callback() with the event parameter\n * @private\n *\n * @param {HTMLAudioElement}\taudiotag The playing <audio> tag\n * @param {function}\t\t\tcallback \tOnce metadata loaded, function to callback\n * @param \t\t{any}\t\t\t\tevent \t\t...with it main parameter, usually an event\n */\nexport function audiotagPreloadMetadata(audiotag, callback=null, event=null) {\n\tif (!audiotag) {\n\t\treturn;\n\t}\n\tif (audiotag.readyState > audiotag.HAVE_NOTHING) {\n\t\tcallback?.(event);\n\t\treturn;\n\t}\n\t// loading metadata. May not work on Apples : 'loadedmetadata'\n\tif (callback) {\n\t\taudiotag.addEventListener(\n\t\t\t'loadedmetadata',\n\t\t\t() => callback?.(event),\n\t\t\toncePassiveEvent\n\t\t);\n\t}\n\t\n\t//audiotag.setAttribute('preload', 'metadata');\n\taudiotag.load();\n}\n\n/**\n * @summary Attach events on a <audio> tag\n *\n * @param {HTMLAudioElement} audiotag The audiotag\n */\nexport function attach_events_audiotag(audiotag) {\n\taudiotag.addEventListener('loadedmetadata', recallStoredPlay, oncePassiveEvent);\n\taudiotag.addEventListener('play', trigger.playOnce, passiveEvent);\n\taudiotag.addEventListener('ended', trigger.nexttrack, passiveEvent);\n\t// those ↓ for PHRACKING SAFARI\n\taudiotag.addEventListener('ready', recallStoredPlay, passiveEvent);\n\taudiotag.addEventListener('canplay', recallStoredPlay, passiveEvent);\n\n\t// see https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events for list of events\n\tfor (const on of [\n\t\t'ready', 'load', 'loadeddata', 'canplay', 'abort',\n\t\t'error', 'emptied',\n\t\t'play', 'playing', 'pause', 'ended',\n\t\t'durationchange', 'loadedmetadata', 'timeupdate', 'waiting'\n\t]) {\n\t\taudiotag.addEventListener(on, trigger.update, passiveEvent);\n\t}\n\n\tif (!browserIsDecent) {\n\t\t// in case we are in legacy mode\n\t\tfor (const on of ['pause', 'ended']) {\n\t\t\taudiotag.addEventListener(on, trigger.pause, passiveEvent);\n\t\t}\n\t}\n\n\t// ask ASAP metadata about media\n\tif (audiotag.getAttribute('preload') === '') {\n\t\taudiotagPreloadMetadata(audiotag);\n\t}\n}\n\n/**\n * @summary Trigger display updates in the interface\n * @private\n * @param {HTMLAudioElement} \taudiotag \t\tTag to refresh interface\n */\nexport function updateAudiotag(audiotag) {\n\tfindCPU(audiotag)?.update();\n\tdocument.CPU.globalController?.update();\n}\n\n/**\n * @summary Connects an audiotag to CPU APIs, launched at start or when the webcomponent appears\n *\n * @param {HTMLAudioElement} audiotag The audiotag\n */\nexport function connectAudiotag(audiotag) {\n\tif (audiotag._CPU_played != null) {\n\t\treturn;\n\t}\n\taudiotag._CPU_played = false;\n\n\tattach_events_audiotag(audiotag);\n\n\t// hide native controls\n\taudiotag.hidden = true; \n\t// PHRACK SAFARI // may be we should remove upper line ?\n\taudiotag.removeAttribute('controls');\n\n\t// playlist\n\taddToPlaylist(audiotag);\n}\n\n","import { pause, playOnce, play, toggleplay, timecodeEnd } from '../mediatag/actions.js';\n\nimport fine_nav from './fine_nav.js';\nimport hash_order from './hash_order.js';\nimport throbber from './throbber.js';\nimport trigger_key from './key.js';\nimport cue from './cue.js';\nimport track from './track.js';\nimport trigger_update from './update.js';\n\n\nexport const trigger = {\n\t...hash_order,\n\t...fine_nav,\n\t...throbber,\n\t...trigger_key,\n\t...trigger_update,\n\t...cue,\n\t...track,\n\tpause,\n\tplayOnce,\n\tplay,\n\ttoggleplay,\n\n\t// @private Needed for tests\n\t_end : () => timecodeEnd,\n\n};\n\nexport default trigger;","import { findCPU } from '../primitives/utils.js';\n\nlet ev = null;\n\n/**\n * @summary Action on a pointerdown Event\n *\n * @param {Object} \t\t\t\t\t\t\tevent The event\n */\nexport function down({target}) {\n\tev = setTimeout(act, document.CPU.alternateDelay, findCPU(target));\n}\n\n/**\n * @summary Repeated action during the pointer pressed\n *\n * @param {Object} \t\t\t\t\t\t\tComponent.CPU Active component under the pointer\n */\nfunction act(elCPU) {\n\telCPU.showHandheldNav();\n\tev = null;\n}\n\n/**\n * @summary Action for the release of the pointer\n */\nexport function up() {\n\tclearTimeout(ev);\n\tev = null;\n}\n\nexport const timebar_finger_manager = {\n\tdown,\n\tact,\n\tup\n};\n\nexport default timebar_finger_manager;","import trigger from '../trigger/trigger.js';\n\n\n// Repeated event allocation\nlet pressing = null;\nexport const acceptable_press_actions = ['fastreward', 'reward', 'foward', 'fastfoward'];\n\n/**\n * @summary Start handheld navigation button press\n * @private\n *\n * @param {Object} event The event\n */\nexport function press(event) {\n\tconst target = event.target.id ? event.target : event.target.closest('button');\n\tif ( (!target.id) || (!acceptable_press_actions.includes(target.id))) {\n\t\t// we have been misleaded\n\t\treturn;\n\t}\n\t// execute the associated function\n\ttrigger[target.id](event);\n\tif (pressing) {\n\t\twindow.clearTimeout(pressing);\n\t}\n\tpressing = window.setTimeout(repeat, document.CPU.repeatDelay, event);\n\tevent.preventDefault();\n}\n\n/**\n * @summary Repeat during pressing handheld navigation button\n * @private\n *\n * @param {Object} event The event\n */\nexport function repeat(event) {\n\ttrigger[event.target.id](event);\n\t// next call : repetition are closest\n\tpressing = window.setTimeout(repeat, document.CPU.repeatFactor, event);\n\tevent.preventDefault?.();\n}\n\n/**\n * @summary Release handheld navigation button\n * @private\n *\n * @param {Object} event The event\n */\nexport function release(event) {\n\twindow.clearTimeout(pressing);\n\tpressing = null;\n\tevent.preventDefault();\n}\n\n// Handheld navigation button process\n// @private\nexport const finenav_finger_manager = {\n\tpress,\n\trepeat,\n\trelease\n};\n\nexport default finenav_finger_manager;","import { findCPU } from './primitives/utils.js';\nimport { passiveEvent, oncePassiveEvent, preventLinkOnSamePage } from './primitives/events.js';\nimport { audiotagPreloadMetadata } from './mediatag/extension.js';\n\nimport { down, up } from './component/timebar_finger_manager.js';\nimport { acceptable_press_actions, press, release } from './component/finenav_finger_manager.js';\n\nimport trigger from './trigger/trigger.js';\nimport { buildChaptersLoader } from './build_chapters.js';\nimport { buildPlaylist } from './build_playlist.js';\n\n\n/**\n * @summary Interprets `navigator.share` native API\n *\n * @param {Object} event Activation event\n */\nfunction nativeShare(event) {\n\tconst {title, canonical} = findCPU(event.target).audiotagDataset();\n\tnavigator.share({\n\t\ttitle,\n\t\ttext\t: title,\n\t\turl \t: canonical\n\t});\n\tevent.preventDefault();\n}\n\n/**\n * @private, because called at start\n *\n * @param {Object} \t\t\telCPU <cpu-audio>.CPU\n *\n * @summary Builds the controller.\n */\nexport function buildInterface(elCPU) {\n\t// #interface SHOULD have a tabindex=\"-1\" attribute. This is mandatory for getting keyboard browsing. Any attempt to give it focus will focus #control or #toggleplay instead. \n\telCPU.container.addEventListener('focus', (event) => {\n\t\t(elCPU.shadowId('control') ?? elCPU.shadowId('toggleplay'))?.focus();\n\t\tevent.preventDefault();\n\t});\n\n\tconst { classList } = elCPU.container;\n\n\t// hide broken image while not loaded\n\telCPU.shadowId('poster')?.addEventListener('load', () => {\n\t\tclassList.add('poster-loaded');\n\t}, passiveEvent);\n\n\t// main buttons management\n\tconst cliquables = {\n\t\tpause : trigger.pause,\n\t\tplay : trigger.play,\n\t\ttime : trigger.throbble,\n\t\tactions : () => elCPU.showActions(),\n\t\tback : (event) => {elCPU.showMain(); event.preventDefault();},\n\t\tposter : () => elCPU.showMain(),\n\t\trestart : trigger.restart,\n\t\ttoggleplay : trigger.toggleplay,\n\t\tprevcue : trigger.prevcue,\n\t\tnextcue : trigger.nextcue,\n\t\tprevtrack : trigger.prevtrack,\n\t\tnexttrack : trigger.nexttrack,\n\t};\n\tfor (const [elementId, elementAction] of Object.entries(cliquables)) {\n\t\tconst el = elCPU.shadowId(elementId);\n\t\tel?.addEventListener('click', elementAction, el.tagName === 'A' ? {} : passiveEvent);\n\t}\n\n\t// relative browsing buttons management\n\t// *ward : handheld nav to allow long press to repeat action\n\tfor (const elementId of acceptable_press_actions) {\n\t\tconst button_element = elCPU.shadowId(elementId);\n\t\tif (button_element) {\n\t\t\tbutton_element.addEventListener('pointerdown', press);\n\t\t\tbutton_element.addEventListener('pointerout', release);\n\t\t\tbutton_element.addEventListener('pointerup', release);\n\t\t}\n\t}\n\n\t// keyboard management\n\telCPU.element.addEventListener('keydown', trigger.key);\n\n\t// throbber management\n\tconst timeline_element = elCPU.shadowId('time');\n\tif (timeline_element) {\n\t\ttimeline_element.addEventListener('pointerenter', trigger.hover, passiveEvent);\n\t\ttimeline_element.addEventListener('pointermove', trigger.hover, passiveEvent);\n\t\ttimeline_element.addEventListener('pointerout', trigger.out, passiveEvent);\n\t\ttimeline_element.addEventListener('pointerdown', down, passiveEvent);\n\t\ttimeline_element.addEventListener('pointerup', up, passiveEvent);\n\t}\n\n\tif (navigator.share) {\n\t\tclassList.add('hasnativeshare');\n\t\telCPU.shadowId('nativeshare')?.addEventListener('click', nativeShare, passiveEvent);\n\t}\n\n\tconst canonical_element = elCPU.shadowId('canonical'); \n\tif (canonical_element) {\n\t\tpreventLinkOnSamePage( canonical_element );\n\t}\n\n\tif (!elCPU.audiotag) {\n\t\t// <cpu-controller> without <cpu-audio> , see https://github.com/dascritch/cpu-audio/issues/91\n\t\treturn;\n\t}\n\n\telCPU.container.addEventListener('pointerenter', () => audiotagPreloadMetadata(elCPU.audiotag), oncePassiveEvent);\n\n\telCPU.audiotag.addEventListener('durationchange', () => elCPU.repositionTracks(), passiveEvent);\n\n\tbuildChaptersLoader(elCPU);\n\tbuildPlaylist();\n\telCPU.showMain();\n\telCPU.updatePlayButton();\n\telCPU.emitEvent('ready');\n\n\telCPU.updateLinks();\n\n}\n\nexport default buildInterface;","const head = document.head;\n\nexport const defaultDataset = {\n\tget title() {\n\t\tfor (const domain of ['property=\"og:title\"', 'name=\"twitter:title\"']) {\n\t\t\tconst header_element = head.querySelector(`meta[${domain}]`);\n\t\t\tif (header_element) {\n\t\t\t\treturn header_element.content;\n\t\t\t}\n\t\t}\n\t\tconst title = document.title;\n\t\treturn title === '' ? null : title;\n\t},\n\tget poster() {\n\t\tfor (const attr of ['property=\"og:image\"', 'name=\"twitter:image:src\"']) {\n\t\t\tconst header_element = head.querySelector(`meta[${attr}]`);\n\t\t\tif (header_element) {\n\t\t\t\treturn header_element.content;\n\t\t\t}\n\t\t}\n\t\treturn null;\n\t},\n\tget canonical() {\n\t\tconst header_element = head.querySelector('link[rel=\"canonical\"]');\n\t\tif (header_element) {\n\t\t\treturn header_element.href;\n\t\t}\n\t\treturn location.href.split('#')[0];\n\t},\n\tget twitter() {\n\t\tconst header_element = head.querySelector('meta[name=\"twitter:creator\"]');\n\t\tif ((header_element) && (header_element.content.length > 1)) {\n\t\t\treturn header_element.content;\n\t\t}\n\t\treturn null;\n\t},\n\tplaylist : null,\n\twaveform : null,\n\tduration : null,\n\tdownload : null\n};\n\nexport default defaultDataset;\n","import defaultDataset from '../bydefault/dataset.js';\n\n\nexport const utils = {\n\n\tattributesChanges : function() {\n\t\t// mode=\"\" attribute, on general aspect. may be coma separated\n\t\tlet mode = null;\n\t\tif (this.element.hasAttribute('mode')) {\n\t\t\tmode = this.element.getAttribute('mode');\n\t\t\t// in case of a mode=\"still,play\" declaration\n\t\t\tconst [mode_still, mode_play] = mode.split(',');\n\t\t\tif (mode_play) {\n\t\t\t\tmode = this.audiotag.paused ? mode_still : mode_play;\n\t\t\t\tthis.mode_when_play = mode_play;\n\t\t\t}\n\t\t}\n\t\tthis.setMode(mode);\n\n\t\t// hide=\"\" attribute, space separated elements to hide\n\t\tif (this.element.hasAttribute('hide')) {\n\t\t\tthis.setHide(this.element.getAttribute('hide').split(' '));\n\t\t}\n\n\t\t// TODO : waveform, poster, title, mirroring it to audiotag\n\t},\n\n\t/**\n\t * @summary Will get presentation data from <audio> or from parent document\n\t *\n\t * @package\n\t *\n\t * @return {Object} dataset\n\t */\n\taudiotagDataset : function () {\n\t\treturn {...defaultDataset, ...this.audiotag.dataset};\n\t},\n\n\t/**\n\t * @summary Check if the actual <cpu-audio> is mirrored in <cpu-controller>. False if no cpu-controller\n\t * @private but next time public ?\n\t *\n\t * @return boolean\t\t\tFalse if no cpu-controller or not mirrored\n */\n\tmirroredInController: function() {\n\t\tconst globalController = document.CPU.globalController;\n\t\treturn (globalController) && (this.audiotag.isEqualNode(globalController.audiotag));\n\t},\n\n\t/**\n\t * @summary create and fire custom events for the global document.\n\t * @private\n\t *\n\t * We async-ed it, to avoid ultra-probable performances issues\n\t *\n\t * @param {string} event_name The event name, will be prefixed with CPU_\n\t * @param {Object|undefined} detail Specific public informations about the event\n\t * @return {Promise} { description_of_the_return_value }\n\t */\n\temitEvent:async function(event_name, detail = undefined) {\n\t\tthis.element.dispatchEvent(\n\t\t\tnew CustomEvent(`CPU_${event_name}`, {\n\t\t\t\ttarget \t\t: this.element,\n\t\t\t\tbubbles \t: true,\n\t\t\t\tcancelable \t: false,\n\t\t\t\tcomposed \t: false,\n\t\t\t\tdetail \t\t: detail\n\t\t\t})\n\t\t);\n\t},\n\n\t/**\n\t * @summary et an Element from the shadowDOM by its id\n\t * @private\n\t *\n\t * @param {string} id \tidentification name of the element\n\t * @return {HTMLElement} { The expected element }\n\t */\n\tshadowId: function(id) {\n\t\treturn this.shadow.getElementById(id);\n\t},\n\t\n};\n\nexport default utils;\n","import { error } from '../primitives/console.js';\nimport __ from '../primitives/i18n.js';\n\nimport { addIdToAudiotag } from '../mediatag/extension.js';\n\nimport { validId } from '../component/planename.js';\n\nimport { update } from '../trigger/update.js';\n\n\n// Acceptables attributes values for hide=\"\" parameter on webcomponent\nexport const acceptableHideAtttributes = ['poster', 'actions', 'timeline', 'chapters', 'panels', 'panels-title', 'panels-except-play'];\n\n\nexport const status = {\n\n\t/**\n\t * @summary Used for `mode=\"\"` attribute.\n\t * @public\n\t *\n\t * @param {string|null} mode Accepted are only in `/\\w+/` format, 'default' by default\n\t */\n\tsetMode: function(mode = null) {\n\t\tmode = mode ?? 'default';\n\t\tif (this.mode_was === mode) {\n\t\t\treturn;\n\t\t}\n\t\tconst { classList } = this.container;\n\t\tclassList.remove(`mode-${this.mode_was}`);\n\t\tclassList.add(`mode-${mode}`);\n\t\tthis.mode_was = mode;\n\t},\n\t/**\n\t * @summary Change the presentation style reflecting the media tag status\n\t * @public\n\t *\n\t * @param {string} act can be 'loading', 'pause', 'glow' or 'play'\n\t */\n\tsetAct : function(act) {\n\t\tif (this.act_was === act) {\n\t\t\treturn;\n\t\t}\n\t\tif ( (! document.CPU.hadPlayed) && (act === 'loading') ){\n\t\t\tif (this.act_was !== null) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// correction for iOS, stuck in \"loading\" state at the beginning, see #138\n\t\t\tact = 'glow';\n\t\t}\n\t\tconst classes = this.container.classList;\n\t\tclasses.remove(\n\t\t\t'act-loading',\n\t\t\t'act-buffer',\n\t\t\t'act-pause',\n\t\t\t'act-play',\n\t\t\t'act-glow'\n\t\t\t);\n\t\tclasses.add(`act-${act}`);\n\t\tif ((this.act_was === 'play') && (act === 'loading')) {\n\t\t\tclasses.add(`act-buffer`);\n\t\t}\n\t\tthis.act_was = act;\n\t},\n\t/**\n\t * @public\n\t * @summary Hide some blocks in the interface\n\t * used for `hide=\"\"` attribute\n\t *\n\t * @param {Array<string>} hide_elements Array of strings, may contains\n\t * 'actions' or 'chapters'\n\t */\n\tsetHide : function(hide_elements) {\n\t\tconst container_class = this.container.classList;\n\n\t\tfor (const hide_this of acceptableHideAtttributes) {\n\t\t\tcontainer_class.remove(`hide-${hide_this}`);\n\t\t}\n\n\t\tfor (let hide_this of hide_elements) {\n\t\t\thide_this = hide_this.toLowerCase();\n\t\t\tif (acceptableHideAtttributes.includes(hide_this)) {\n\t\t\t\tcontainer_class.add(`hide-${hide_this}`);\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * @summary Complete the interface at build time\n\t * @package\n\t */\n\tcompleteTemplate: function() {\n\t\tconst dataset = this.audiotagDataset();\n\t\tlet { title, waveform } = dataset;\n\t\tconst element_canonical = this.shadowId('canonical');\n\t\tif (element_canonical) {\n\t\t\telement_canonical.href = dataset.canonical;\n\t\t\tlet classlist = element_canonical.classList;\n\t\t\tif (!title) {\n\t\t\t\tclasslist.add('untitled');\n\t\t\t\ttitle = __.untitled;\n\t\t\t} else {\n\t\t\t\tclasslist.remove('untitled');\n\t\t\t}\n\t\t\telement_canonical.innerText = title;\n\t\t}\n\n\t\tif (this.element.title !== title) {\n\t\t\tthis.element.title = title; // WATCHOUT ! May goes recursive with observers on the wbecomponent\n\t\t}\n\t\tconst poster = this.shadowId('poster');\n\t\tif (poster) {\n\t\t\tposter.src = dataset.poster || '';\n\t\t}\n\t\tconst time_element = this.shadowId('time');\n\t\tif (time_element) {\n\t\t\ttime_element.style.backgroundImage = waveform ? `url(${waveform})` : '';\n\t\t}\n\t\tthis.showMain();\n\t},\n\n\t/**\n\t * @summary Attach the audiotag to the API\n\t * @package\n\t *\n\t * @param {Element} audiotag The audiotag\n\t */\n\tattachAudiotagToInterface: function(audiotag) {\n\t\tif (!audiotag) {\n\t\t\treturn;\n\t\t}\n\t\tthis.audiotag = audiotag;\n\t\taddIdToAudiotag(audiotag);\n\t\tthis.completeTemplate();\n\n\t\t// throw simplified event\n\t\tupdate({target : audiotag});\n\t},\n\n\t\t/**\n\t * @summary Inject a <style> into the shadowDom.\n\t * @public\n\t *\n\t * Usage example in applications/chapters_editor.js\n\t *\n\t * @param \t{string} styleName \tA name in the range /[a-zA-Z0-9\\-_]+/, key to tag the created <style>\n\t * @param \t{string} css \t\t\tinline CSS to inject\n\t */\n\tinjectCss: function(styleName, css) {\n\t\tif (!styleName.match(validId)) {\n\t\t\terror(`injectCss invalid key \"${styleName}\"`);\n\t\t\treturn;\n\t\t}\n\n\t\tthis.removeCss(styleName);\n\t\tconst element = document.createElement('style');\n\t\telement.id = `style_${styleName}`;\n\t\telement.innerHTML = css;\n\t\tthis.container.appendChild(element);\n\t},\n\n\t/**\n\t * @summary Remove an injected <style> into the shadowDom\n\t * @public\n\t *\n\t * @param \t{string} styleName \tKey of the created <style> , /[a-zA-Z0-9\\-_]+/\n\t */\n\tremoveCss: function(styleName) {\n\t\tthis.shadowId(`style_${styleName}`)?.remove();\n\t}\n};\n\nexport default status;","import __ from '../primitives/i18n.js';\nimport { absolutizeUrl } from '../primitives/filters.js';\nimport { secondsInColonTime } from '../primitives/convert.js';\n\nimport { isAudiotagStreamed, audiotagDuration, uncertainDuration } from '../mediatag/time.js';\nimport { timecodeStart, timecodeEnd } from '../mediatag/actions.js';\n\nimport { showElement } from '../component/show.js';\n\nconst planeNameBorders = '_borders';\n\nexport const updates = {\n\n\t/**\n\t * @public\n\t * @summary update play/pause button according to media status\n\t */\n\tupdatePlayButton: function() {\n\t\tconst audiotag = this.audiotag;\n\t\tconst _attr = audiotag.getAttribute('preload');\n\t\tconst control_button = this.shadowId('control');\n\t\tconst aria = 'aria-label';\n\t\tlet _preload = _attr ? (_attr.toLowerCase() !== 'none') : true ;\n\t\tif (\n\t\t\t\t(audiotag.readyState < audiotag.HAVE_CURRENT_DATA ) &&\n\t\t\t\t((_preload) || (audiotag._CPU_played))\n\t\t\t) {\n\t\t\tthis.setAct('loading');\n\t\t\tcontrol_button.setAttribute(aria, __.loading);\n\t\t\treturn;\n\t\t}\n \t\t// warning : play/pause still inverted in \"__\"\n \t\tlet label = 'pause';\n\t\tlet will_act = 'play';\n\t\tif (audiotag.paused) {\n\t\t\tlabel = 'play';\n\t\t\twill_act = 'pause';\n\t\t\tif ((!audiotag._CPU_played) && (this.glowBeforePlay)) {\n\t\t\t\t// TODO check option\n\t\t\t\twill_act = 'glow';\n\t\t\t}\n\t\t}\n\n\t\tthis.setAct(will_act);\n\t\tcontrol_button.setAttribute(aria, __[label]);\n\t\tconst hide_panels_except_play_mark = 'last-used';\n\n\t\tconst container_class = this.container.classList;\n\t\tif (!audiotag.paused) {\n\t\t\taudiotag._CPU_played = true;\n\t\t\tcontainer_class.add(hide_panels_except_play_mark);\n\t\t\tif (this.mode_when_play) {\n\t\t\t\tthis.setMode(this.mode_when_play);\n\t\t\t\tthis.mode_when_play = null;\n\t\t\t}\n\t\t} else {\n\t\t\tif (! this.audiotag.isEqualNode(document.CPU.lastUsed)) {\n\t\t\t\tcontainer_class.remove(hide_panels_except_play_mark);\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * @summary Update time-line length\n\t * @private\n\t *\n\t * @param {number} \t\t\t\t\tseconds The seconds\n\t * @param {number|undefined|null=} \tratio ratio position in case time position are still unknown\n\t */\n\tupdateLine: function(seconds, ratio = null) {\n\t\tconst loadingline_element = this.shadowId('loadingline');\n\t\tif (!loadingline_element) {\n\t\t\treturn;\n\t\t}\n\t\tconst { duration } = this.audiotag;\n\t\tratio = ratio ?? ( duration === 0 ? 0 : (100*seconds / duration) );\n\t\tloadingline_element.style.width = `${ratio}%`;\n\t},\n\n\t/**\n\t * @summary update current timecode and related links\n\t * @private\n\t */\n\tupdateTime: function() {\n\t\tconst audiotag = this.audiotag;\n\t\tconst timecode = isAudiotagStreamed(audiotag) ? 0 : Math.floor(audiotag.currentTime);\n\t\tconst canonical = audiotag.dataset.canonical ?? '' ;\n\t\tconst _is_at = canonical.indexOf('#');\n\t\tconst elapse_element = this.shadowId('elapse');\n\t\tif (elapse_element) {\n\t\t\telapse_element.href = \n\t\t\t\t`${ absolutizeUrl(canonical) }#${ (_is_at < 0) ?\n\t\t\t\t\taudiotag.id :\n\t\t\t\t\tcanonical.substr(_is_at + 1) }&t=${timecode}`;\n\t\t}\n\n\t\tconst currenttime_element = this.shadowId('currenttime');\n\t\tif (currenttime_element) {\n\t\t\tthis.shadowId('currenttime').innerText = secondsInColonTime(audiotag.currentTime);\n\t\t}\n\t\tconst duration_element = this.shadowId('totaltime');\n\t\tif (duration_element) {\n\t\t\tconst duration = audiotagDuration(audiotag);\n\t\t\tduration_element.innerText = uncertainDuration(duration) ? '' : `\\u00a0/\\u00a0${secondsInColonTime(duration)}`;\n\t\t\tshowElement(duration_element, duration);\n\t\t}\n\t\tthis.updateLine(audiotag.currentTime);\n\t},\n\n\t/**\n\t * @summary Shows indicators for the limits of the playing position\n\t * @private\n\t */\n\tupdateTimeBorders: function() {\n\t\tconst audiotag = this.audiotag;\n\t\tif ((!document.CPU.isAudiotagGlobal(audiotag)) || (timecodeEnd === false)) {\n\t\t\tthis.removePlane(planeNameBorders);\n\t\t\treturn;\n\t\t}\n\t\t// verify if plane exists, and point is invariant\n\t\tif (this.plane(planeNameBorders)) {\n\t\t\tconst check = this.point(planeNameBorders, planeNameBorders);\n\t\t\tif (\n\t\t\t\t(check) &&\n\t\t\t\t(check.start === timecodeStart) &&\n\t\t\t\t(check.end === timecodeEnd)) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tthis.addPlane(planeNameBorders,{\n\t\t\ttrack \t: 'borders',\n\t\t\tpanel \t: false,\n\t\t\thighlight \t: false\n\t\t});\n\t\tthis.addPoint(planeNameBorders, planeNameBorders, {\n\t\t\tstart \t\t: timecodeStart,\n\t\t\tlink \t: false,\n\t\t\tend \t: timecodeEnd\n\t\t});\n\n\t},\n\n\t/**\n\t * @summary Show that the media is loading\n\t * @private\n\t *\n\t * @param {number} seconds The seconds\n\t */\n\tupdateLoading: function(seconds, ratio) {\n\t\tthis.updateLine(seconds, ratio);\n\t\tthis.setAct('loading');\n\t},\n\n\t/**\n\t * @summary Show the current media error status. NOTE : this is not working, even on non supported media type\n\t * Chrome logs an error « Uncaught (in promise) DOMException: Failed to load because no supported source was found. »\n\t * but won't update message\n\t *\n\t * @private\n\t *\n\t * @return {boolean} True if an error is displayed\n\t */\n\tupdateError: function() {\n\t\tconst audiotag = this.audiotag;\n\t\tif (!audiotag) {\n\t\t\treturn true;\n\t\t}\n\t\tconst error_object = audiotag.error;\n\t\tif (error_object) {\n\t\t\tlet error_message;\n\t\t\tthis.show('error');\n\t\t\tconst m = MediaError;\n\t\t\tswitch (error_object.code) {\n\t\t\t\tcase m.MEDIA_ERR_ABORTED:\n\t\t\t\t\terror_message = __.media_err_aborted;\n\t\t\t\t\tbreak;\n\t\t\t\tcase m.MEDIA_ERR_NETWORK:\n\t\t\t\t\terror_message = __.media_err_network;\n\t\t\t\t\tbreak;\n\t\t\t\tcase m.MEDIA_ERR_DECODE:\n\t\t\t\t\terror_message = __.media_err_decode;\n\t\t\t\t\tbreak;\n\t\t\t\tcase m.MEDIA_ERR_SRC_NOT_SUPPORTED:\n\t\t\t\t\terror_message = __.media_err_src_not_supported;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\terror_message = __.media_err_unknow;\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tconst pageerror = this.shadowId('pageerror');\n\t\t\tif (pageerror) {\n\t\t\t\tpageerror.innerText = error_message;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t},\n\n\n\t/**\n\t * @private\n\t * still need to be public exposed for tests\n\t *\n\t * @summary Update links for sharing\n\t */\n\tupdateLinks : function() {\n\t\tconst audiotag = this.audiotag;\n\t\tconst dataset = this.audiotagDataset();\n\t\tconst canonical = absolutizeUrl( dataset.canonical ?? '' );\n\t\tconst timepos = (audiotag.currentTime === 0) ? '' : `&t=${Math.floor(audiotag.currentTime)}`;\n\t\t// watch out : we should put the ID only if canonical URL is strictly identical to this page\n\t\tconst tag_id = (canonical === absolutizeUrl(window.location.href)) ? audiotag.id : '';\n\t\tconst _url = encodeURIComponent(`${canonical}#${tag_id}${timepos}`);\n\t\t/* why did I want an @ in the attribute if I cut it in my code ? to keep HTML readable and comprehensible, instead to develop attribute name into a \"twitter-handler\" */\n\t\tconst _twitter = (dataset.twitter?.[0]!=='@') ? '' : `&via=${dataset.twitter.substring(1)}`;\n\n\t\tconst link = audiotag.querySelector('source[data-downloadable]')?.src ||\n\t\t\t\t\t dataset.download ||\n\t\t\t\t\t audiotag.currentSrc;\n\n\t\tconst title = dataset.title;\n\t\tconst links = {\n\t\t\ttwitter : `https://twitter.com/share?text=${title}&url=${_url}${_twitter}`,\n\t\t\tfacebook : `https://www.facebook.com/sharer.php?t=${title}&u=${_url}`,\n\t\t\temail : `mailto:?subject=${title}&body=${_url}`,\n\t\t\tlink\n\t\t};\n\t\tfor (const key in links) {\n\t\t\tconst element = this.shadowId(key);\n\t\t\tif (element) {\n\t\t\t\telement.href = links[key];\n\t\t\t}\n\t\t}\n\t},\n\n\t/**\n\t * @summary Will refresh player interface at each time change (a lot)\n\t *\n\t * @private\n\t */\n\tupdate: function() {\n\t\tif (!this.updateError()) {\n\t\t\tthis.updatePlayButton();\n\t\t\tthis.updateTime();\n\t\t\tthis.updateTimeBorders();\n\t\t}\n\t}\n\n};\n\nexport default updates;","import { secondsInColonTime, secondsInTime } from '../primitives/convert.js';\n\nimport { isAudiotagStreamed, uncertainDuration } from '../mediatag/time.js';\nimport { audiotagPreloadMetadata } from '../mediatag/extension.js';\n\nimport { hover } from '../trigger/throbber.js';\n\nconst hideThrobber_delay = 1000;\n\nexport const throbber = {\n\n\t/**\n\t * @summary Position an element in the timeline, on its time\n\t * @private\n\t *\n\t * @param {Element} \t\t\t \t\t element Element to impact, should be in #time\n\t * @param {number|null|undefined} \t \tseconds_begin Starts position in seconds, do not apply if undefined\n\t * @param {number|null|undefined|boolean}\tseconds_end Ends position in seconds, do not apply if NaN\n\t */\n\tpositionTimeElement: function(element, seconds_begin = null, seconds_end = null) {\n\t\tconst { duration } = this.audiotag;\n\n\t\tif (uncertainDuration(duration)) {\n\t\t\t// duration still unkown ! We will need to redraw later the tracks\n\t\t\treturn;\n\t\t}\n\n\t\t// completely ugly... but « WAT » ! as in https://www.destroyallsoftware.com/talks/wat\n\t\tconst isSeconds = (sec) => ((sec != undefined) && (sec !== false));\n\n\t\tif (isSeconds(seconds_begin)) {\n\t\t\telement.style.left = `${100 * (seconds_begin / duration)}%`;\n\t\t}\n\t\tif (isSeconds(seconds_end)) {\n\t\t\telement.style.right = `${100 * (1 - (seconds_end / duration))}%`;\n\t\t}\n\n\t},\n\n\t/**\n\t * @summary Shows the throbber\n\t *\n\t * @public\n\t *\n\t * @param {number} seeked_time The seeked time\n\t */\n\tshowThrobberAt: async function(seeked_time) {\n\t\tconst audiotag = this.audiotag;\n\t\tif (audiotag.duration < 1) {\n\t\t\t// do not try to show if no metadata\n\t\t\treturn;\n\t\t}\n\t\tif ((isNaN(audiotag.duration)) && (!isAudiotagStreamed(audiotag))) {\n\t\t\t// as we navigate on the timeline, we wish to know its total duration\n\t\t\t// yes, this is twice calling, as of trigger.throbble()\n \t\t\taudiotag.setAttribute('preload', 'metadata');\n\t\t\taudiotagPreloadMetadata(audiotag, hover, event);\n\t\t}\n\n\t\tconst phylactere = this.shadowId('popup');\n\t\tthis.positionTimeElement(phylactere, seeked_time);\n\t\tphylactere.style.opacity = 1;\n\t\tphylactere.innerHTML = secondsInColonTime(seeked_time);\n\t\tphylactere.dateTime = secondsInTime(seeked_time).toUpperCase();\n\t},\n\n\t/**\n\t * @summary Hides immediately the throbber.\n\t * @public\n\t */\n\thideThrobber: function() {\n\t\t// we use opacity instead of a class change to permits opacity smooth transition via `--cpu-background-transitions`\n\t\t// well, in fact, i can use a class, and change opacity from the css.... facepalm.\n\t\tthis.shadowId('popup').style.opacity = 0;\n\t},\n\n\t/**\n\t * @summary Hides the throbber later. Will delay the hiding if recalled.\n\t * @public\n\t */\n\thideThrobberLater: function() {\n\t\tconst phylactere = this.shadowId('popup');\n\t\tif (phylactere._hider) {\n\t\t\twindow.clearTimeout(phylactere._hider);\n\t\t}\n\t\tphylactere._hider = window.setTimeout( () => { this.hideThrobber(); }, hideThrobber_delay);\n\t}\t\n};\n\n\nexport default throbber;","import { isAudiotagStreamed } from '../mediatag/time.js';\n\nimport { showElement } from '../component/show.js';\n\nexport const show = {\n\t/**\n\t * @summary Shows the interface\n\t *\n\t * @public\n\t * @param {string} mode The mode, can be 'main', 'share' or 'error'\n\t */\n\tshow : function(mode) {\n\t\tconst { classList } = this.container;\n\t\tclassList.remove(\n\t\t\t'show-main',\n\t\t\t'show-share',\n\t\t\t'show-error',\n\t\t\t'media-streamed'\n\t\t);\n\t\tif (isAudiotagStreamed(this.audiotag)) {\n\t\t\tclassList.add('media-streamed');\n\t\t}\n\t\tclassList.add(`show-${mode}`);\n\t},\n\n\t/**\n\t * @summary Shows the sharing panel\n\t * @private\n\t */\n\tshowActions: function(/* event */) {\n\t\tthis.show('share');\n\t\tthis.updateLinks();\n\t},\n\n\t/**\n\t * @summary Shows the main interface\n\t * @private\n\t */\n\tshowMain: function(/* event */) {\n\t\tshowElement(this.container, true);\n\t\tthis.show('main');\n\t},\n\n\t/**\n * @summary Shows the handheld fine navigation\n * @private\n\t *\n\t * @param {Object|undefined} event Triggering event\n\t */\n\tshowHandheldNav: function(event) {\n\t\tif (isAudiotagStreamed(this.audiotag)) {\n\t\t\treturn;\n\t\t}\n\t\t// For resolving #180 , <details>.open != <details>.open will do the trick\n\t\tthis.container.classList.toggle('show-handheld-nav');\n\t\tevent?.preventDefault();\n\t}\n};\n\nexport default show;","import { uncertainDuration } from '../mediatag/time.js';\n\nimport { validId, getPointId } from '../component/planename.js';\n\n\n/**\n * @summary Check acceptance of a pointData for insertion\n *\n * @param {Object} pointData \tnormalized pointData to check\n * @return boolean \t\t\t\ttrue is ok\n */\nfunction checkPointData({start, end}) {\n\treturn (((start == null) || (start >= 0)) && ((end == null) || (end >= start)));\n}\n\n\nexport const planes = {\n\t\t/**\n\t * @summary Gets an array of whole planes\n\t * @private\n\t *\n\t * @return {Array(string)} array of planeNames\n\t */\n\tplaneNames : function() {\n\t\t// TODO : we need a way to order them, see #123 https://github.com/dascritch/cpu-audio/issues/123\n\t\t// BUG we may have duplicates, it can happens even with protections in addPlane() \n\t\t// BUG will crash if no audiotag\n\t\treturn Object.keys(this._planes).concat(Object.keys(this.audiotag?._CPU_planes ?? {}));\n\t},\n\n\t/**\n\t * @summary Gets the plane info\n\t * @private\n\t *\n\t * @param {string} planeName The name\n\t * @return {Object} data of the plane\n\t */\n\tplane: function(planeName) {\n\t\treturn this._planes[planeName] ?? this.audiotag?._CPU_planes[planeName];\n\t},\n\n\t/**\n\t * @summary Gets the plane track element\n\t * @private but needed in tests\n\t *\n\t * @param {string} planeName The name\n\t * @return {Element} The <aside> track element from ShadowDom interface\n\t */\n\tplaneTrack: function(planeName) {\n\t\treturn this.shadowId(`track_«${planeName}»`);\n\t},\n\n\t/**\n\t * @summary Gets the plane panel element\n\t * @private but needed in test\n\t *\n\t * @param {string} planeName The name\n\t * @return {Element} The panel element from ShadowDom interface\n\t */\n\tplanePanel: function(planeName) {\n\t\treturn this.shadowId(`panel_«${planeName}»`);\n\t},\n\n\t/**\n\t * @summary Gets the <nav><ul> plane panel element\n\t * @private but needed in tests\n\t *\n\t * @param {string} planeName The name\n\t * @return {Element} The <ul> element from ShadowDom interface, null if inexisting\n\t */\n\tplaneNav: function(planeName) {\n\t\treturn this.planePanel(planeName)?.querySelector(`ul`);\n\t},\n\n\t/**\n\t * @summary Add an annotation plane layer\n\t * @public\n\t *\n\t * @param {string} planeName A name in the range /[a-zA-Z0-9\\-_]+/\n\t * @param {Object} planeData { \n\t \t\t\t\t\t\t\t\t\t\ttitle : The displayed title for the panel,\n\t \t\t\t\t\t\t\t\t\t\ttrack : true/false/classnames ,\n\t * \t\t\t\t\t\t\t\t\t\tpanel : true/false/classnames ,\n\t * \t\t\t\t\t\t\t\t\t\thighlight : true/false,\n\t *\t\t\t\t\t\t\t\t\t\t_comp : true/false // only stored in component, private use only\n\t }\n\t *\n\t * @return {boolean} success\n\t */\n\taddPlane: function(planeName, planeData = {}) {\n\t\tif ((! planeName.match(validId)) || (this.plane(planeName))) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// I don't understand (yet) why, when I move this declaration at the top of this source file, tests will fail\n\t\tconst planeDataDefault = {\n\t\t\ttrack : true,\n\t\t\tpanel : true,\n\t\t\ttitle : '',\n\t\t\thighlight : true,\n\t\t\tpoints : {},\n\t\t\t_comp\t\t: false\n\t\t};\n\n\t\tplaneData = { ...planeDataDefault, ...planeData};\n\n\t\tif (!planeData._comp) {\n\t\t\tif (this.isController) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthis.audiotag._CPU_planes = this.audiotag._CPU_planes ?? {};\n\t\t\tthis.audiotag._CPU_planes[planeName] = planeData;\n\t\t} else {\n\t\t\tthis._planes[planeName] = planeData;\n\t\t}\n\t\tthis.drawPlane(planeName);\n\t\treturn true;\n\t},\n\n\t/**\n\t * @summary Remove an annotation plane layer\n\t * @public\n\t *\n\t * @param {string} planeName A name in the range /[a-zA-Z0-9\\-_]+/\n\t *\n\t * @return {boolean} success\n\t */\n\tremovePlane: function(planeName) {\n\t\tif ( (! planeName.match(validId)) || (! this.plane(planeName)) || (this.isController && (!this._planes[planeName])) ) {\n\t\t\treturn false;\n\t\t}\n\n\t\tdelete (this._planes[planeName] ? this._planes : this.audiotag._CPU_planes)[planeName];\n\n\t\tthis.planeTrack(planeName)?.remove();\n\t\tthis.planePanel(planeName)?.remove();\n\n\t\tif ( (!this.isController) && (this.mirroredInController()) ) {\n\t\t\t// as plane data is removed, it will remove its aside and track\n\t\t\tdocument.CPU.globalController.drawPlane(planeName);\n\t\t}\n\n\t\treturn true;\n\t},\n\n\t/**\n\t * @summary Shortcut to get points data\n\t * @private\n\t *\n\t * @param {string} planeName The plane name\n\t * @return {Object} Data\n\t */\n\tplanePoints: function(planeName) {\n\t\treturn this.plane(planeName)?.points;\n\t},\n\n\t/**\n\t * @summary Gets the point info\n\t * @public\n\t *\n\t * @param {string} planeName The plane name\n\t * @param {string} pointName The point name\n\t * @return {Object} Data\n\t */\n\tpoint: function(planeName, pointName) {\n\t\treturn this.plane(planeName)?.points?.[pointName];\n\t},\n\n\t/**\n\t * @summary Gets the point element in the track\n\t * @private but needed in tests\n\t *\n\t * @param {string} planeName The plane\n\t * @param {string} pointName The point\n\t * @return {Element} The <div> point element into <aside> from ShadowDom interface\n\t */\n\tpointTrack: function(planeName, pointName) {\n\t\treturn this.shadowId(getPointId(planeName, pointName, false));\n\t},\n\n\t/**\n\t * @summary Gets the point element in the panel\n\t * @private but needed in tests\n\t *\n\t * @param {string} planeName The plane\n\t * @param {string} pointName The point\n\t * @return {Element} The <li> point element into panel from ShadowDom interface\n\t */\n\tpointPanel: function(planeName, pointName) {\n\t\treturn this.shadowId(getPointId(planeName, pointName, true));\n\t},\n\n\t/**\n\t * @summary Resort points of a plane by start-time. Should bne later renamed planePointSort , as we will need a planeSort ?\n\t * @private\n\t *\n\t * @param {string} planeName The plane name\n\t */\n\tplaneSort: function(planeName) {\n\t\tconst old_points = this.planePoints(planeName);\n\t\tif (!old_points) {\n\t\t\treturn ;\n\t\t}\n\n\t\tthis.plane(planeName).points = Object.fromEntries( \n\t\t\t\t\t\t\t\tObject.entries(\n\t\t\t\t\t\t\t\t\told_points\t\t\t\t\t\t\t \t\n\t\t\t\t\t\t\t\t).sort(\n\t\t\t\t\t\t\t \t([, point_a], [, point_b]) => {\n\t\t\t\t\t\t\t \t\treturn point_a.start - point_b.start;\n\t\t\t\t\t\t\t \t}\n\t\t\t\t\t\t\t )\n\t\t\t\t\t\t );\n\t\tconst points = Object.values( this.plane(planeName).points );\n\t\tthis.plane(planeName)._st_max = points[points.length - 1]?.start ?? 0;\n\t},\n\n\t/**\n\t * @summary get pointNames from a planeName\n\t * @private may goes public later\n\t *\n\t * @param {string} planeName The plane name\n\t * @return {[string]} points_names\t Array of pointNames\n\t */\n\tplanePointNames: function(planeName) {\n\t\treturn Object.keys(this.planePoints(planeName));\n\t},\n\n\t/**\n\t * @summary Reorder panel of a plane by points order\n\t * @private\n\t *\n\t * @param {string} planeName The plane name\n\t */\n\tpanelReorder: function(planeName) {\n\t\t// TODO we may lose focused element. Store it to refocus it at the end\n\t\tthis.planeSort(planeName);\n\t\tif (!this.planePanel(planeName)) {\n\t\t\treturn;\n\t\t}\n\t\tlet previous_element, element;\n\t\tfor (const pointName of this.planePointNames(planeName)) {\n\t\t\telement = this.pointPanel(planeName, pointName);\n\t\t\tprevious_element?.insertAdjacentElement('afterend', element);\n\t\t\tprevious_element = element;\n\t\t}\n\t},\n\n\t/**\n\t * @summary Add an annotation point\n\t * @public\n\t *\n\t * @param {string} planeName The existing plane name\n\t * @param {string} pointName The point name, should conform to /^[a-zA-Z0-9\\-_]+$/\n\t * @param {Object} pointData {\n\t * \t\t\t\t\t\t\t\t\t\t\tstart : <seconds>,\n\t *\t\t\t\t\t\t\t\t\t\t image : <url>,\n\t * \t\t\t\t\t\t\t\t\t\t\tlink : <url>/true (in audio)/false (none),\n\t * \t\t\t\t\t\t\t\t\t\t\ttext : <text>,\n\t * \t\t\t\t\t\t\t\t\t\t\tend : <seconds> }\n\t *\n\t * @return {boolean} success\n\t */\n\taddPoint: function(planeName, pointName, pointData={}) {\n\t\tconst start = Number(pointData.start);\n\n\t\tif ( (!pointName.match(validId)) ||\n\t\t\t(!this.plane(planeName)) ||\n\t\t\t(this.point(planeName, pointName)) ||\n\t\t\t(!checkPointData(pointData)) ) {\n\t\t\treturn false;\n\t\t}\n\t\tif ((!this._planes[planeName]) && (this.isController)) {\n\t\t\t// accept points adding on controller only for private planes\n\t\t\treturn false;\n\t\t}\n\t\t\n\t\tpointData.start = start;\n\t\tthis.plane(planeName).points[pointName] = pointData;\n\n\t\tthis.emitEvent('addPoint', {\n\t\t\tplaneName,\n\t\t\tpointName,\n\t\t\tpointData\n\t\t});\n\n\t\tif (this.plane(planeName)._st_max > start) {\n\t\t\t// we need to reorder the plane\n\t\t\tthis.panelReorder(planeName);\n\t\t} else {\n\t\t\tthis.drawPoint(planeName, pointName);\n\t\t\tthis.plane(planeName)._st_max = start;\n\t\t}\n\n\t\treturn true;\n\t},\n\n\t/**\n\t * @summary Bulk push (add/modify) points\n\t * @public\n\t *\n\t * @param {string} planeName The existing plane name\n\t * @param {Object} Object of pointData {\n\t \t point_1 : pointData_1,\n\t \t point_2 : pointData_2,\n\t * \t\t\t\t\t\t\t\t\t\t\t}\n\t *\n\t * @return {boolean} success\n\t */\n\tbulkPoints: function(planeName, pointDataGroup={}) {\n\t\tif (!this.plane(planeName)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ((!this._planes[planeName]) && (this.isController)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (const [pointName, pointData] of Object.entries(pointDataGroup)) {\n\t\t\tif ((!pointName.match(validId)) || (!checkPointData(pointData))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tpointDataGroup = {...this.plane(planeName).points, ...pointDataGroup};\n\t\tthis.plane(planeName).points = pointDataGroup;\n\n\t\tthis.emitEvent('bulkPoints', {\n\t\t\tplaneName,\n\t\t\tpointDataGroup\n\t\t});\n\t\tconst nav = this.planeNav(planeName);\n\t\tif (nav) {\n\t\t\tnav.innerHTML = '';\n\t\t}\n\t\tthis.refreshPlane(planeName);\n\t\treturn true;\n\t},\n\n\n\t/**\n\t * @summary Edit an annotation point\n\t * @public\n\t *\n\t * @param {string} planeName The existing plane name\n\t * @param {string} pointName The existing point name\n\t * @param {Object} data { 'image' : <url>,\n\t * \t\t\t\t\t\t\t\t\t\t\t'link' : <url>/true (in audio)/false (none),\n\t * \t\t\t\t\t\t\t\t\t\t\t'text' : <text>,\n\t * \t\t\t\t\t\t\t\t\t\t\t'start' : <seconds>,\n\t * \t\t\t\t\t\t\t\t\t\t\t'end' : <seconds> }\n\t *\t\t\t\t\t\t\t\t\t\t will only change keys in the list\n\t */\n\teditPoint: function(planeName, pointName, pointData) {\n\t\tconst plane = this.plane(planeName);\n\t\tif (!plane) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst original_data = this.point(planeName, pointName);\n\t\tif (!original_data) {\n\t\t\treturn false;\t\n\t\t}\n\n\t\tlet { start } = pointData;\n\t\tstart = Number(start);\n\t\tconst will_refresh = ((start != null) && (start !== original_data.start));\n\n\t\tpointData = {...original_data, ...pointData};\n\n\t\tif (!checkPointData(pointData)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tplane.points[pointName] = pointData;\n\n\t\tthis.drawPoint(planeName, pointName);\n\t\tif (will_refresh) {\n\t\t\tthis.panelReorder(planeName);\n\t\t}\n\n\t\tthis.emitEvent('editPoint', {\n\t\t\tplaneName,\n\t\t\tpointName,\n\t\t\tpointData\n\t\t});\n\n\t\tif (plane._st_max < start) {\n\t\t\tplane._st_max = start;\n\t\t}\n\t},\n\n\t/**\n\t * @summary Remove an annotation point\n\t * @public\n\t *\n\t * @param {string} planeName A name in the range /^[a-zA-Z0-9\\-_$]+/\n\t * @param {string} pointName A name in the range /^[a-zA-Z0-9\\-_$]+/\n\t * @return {boolean} success\n\t */\n\tremovePoint: function(planeName, pointName) {\n\t\tconst plane = this.plane(planeName);\n\t\tif ((!plane) || (!this.point(planeName, pointName))) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.emitEvent('removePoint', {\n\t\t\tplaneName,\n\t\t\tpointName\n\t\t});\n\n\t\tthis.pointTrack(planeName, pointName)?.remove();\n\t\tthis.pointPanel(planeName, pointName)?.remove();\n\n\t\t// recalc _start_max for caching repaints\n\t\tlet _st_max = 0;\n\t\tfor (const s of Object.values(this.planePoints(planeName))) {\n\t\t\tconst that_start = Number(s.start);\n\t\t\t_st_max = _st_max < that_start ? that_start : _st_max;\n\t\t}\n\t\tplane._st_max = _st_max;\n\n\t\tif ( (!this.isController) && (this.mirroredInController()) ) {\n\t\t\tdocument.CPU.globalController.removePoint(planeName, pointName);\n\t\t}\n\t\tif (plane.points[pointName]) {\n\t\t\tdelete plane.points[pointName];\n\t\t}\n\t\treturn true;\n\t},\n\n\t/**\n\t * @summary Remove any points from an annotation plane\n\t * @public\n\t *\n\t * @param {string} planeName The plane name\n\t */\n\tclearPlane: function(planeName) {\n\t\tconst plane = this.plane(planeName);\n\t\tif (!plane) {\n\t\t\treturn false;\n\t\t}\n\n\t\tfor (const pointName of Object.keys(plane.points)) {\n\t\t\tthis.removePoint(planeName, pointName);\n\t\t}\n\t\t// need to repass in case of badly removed / malformed entries\n\t\tconst nav = this.planeNav(planeName);\n\t\tif (nav) {\n\t\t\tnav.innerHTML = '';\n\t\t}\n\t\t// purge repaint flag to redraw\n\t\tplane._st_max = 0;\n\n\t\treturn true;\n\t},\n\n\t/**\n\t * @summary Needed because Chrome can fire loadedmetadata before knowing audio duration. Fired at durationchange\n\t *\n\t * @private\n\t */\n\trepositionTracks: function() {\n\t\tif (uncertainDuration(this.audiotag.duration)) {\n\t\t\t// duration still unkown\n\t\t\treturn ;\n\t\t}\n\n\t\tfor (const planeName in this.audiotag._CPU_planes) {\n\t\t\tconst plane_data = this.plane(planeName);\n\t\t\tif (plane_data.track) {\n\t\t\t\tfor (const pointName of this.planePointNames(planeName)) {\n\t\t\t\t\tconst {start, end} = this.point(planeName, pointName);\n\t\t\t\t\tconst pointTrack = this.pointTrack(planeName, pointName);\n\t\t\t\t\tif (pointTrack) {\n\t\t\t\t\t\tthis.positionTimeElement(pointTrack, start, end);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\n};\n\nexport default planes;","import { adjacentArrayValue } from '../primitives/operators.js';\nimport { planeAndPointNamesFromId } from './planename.js';\n\n/**\n * @summary relatively browse up or down with focus\n * @private\n */\nexport function relative_focus(self, go_foward) {\n\tconst planeNames = self.planeNames();\n\tif (planeNames.length == 0) {\n\t\treturn;\n\t}\n\n\tconst validPlane = (id) => {\n\t\tconst {track, panel, points} = self.plane(id);\n\t\treturn (((track !== false) || (panel !== false))\n\t\t\t\t&& ((self.planePanel(id)?.clientHeight > 0) || (self.planeTrack(id)?.clientHeight > 0))\n\t\t\t\t&& (points)\n\t\t\t\t&& (Object.keys(points).length > 0));\n\t};\n\tconst scanToPrevPlane = (fromPlane) => {\n\t\tfor(let id = planeNames.indexOf(fromPlane) -1; id >= 0 ; id--) {\n\t\t\tconst out = planeNames[id];\n\t\t\tif (validPlane(out)) {\n\t\t\t\treturn out;\n\t\t\t}\n\t\t}\n\t};\n\tconst scanToNextPlane = (fromPlane) => {\n\t\tfor (let id = planeNames.indexOf(fromPlane) +1; id < planeNames.length ; id++) {\n\t\t\tconst out = planeNames[id];\n\t\t\tif (validPlane(out)) {\n\t\t\t\treturn out;\n\t\t\t}\n\t\t}\n\t};\n\n\tlet planeName, pointName, planePointNames;\n\tlet wasFocused = self.focused();\n\tif (wasFocused) {\n\t\tif (!wasFocused.id) {\n\t\t\twasFocused = wasFocused.closest('[id]');\n\t\t}\n\t\t({planeName, pointName} = planeAndPointNamesFromId(wasFocused.id));\n\t}\n\tif (pointName != '') { // NOTE : loosy comparison is important\n\t\tplanePointNames = self.planePointNames(planeName);\n\t\tpointName = adjacentArrayValue(planePointNames, pointName, go_foward ? 1 : -1);\n\t}\n\tif (!pointName) {\n\t\tplaneName = go_foward ? scanToNextPlane(planeName) : scanToPrevPlane(planeName);\n\t\tif (!planeName) {\n\t\t\treturn;\n\t\t}\n\t\tconst points = self.planePointNames(planeName);\n\t\tpointName = points[go_foward ? 0 : (points.length - 1)];\n\t}\n\tself.focusPoint(planeName, pointName);\n}\n\nexport default relative_focus;\n","import relative_focus from '../component/relative_focus.js';\n\nexport const planes_focus = {\n\t/**\n\t * @summary Give focus on an annotation point\n\t * @public\n\t *\n\t * @param {string} planeName The existing plane name\n\t * @param {string} pointName The existing point name\n\t * @return boolean has focus\n\t */\n\tfocusPoint: function(planeName, pointName) {\n\t\t// get element, first on the plane, and else on the plane\n\t\tconst element = this.pointPanel(planeName, pointName)?.querySelector('a') ?? this.pointTrack(planeName, pointName);\n\t\tif (!element) {\n\t\t\treturn false;\n\t\t}\n\t\telement.focus();\n\t\treturn true;\n\t},\n\n\t/**\n\t * @summary Get focused element in shadow\n\t * @public\n\t *\n\t * @return {Element|null} \t\tFocused element, or null\n\t */\n\tfocused: function() {\n\t\treturn this.shadow.querySelector(':focus');\n\t},\n\n\t/**\n\t * @summary Get ID of focused element in shadow\n\t * @public\n\t *\n\t * @return {string|null|undefined} \t\tFocused ID, or null or undefined\n\t */\n\tfocusedId: function() {\n\t\tconst target = this.focused();\n\t\tif (!target) {\n\t\t\treturn;\n\t\t}\n\t\tconst out = target.id != '' ? target.id : target.closest('[id]').id;\n\t\treturn out == '' ? null : out;\n\t},\n\n\t/**\n\t * @summary browse yo with focus in panels using ↑ key\n\t * @private\n\t */\n\tprevFocus: function() {\n\t\trelative_focus(this, false);\n\t},\n\n\t/**\n\t * @summary browse down with focus in panels using ↓ key\n\t * @private\n\t */\n\tnextFocus: function() {\n\t\trelative_focus(this, true);\n\t},\n\n};\n\nexport default planes_focus;","import translateVTT from '../primitives/translate_vtt.js';\nimport { selectorAudioInComponent } from '../primitives/utils.js';\n\nimport { planeAndPointNamesFromId } from '../component/planename.js';\nimport { audiotagPreloadMetadata } from '../mediatag/extension.js';\n\nimport { switchControllerTo } from '../cpu_controller.class.js';\nimport buildInterface from '../build_interface.js';\n\nimport utils from './utils.js';\nimport status from './status.js';\nimport updates from './updates.js';\nimport throbber from './throbber.js';\nimport show from './show.js';\nimport planes from './planes.js';\nimport planes_draw from './planes_draw.js';\nimport planes_focus from './planes_focus.js';\n\n\n/**\n*\n* @summary Constructs the api .CPU object for the component\n* @public\n*\n* @param {Element} element The DOMelement\n*/\nexport function\tconstructor(element) {\n\n\tconst { audiotag, shadowRoot } = element;\n\n\tconst self = {\n\t\telement,\n\t\tshadow : shadowRoot,\n\t\taudiotag,\n\t\tmode_when_play : null,\n\t\tglowBeforePlay : !! element.hasAttribute('glow'),\n\t\tcurrent_playlist : [],\n\t\t_activecue_id : null,\n\t\tmode_was : null,\n\t\tact_was : null,\n\t\tisController : false,\n\n\t\t// integration of segments per features\n\t\t...utils,\n\t\t...status,\n\t\t...updates,\n\t\t...throbber,\n\t\t...show,\n\t\t...planes,\n\t\t...planes_draw,\n\t\t...planes_focus,\n\n\t\t// Passthru there only for testing purposes.\n\t\ttranslateVTT, \n\t\tplaneAndPointNamesFromId, \n\t};\n\n\tself.container = self.shadowId('interface');\n\n\telement.CPU = self;\n\n\tif ( (audiotag) && (! audiotag._CPU_planes)) {\n\t\taudiotag._CPU_planes = {};\n\t}\n\n\t// only used for CPU-CONTROLLER, for playlist\n\tself._planes = {};\n\n\tconst globalController = document.CPU.globalController;\n\tif ((audiotag) && (globalController) && (!globalController.audiotag)) {\n\t\t// CPU-Controller was intancied before any audiotag was available\n\t\tswitchControllerTo(audiotag);\n\t}\n\n\tif (!audiotag) { // Implicitely a CPU-CONTROLLER\n\t\tself.isController = true;\n\t\tself.container.classList.add('controller');\n\t\tdocument.CPU.globalController = self;\n\t\tself.audiotag = document.querySelector(selectorAudioInComponent);\n\t\taudiotagPreloadMetadata(self.audiotag);\n\t}\n\n\t// From there, always use self.audiotag.\n\n\tbuildInterface(self);\n\tself.attachAudiotagToInterface(self.audiotag);\n\tself.attributesChanges();\n}\n\nexport default constructor;","import { CpuAudioTagName, CpuControllerTagName, selectorAcceptable, findCPU } from './primitives/utils.js';\nimport { notScreenContext } from './primitives/checkers.js';\nimport { warn, info } from './primitives/console.js';\n\n// generated during ./make.sh for each theme\nimport { template } from '../tmp/insert_template.js';\n\nimport { removeOfPlaylists, buildPlaylist, rePointsPlaylist } from './build_playlist.js';\n\nimport constructor from './component_cpu/constructor.js';\n\nconst media_tagname = 'audio';\n\n/**\n * @summary When a <cpu-audio> plays, attach it to the eventual <cpu-controller>\n * @private\n *\n * @param {audiotag} HTMLAudioElement The playing <audio> tag\n */\nexport function switchControllerTo(audiotag) {\n\tconst globalController = document.CPU.globalController;\n\tif (!globalController) {\n\t\treturn;\n\t}\n\n\tif (!audiotag.isEqualNode(globalController.audiotag)) {\n\t\t// remove previous orphan audio tag\n\t\tconst previous_audiotag = document.CPU.globalController.element.querySelector(media_tagname);\n\t\tif (previous_audiotag) {\n\t\t\tremoveOfPlaylists(previous_audiotag);\n\t\t\tprevious_audiotag.remove();\n\t\t}\n\n\t\tconst wasFocused = globalController.focusedId();\n\t\tglobalController.attachAudiotagToInterface(audiotag);\n\t\t// globalController.audiotag = audiotag; unuseful : done upper\n\t\tglobalController.showMain();\n\t\tglobalController.redrawAllPlanes();\n\t\tglobalController.setMode(); \t// to switch back the display between streamed/not-str medias\n\t\tbuildPlaylist(wasFocused);\n\t}\n}\n\n/**\n * @summary Interprets if <cpu-audio>/<cpu-controller> element is modified\n *\n * @param {Object} mutationsList The mutations list\n */\nfunction modifiedController([{target}]) {\n\tconst elCPU = findCPU(target);\n\tconst component = elCPU.element;\n\tconst audio_element = component.querySelector(media_tagname);\n\tconst globalController = document.CPU.globalController;\n\tif ((!audio_element) && (component.tagName !== CpuControllerTagName)) {\n\t\tinfo(`<${media_tagname}> element was removed.`);\t\t\n\t\tcomponent.remove();\n\t\tif (globalController) {\n\t\t\trePointsPlaylist();\n\t\t}\n\t\treturn;\n\t}\n\tcomponent.copyAttributesToMediaDataset?.();\n\telCPU.attributesChanges();\n\n\tif (document.CPU.currentPlaylistID() === audio_element?.dataset.playlist) {\n\t\trePointsPlaylist();\n\t}\n}\n\n/**\n * Controller without assigned audio element, i.e. global page controller\n *\n * @class CpuControllerElement (name)\n */\nexport class CpuControllerElement extends HTMLElement {\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.CPU = null;\n\t\tthis.observer = null;\n\n\t\tif (notScreenContext) {\n\t\t\t// I'm not in a screen context, as a braille surface\n\t\t\t// Sorry, but your browser's native controls are surely more accessible\n\t\t\tthis.remove();\n\t\t\treturn ;\n\t\t}\n\n\t\t/// TODO if a CPU-Controller is still there, do not create\n\n\t\tif (this.tagName === CpuAudioTagName) {\n\t\t\tif (!this.querySelector(selectorAcceptable)) {\n\t\t\t\t// Graceful degradation : do not start if no media element OR no native controls\n\t\t\t\twarn(`<${CpuAudioTagName}> tag without <audio controls>.\\nRead the manual first: https://github.com/dascritch/cpu-audio/blob/master/INSTALL.md`);\n\t\t\t\tthis.remove();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tif ((this.tagName === CpuControllerTagName) && (document.CPU.globalController)) {\n\t\t\t// called twice ????\n\t\t\twarn(`<${CpuControllerTagName}> tag instancied twice`);\n\t\t\tthis.remove();\n\t\t\treturn ;\n\t\t}\n\n\t\tthis.shadow = this.attachShadow({mode: 'open'});\n\t\tthis.shadow.innerHTML = template();\n\t}\n\n\tconnectedCallback() {\n\t\tif (notScreenContext) {\n\t\t\treturn ;\n\t\t}\n\n\t\tif (!this.shadowRoot) {\n\t\t\treturn;\n\t\t}\n\n\t\tnew constructor(this);\n\n\t\tthis.observer = new MutationObserver(modifiedController);\n\t\tthis.observer.observe(this, {\n\t\t\tchildList \t: true,\n\t\t\tattributes\t: true\n\t\t});\n\t\tthis.CPU.attributesChanges();\n\t}\n\n\tdisconnectedCallback() {\n\t\tif (!this.observer) {\n\t\t\t// was already deleted because instancied twice\n\t\t\treturn;\n\t\t}\n\t\tthis.observer.disconnect();\n\t\tthis.CPU.emitEvent('removed');\n\t\tif ((this.tagName === CpuControllerTagName) && (document.CPU.globalController)) {\n\t\t\tdocument.CPU.globalController = null;\n\t\t}\n\t}\n\n}\n","// auto-generated source, done via make.sh\n\t\t\timport {__} from '../src/primitives/i18n.js';\n\t\t\t/** @summary insert styles into host document */\n\t\t\texport function insert_style() {\n\t\t\t\tconst style = document.createElement('style');\n\t\t\t\tstyle.innerHTML = `audio[controls]{display:block;width:100%}:root{--cpu-height:64px;--cpu-font-family:Lato,\"Open Sans\",\"Segoe UI\",Frutiger,\"Frutiger Linotype\",\"Dejavu Sans\",\"Helvetica Neue\",Arial,sans-serif;--cpu-font-size:15px;--cpu-font-small-size:calc(var(--cpu-font-size) * 0.8);--cpu-line-height:1.2;--cpu-background:#555;--cpu-color:#ddd;--cpu-playing-background:#444;--cpu-playing-color:#fff;--cpu-error-background:#a00;--cpu-error-color:#ff7;--cpu-popup-background:#aaa;--cpu-popup-color:#333;--cpu-cue:#000;--cpu-timeline-limits:#f00;--cpu-elapse-width:160px;--cpu-min-padding:16px;--cpu-inner-shadow:inset 0px 5px 10px -5px black;--cpu-color-transitions:0s;--cpu-background-transitions:0s}@media (max-width:640px){.interface,:root{--cpu-font-size:13px;--cpu-height:48px;--cpu-elapse-width:140px;--cpu-min-padding:4px}@media (max-width:480px){.interface,:root{--cpu-elapse-width:70px}}}`;\n\t\t\t\tdocument.head.appendChild(style);\n\t\t\t}\n\t\t\t/** @summary template to be inserted into webcomponent */\n\t\t\texport function template() {\n\t\t\t\treturn `<style>:host{all:initial;display:block;contain:content}.act-buffer,.act-play{--cpu-background:var(--cpu-playing-background);--cpu-color:var(--cpu-playing-color)}.show-error{--cpu-background:var(--cpu-error-background);--cpu-color:var(--cpu-error-color)}#interface{--cpu-timeline-height:10px;background:var(--cpu-background);color:var(--cpu-color)}#interface.no{display:block;pointer-events:none}#interface.no main{visibility:hidden}#interface,*{font-family:var(--cpu-font-family);font-size:var(--cpu-font-size);font-weight:400;font-style:normal;line-height:var(--cpu-line-height);border:none;padding:0;margin:0;text-indent:0;list-style-type:none;-webkit-user-select:none;user-select:none;transition:color var(--cpu-color-transitions),background-color var(--cpu-background-transitions),opacity var(--cpu-background-transitions)}main{display:flex;overflow:hidden;height:var(--cpu-height);top:0;z-index:2}main,summary{position:sticky;background:var(--cpu-background)}a,button{color:currentColor;border:none;text-decoration:none;cursor:pointer;-webkit-touch-callout:none}button{background:0 0}svg{fill:currentColor;width:var(--cpu-height);height:var(--cpu-height)}em,i{font-style:italic}b,strong{font-weight:700}[src='']{visibility:hidden}#pageerror{padding:0 4px;align-self:center}.siders{flex:0 0 var(--cpu-height);width:var(--cpu-height);max-height:var(--cpu-height);height:100%;text-align:center;vertical-align:middle}.act-glow #play,.act-loading #loading,.act-pause #play,.act-play #pause{display:block}.act-glow #play{animation:glow 2s infinite}@keyframes glow{0%{opacity:.5}50%{opacity:1}100%{opacity:.5}}.show-main #pagemain,.show-share #pageshare{flex:1 1 100%;display:flex;align-items:center}.act-loading #loading circle{fill:#777;opacity:1;animation:pulse 2s infinite}#loading circle:nth-child(2){animation-delay:.5s}#loading circle:nth-child(3){animation-delay:1s}@keyframes pulse{50%{opacity:0}}#poster{max-width:var(--cpu-height);min-width:var(--cpu-height);max-height:var(--cpu-height);min-height:var(--cpu-height);object-fit:contain;opacity:0}.poster-loaded #poster{opacity:1}.siders svg{vertical-align:middle;max-width:100%;max-height:100%}#titleline{display:flex;align-items:center}#about,#title{flex:1 1 auto;position:relative}#title{overflow:hidden;text-overflow:'…'}#title a{display:block;max-height:calc(6px + calc(2 * var(--cpu-font-size)))}#canonical.untitled{font-style:italic}#elapse{flex:0 1 var(--cpu-elapse-width);text-align:right}.mode-compact #elapse{flex:0 0 calc(var(--cpu-elapse-width) + 32px);text-align:center}#time{background-color:#000;background-repeat:no-repeat;background-size:100% 100%;width:100%;height:var(--cpu-timeline-height);display:block;position:relative}#loadingline{background:currentColor;height:var(--cpu-timeline-height);display:block;position:absolute;left:0;pointer-events:none}#loadingline:after{content:'';position:absolute;right:0;width:0;height:var(--cpu-timeline-height);display:block;outline:var(--cpu-color) 4px solid;z-index:127;opacity:0}main:focus #loadingline:after,main:hover #loadingline:after{opacity:1}aside{position:absolute;width:100%}aside a{position:absolute;display:block}aside a span{display:none}aside.chapters{height:2px}aside.chapters a{background:var(--cpu-cue);height:2px;border:1px solid var(--cpu-background)}aside.chapters a.active-cue{background:var(--cpu-color)}aside.borders{pointer-events:none;height:var(--cpu-timeline-height);z-index:4;top:calc(var(--cpu-timeline-height) + 6px)}aside.borders a{height:var(--cpu-timeline-height);background:0 0}aside.borders a:after,aside.borders a:before{pointer-events:none;content:\"\";position:absolute;width:2px;height:var(--cpu-timeline-height);border:2px solid var(--cpu-timeline-limits)}aside.borders a:before{border-right-width:0;left:0}aside.borders a:after{border-left-width:0;left:100%}.act-loading #loadingline{background:repeating-linear-gradient(45deg,var(--cpu-color) 0,var(--cpu-background) 15px,var(--cpu-color) 30px);background-size:200% 200%;animation:loadingline 1s linear infinite}@keyframes loadingline{0%{background-position-y:var(--cpu-timeline-height)}}#handheld-nav{max-height:calc(6px + calc(2 * var(--cpu-font-size)));padding-bottom:8px}.show-handheld-nav #handheld-nav{display:flex}#handheld-nav *{flex:1 0 auto;height:calc(2 * var(--cpu-font-size))}.hide-actions #actions{visibility:hidden;pointer-events:none;min-width:var(--cpu-min-padding);max-width:var(--cpu-min-padding)}#pageshare{text-align:center}#pageshare a{display:flex;align-items:center;justify-content:center;height:var(--cpu-height)}#pageshare a,#pageshare div{flex:1 0;color:#fff;text-decoration:none;overflow:hidden;text-overflow:clip}#pageshare svg{vertical-align:middle;width:32px;height:32px}#twitter{background:#4db5f4}#facebook,#nativeshare{background:#5974cc}#email{background:#c00}#link{background:#77f}#popup{pointer-events:none;position:absolute;transform:translate(-25px,-19px);z-index:127;min-width:50px;font-size:11px;text-align:center;padding:2px;border-radius:4px;box-shadow:#000 2px 2px;background:var(--cpu-popup-background);color:var(--cpu-popup-color);opacity:0}#popup:before{pointer-events:none;content:\"\";position:absolute;z-index:127;left:20px;bottom:-8px;width:0;height:0;border-top:8px solid var(--cpu-popup-background);border-left:4px solid transparent;border-right:4px solid transparent}.panel{display:flex;list-style:none;flex-direction:column;padding:0 var(--cpu-min-padding);box-shadow:var(--cpu-inner-shadow)}summary{text-align:center;list-style-type:revert;top:var(--cpu-height);box-shadow:var(--cpu-inner-shadow);padding:4px}summary::marker{content:'⍓\\u00A0'}[open]>summary::marker{content:'⍌\\u00A0'}.cue{border-top:1px solid #000;display:flex;margin:0;padding:2px}.cue strong{flex:1 1;font-weight:400}.cue time{flex:0 0 var(--cpu-elapse-width) 0px;text-align:right}.nocuetime time{display:none}.cue time,aside a{font-size:var(--cpu-font-small-size)}.mode-compact{width:calc(var(--cpu-elapse-width) + var(--cpu-height) * 2 + 32px)}.mode-button{width:var(--cpu-height)}.mode-button #about,.mode-button #actions,.mode-button #poster,.mode-button .panel,.mode-button aside,.mode-compact #actions,.mode-compact #line,.mode-compact #title,.mode-compact .panel,.mode-compact aside{width:0;display:none}#control svg,#handheld-nav,#pageshare #nativeshare,.hasnativeshare #pageshare .nonativeshare,.hide-chapters .chapters,.hide-panels .panel,.hide-panels-except-play .panel,.hide-panels-title summary,.hide-poster #poster,.hide-timeline #line,.media-streamed #line,.media-streamed #link,.mode-hidden,.no,.show-error #pagemain,.show-error #pageshare,.show-error #poster,.show-error .panel,.show-handheld-nav #titleline,.show-main #pageerror,.show-main #pageshare,.show-share #pageerror,.show-share #pagemain{display:none}.hasnativeshare #pageshare #nativeshare{display:flex}.mode-compact.show-main #pagemain{flex:0 0 auto}#pageshare div:hover,.active-cue,.with-preview,a:focus,a:hover,button:focus,button:hover,summary:focus{background:var(--cpu-focus-background,var(--cpu-color))!important;color:var(--cpu-focus-color,var(--cpu-background))!important;outline:0}@media (max-width:640px){.nosmall{display:none!important}#elapse{max-height:16px}#interface{--cpu-timeline-height:8px}#handheld-nav{padding-bottom:4px}}@media (max-width:480px){.nosmaller{display:none!important}.mode-default #elapse{flex:0 1 var(--cpu-elapse-width)}.mode-default #pagemain{padding-bottom:16px}#titleline{height:32px}#line{position:absolute;left:calc(0px - var(--cpu-height));right:calc(0px - var(--cpu-height));height:16px;top:32px}aside a{pointer-events:none}aside.borders{top:-2px}aside.chapters{top:8px}#handheld-nav{padding-bottom:2px}.siders svg{height:calc(var(--cpu-height) - 16px)}}@media (max-width:320px){.mode-default #elapse,.nosmallest{display:none!important}}@media print{#interface{display:none}}@media (prefers-reduced-motion:reduce){*{animation:none!important}}</style><div id=\"interface\"class=\"no\"tabindex=\"-1\"><main><img id=\"poster\"class=\"nosmall\"src=\"\"alt=\"\"loading=\"lazy\"decoding=\"async\"><section id=\"pageerror\"role=\"alert\"></section><section id=\"pagemain\"><button type=\"button\"id=\"control\"tabindex=\"0\"class=\"siders\"><svg id=\"loading\"viewBox=\"0 0 32 32\"aria-hidden=\"true\"><title>${__.loading}</title><circle cx=\"6\"cy=\"22\"r=\"4\"/><circle cx=\"16\"cy=\"22\"r=\"4\"/><circle cx=\"26\"cy=\"22\"r=\"4\"/></svg> <svg id=\"pause\"viewBox=\"0 0 32 32\"aria-hidden=\"true\"><title>${__.pause}</title><path d=\"M 6,6 12.667,6 12.667,26 6,26 z\"/><path d=\"M 19.333,6 26,6 26,26 19.333,26 z\"/></svg> <svg id=\"play\"viewBox=\"0 0 32 32\"aria-hidden=\"true\"><title>${__.play}</title><path d=\"M 6,6 6,26 26,16 z\"/></svg></button><div id=\"about\"><div id=\"titleline\"><strong id=\"title\"><a href=\"#\"id=\"canonical\"aria-label=\"${__.canonical}\"></a></strong> <a id=\"elapse\"aria-label=\"${__.moment}\"tabindex=\"-1\"><span id=\"currenttime\">…</span><span id=\"totaltime\"class=\"nosmaller\"></span></a></div><div id=\"handheld-nav\"><button type=\"button\"id=\"restart\"><svg viewBox=\"0 0 24 16\"aria-hidden=\"true\"><polygon points=\"4,0 8,0 8,16 4,16\"/><path d=\"M 16,0 8,8 16,16 z\"/><path d=\"M 24,0 16,8 24,16 z\"/></svg></button> <button type=\"button\"id=\"fastreward\"><svg viewBox=\"0 0 24 16\"aria-hidden=\"true\"><path d=\"M 8,0 0,8 8,16 z\"/><path d=\"M 16,0 8,8 16,16 z\"/><path d=\"M 24,0 16,8 24,16 z\"/></svg></button> <button type=\"button\"id=\"reward\"class=\"nosmallest\"><svg viewBox=\"0 0 24 16\"aria-hidden=\"true\"><path d=\"M 12,0 4,8 12,16 z\"/><path d=\"M 20,0 12,8 20,16 z\"/></svg></button> <button type=\"button\"id=\"foward\"><svg viewBox=\"0 0 24 16\"aria-hidden=\"true\"><path d=\"M 4,0 12,8 4,16 z\"/><path d=\"M 12,0 20,8 12,16 z\"/></svg></button> <button type=\"button\"id=\"fastfoward\"><svg viewBox=\"0 0 24 16\"aria-hidden=\"true\"><path d=\"M 0,0 8,8 0,16 z\"/><path d=\"M 8,0 16,8 8,16 z\"/><path d=\"M 16,0 24,8 16,16 z\"/></svg></button></div><div id=\"line\"><div id=\"time\"><div id=\"loadingline\"role=\"progressbar\"aria-labelledby=\"popup\"></div><time id=\"popup\">--:--</time></div></div></div><a href=\"#\"target=\"social\"id=\"link\"aria-label=\"${__.download}\"title=\"${__.download}\"download class=\"siders\"><svg viewBox=\"0 0 32 32\"aria-hidden=\"true\"><path d=\"M 6,6 26,6 16,22 z\"/><rect x=\"6\"y=\"22\"width=\"20\"height=\"4\"/></svg></a></section></main></div><style>/* Not the recommended way, but I didn't want to copy the whole scoped.css for invalidate only one^w a couple of rules */\n\t#link {\n\t\tbackground : none !important;\n\t}\n\t#link:hover, #link:focus {\n\t\tbackground: var(--cpu-focus-background, var(--cpu-color)) !important;\n\t}</style>`;\n\t\t\t}\n\t\t\n","import { selectorAcceptable, findCPU } from './primitives/utils.js';\nimport {CpuControllerElement} from './cpu_controller.class.js';\nimport { connectAudiotag } from './mediatag/extension.js';\nimport { timeInSeconds } from './primitives/convert.js';\nimport {build_chapters} from './build_chapters.js';\nimport {removeOfPlaylists, rePointsPlaylist} from './build_playlist.js';\n\n\n/**\n * @summary Interprets if <audio> element is modified or removed\n * TODO : act when a child change as <source> or <track>\n *\n * @param {Object} mutationsList The mutations list\n */\nfunction modifiedAudio([{target}]) {\n\tconst elCPU = findCPU(target);\n\n\t// in case <track> changed/removed\n\tbuild_chapters(elCPU);\n\n\t// in case attributes changed\n\telCPU.completeTemplate();\n\n\tconst globalController = document.CPU.globalController;\n\tif (elCPU.audiotag.isEqualNode(globalController?.audiotag)) {\n\t\tbuild_chapters(globalController);\n\t\tglobalController.completeTemplate();\n\t}\n}\n\n/**\n * Controller with assigned audio element\n *\n * @class CpuAudioElement (name)\n */\nexport class CpuAudioElement extends CpuControllerElement {\n\n\tconstructor() {\n\t\tsuper();\n\t\tthis.audiotag = this.querySelector(selectorAcceptable);\n\t\tif (!this.audiotag) {\n\t\t\tthis.remove();\n\t\t\treturn ;\n\t\t}\n\t\tthis.observer = null;\n\t}\n\n\tcopyAttributesToMediaDataset() {\n\t\tif (!this.audiotag) {\n\t\t\tthis.remove();\n\t\t\treturn ;\n\t\t}\n\t\t// copying personalized data to audio tag for persistence\n\t\tfor (const key in document.CPU.defaultDataset) {\n\t\t\tif (this.hasAttribute(key)) {\n\t\t\t\tconst value = this.getAttribute(key);\n\t\t\t\tthis.audiotag.dataset[key] = (key !== 'duration') ? value : timeInSeconds(value);\n\t\t\t}\n\t\t}\n\t}\n\n\tconnectedCallback() {\n\t\tif (!this.audiotag) {\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tthis.copyAttributesToMediaDataset();\n\n\t\tsuper.connectedCallback();\n\n\t\tconnectAudiotag(this.CPU.audiotag);\n\n\t\tthis.observer = new MutationObserver(modifiedAudio);\n\t\tthis.observer.observe(this, {\n\t\t\tchildList\t: true,\n\t\t\tattributes\t: true,\n\t\t\tsubtree\t\t: true\n\t\t});\n\n\t\tif (document.CPU.currentPlaylistID() === this.audiotag.dataset.playlist) {\n\t\t\trePointsPlaylist();\n\t\t}\n\t}\n\n\tdisconnectedCallback() {\n\t\tconst globalController = document.CPU.globalController;\n\t\tconst playlist_id = this.audiotag.dataset.playlist;\n\t\tif ((this.audiotag) && (globalController) && (this.audiotag.isEqualNode(globalController.audiotag))) {\n\t\t\t// we mode the audiotag into the global controller to keep the continuity status.\n\t\t\t// This audiotag will be released at the next switchControllerTo() call\n\t\t\tglobalController.element.appendChild(this.audiotag);\n\t\t} else {\n\t\t\tif (playlist_id) {\n\t\t\t\tremoveOfPlaylists(this.audiotag);\n\t\t\t}\n\t\t}\n\t\tsuper.disconnectedCallback();\n\t}\n}\n","import { warn } from './console.js';\n\nconst selector = 'script[data-cpu-audio]';\n\n/**\n * @private\n * @summary Get the global parameters stored in the <head> of the host document, else returns {}\n *\n * @return {object} The content of the stored content, else an empty object\n */\nexport function head_parameters() {\n\tconst tag = document.head.querySelector(selector);\n\tif (!tag) {\n\t\treturn {};\n\t}\n\ttry {\n\t\treturn JSON.parse(tag.innerHTML);\n\t} catch {\n\t\twarn(`invalid ${selector} parameter tag`);\n\t\treturn {};\n\t}\n}\n\nexport default head_parameters;","import { timeInSeconds } from '../primitives/convert.js';\nimport { selectorAudioInComponent } from '../primitives/utils.js';\nimport { oncePassiveEvent } from '../primitives/events.js';\nimport { warn } from '../primitives/console.js';\n\nimport { play } from './actions.js';\n\nimport { update } from '../trigger/update.js';\n\n/**\n * @public\n * @summary Position a timecode to a named audio tag\n *\n * @param {string} hash The id=\"\" of an <audio> tag\n * @param {string} timecode The timecode,\n * @param {Function|null|undefined} callback_fx Function to be called afterwards, for ending tests\n */\nexport const jumpIdAt = async function(hash, timecode, callback_fx=undefined) {\n\n\t/**\n\t * @param \t{Object}\tevent \ttriggered event, or mockup\n\t */\n\tfunction doNeedleMove({target:audiotag}) {\n\t\t// maybe we should add `timecode` in argument (timecode, event), and bind it to the event listener, moving the function upper\n\t\tconst secs = timeInSeconds(timecode);\n\t\tdocument.CPU.seekElementAt(audiotag, secs);\n\n\t\tconst mocked_event = {target : audiotag};\n\t\tif (audiotag.readyState >= audiotag.HAVE_FUTURE_DATA) {\n\t\t\tdoElementPlay(mocked_event);\n\t\t} else {\n\t\t\taudiotag.addEventListener('canplay', doElementPlay, oncePassiveEvent);\n\t\t}\n\t\tupdate(mocked_event);\n\t}\n\n\t/**\n\t * @param \t{Object}\tevent \ttriggered event, or mockup\n\t */\n\tfunction doElementPlay(event) {\n\t\tplay(null, event.target);\n\t\tcallback_fx?.();\n\t}\n\n\tconst audiotag = /** @type {HTMLAudioElement} */ ( (hash !== '') ? document.getElementById(hash) : document.querySelector(selectorAudioInComponent) );\n\n\tif ( ( audiotag?.currentTime ?? null ) == null ) {\n\t\twarn(`Unknow audiotag #${hash}`);\n\t\treturn;\n\t}\n\n\tconst mocked_event = {target : audiotag};\n\tif (audiotag.readyState < audiotag.HAVE_CURRENT_DATA) {\n\t\t// WHHYYYY ??????\n\t\taudiotag.addEventListener('loadedmetadata', doNeedleMove , oncePassiveEvent);\n\t\taudiotag.load();\n\t\tupdate(mocked_event);\n\n\t\treturn;\n\t}\n\n\tdoNeedleMove(mocked_event);\n\t// No problems\n};\n\nexport default jumpIdAt;","import { findCPU } from '../primitives/utils.js';\n\nimport { isAudiotagStreamed, uncertainPosition, normalizeSeekTime } from './time.js';\n\n/**\n * @summary Position a <audio> element to a time position\n * @public\n *\n * @param {HTMLAudioElement} audiotag <audio> DOM element\n * @param {number} seconds \tWanted position, in seconds\n *\n */\nexport const seekElementAt = function (audiotag, seconds) {\n\tif ((uncertainPosition(seconds)) || // may happens, if the audio track is not loaded/loadable\n\t\t(isAudiotagStreamed(audiotag))) { // never try to set a position on a streamed media\n\t\treturn;\n\t}\n\tseconds = normalizeSeekTime(audiotag, seconds);\n\n\tif (audiotag.fastSeek) {\n\t\t// HTMLAudioElement.fastSeek() is an experimental but really fast function. Firefox only, alas\n\t\t// Note that since the writing of this part, Safari aslo knows fastSeek(). It may be the root cause of some of my issues, as #149\n\t\taudiotag.fastSeek(seconds);\n\t} else {\n\t\ttry {\n\t\t\tconst settime = () => {audiotag.currentTime = seconds;} ;\n\t\t\t// Browsers may not have fastSeek but can set currentTime\n\t\t\tif (audiotag.readyState >= audiotag.HAVE_CURRENT_DATA) {\n\t\t\t\t// Chrome, Edge, and any other webkit-like except Safari on iPhone\n\t\t\t\tsettime();\n\t\t\t} else {\n\t\t\t\t// Safari on iPhone is totally incumbent on media throbbing\n\t\t\t\t// See https://github.com/dascritch/cpu-audio/issues/138#issuecomment-816526902\n\t\t\t\t// and https://stackoverflow.com/questions/18266437/html5-video-currenttime-not-setting-properly-on-iphone\n\t\t\t\taudiotag.load();\n\t\t\t settime();\n\t\t\t if (audiotag.currentTime < seconds){\n\t\t\t audiotag.addEventListener(\"loadedmetadata\", settime, { once: true });\n\t\t\t }\n\t\t\t}\n\t\t} catch(e) {\n\t\t\t// except sometimes, so you must use standard media fragment\n\t\t\taudiotag.src = `${audiotag.currentSrc.split('#')[0]}#t=${seconds}`;\n\t\t}\n\t}\n\n\t// it may be still constructing it, so be precautionous\n\tfindCPU(audiotag)?.updateLoading?.(seconds);\n};\n\nexport default seekElementAt;","import { findCPU } from './primitives/utils.js';\nimport { adjacentKey } from './primitives/operators.js';\nimport convert from './primitives/convert.js';\nimport head_parameters from './primitives/head_parameters.js';\n\nimport defaultParametersDocumentCPU from './bydefault/parameters.js';\nimport defaultDataset from './bydefault/dataset.js';\n\nimport { isAudiotagPlaying } from './mediatag/status.js';\nimport jumpIdAt from './mediatag/jump.js';\nimport seekElementAt from './mediatag/seek.js';\n\nimport trigger from './trigger/trigger.js';\n\n\nexport const DocumentCPU = {\n\t// global object for global API\n\n\t// public, parameters\n\t...defaultParametersDocumentCPU,\n\t// overrided parameters by integrator\n\t...head_parameters(),\n\n\tdefaultDataset,\n\n\t// public, actual active elements\n\t// @public\n\t// @type {HTMLAudioElement|null}\n\tcurrentAudiotagPlaying : null,\n\t// @type {CpuControllerElement|null}\n\t// @public\n\tglobalController : null,\n\n\t// private, indicate a play already occured in the DOM, so we can start any play\n\t// @private\n\t// @type boolean\n\thadPlayed : false,\n\n\t// private, indicate last used audiotag\n\t// @private\n\t// @type {HTMLAudioElement|null}\n\tlastUsed : null,\n\n\t// public, playlists\n\t// @public\n\t// @type Object\n\tplaylists : {},\n\n\t// public, Exposing internals needed for tests\n\t// @public\n\tconvert,\n\t// @public\n\ttrigger,\n\n\t// @public utilities to find CPU API\n\tfindCPU,\n\t// @public utilities for manipulations\n\tadjacentKey,\n\n\t/**\n\t * @public\n\t * @summary Determines if audiotag is currently playing.\n\t *\n\t * @param {HTMLAudioElement} audiotag The audiotag\n\t * @return {boolean} True if audiotag playing, False otherwise.\n\t */\n\tisAudiotagPlaying,\n\t/**\n\t * @public\n\t * @summary Determines if audiotag is displayed in <cpu-controller>\n\t *\n\t * @param {HTMLAudioElement} audiotag The audiotag\n\t * @return {boolean} True if audiotag global, False otherwise.\n\t */\n\tisAudiotagGlobal : function(audiotag) {\n\t\treturn this.globalController ? \n\t\t\taudiotag.isEqualNode(this.globalController.audiotag) : \n\t\t\tthis.isAudiotagPlaying(audiotag);\n\t},\n\n\t/**\n\t * @public\n\t * @summary Position a timecode to a named audio tag\n\t *\n\t * @param {string} hash The id=\"\" of an <audio> tag\n\t * @param {string} timecode The timecode,\n\t * @param {Function|null|undefined} callback_fx Function to be called afterwards, for ending tests\n\t */\n\tjumpIdAt,\n\n\t/**\n\t * @summary Position a <audio> element to a time position\n\t * @public\n\t *\n\t * @param {HTMLAudioElement} audiotag <audio> DOM element\n\t * @param {number} seconds \tWanted position, in seconds\n\t *\n\t */\n\tseekElementAt,\n\n\t/**\n\t * @summary Return the current playing playlist array\n\t * @public\n\t *\n\t * @return {Array} Array with named id\n\t */\n\tcurrentPlaylist : function() {\n\n\t\tconst current_audiotag = this.globalController?.audiotag;\n\t\tif (!current_audiotag) {\n\t\t\treturn [];\n\t\t}\n\n\t\tfor (const playlist of Object.values(this.playlists)) {\n\t\t\tif (playlist.includes(current_audiotag.id)) {\n\t\t\t\treturn playlist;\n\t\t\t}\n\t\t}\n\n\t\treturn [];\n\t},\n\n\t/**\n\t * @summary Return the current playing playlist ID\n\t * @public\n\t *\n\t * @return string|null\t\tNamed id\n\t */\n\tcurrentPlaylistID : function() {\n\t\tconst current_audiotag = this.globalController?.audiotag;\n\t\tif (!current_audiotag) {\n\t\t\treturn [];\n\t\t}\n\n\t\tfor (const playlist_name of Object.keys(this.playlists)) {\n\t\t\tif (this.playlists[playlist_name].includes(current_audiotag.id)) {\n\t\t\t\treturn playlist_name;\n\t\t\t}\n\t\t}\n\n\t\treturn null;\n\t}\n};\n","export const defaultParametersDocumentCPU = {\n\t// those values may be later modified via loading parameters\n\n\t// player basic\n\n\t// @public\n\t// @type boolean\n\tplayStopOthers : true,\n\t// @public\n\t// @type boolean\n\tscrollTo : false,\n\t// @public\n\t// @type boolean\n\tautoplay : false,\n\t// @public\n\t// @type string\n\tIDPrefix: 'CPU-Audio-tag-',\n\n\t// interface building\n\n\t// @public\n\t// @type boolean\n\tglobalCss : true,\n\n\t// playlist interactions\n\n\t// @public\n\t// @type boolean\n\tadvanceInPlaylist : true,\n\n\t// Keyboard navigation\n\n\t// @public\n\t// @type number\n\tkeymove : 5,\n\n\t// Precise navigation with fingers\n\n\t// @public\n\t// @type number\n\talternateDelay : 1000,\n\t// @public\n\t// @type number\n\tfastFactor : 4,\n\t// @public\n\t// @type number\n\trepeatDelay : 400,\n\t// @public\n\t// @type number\n\trepeatFactor : 100,\n\n};\n\nexport default defaultParametersDocumentCPU;","/**\n * @public\n * @summary Determines if audiotag is currently playing.\n *\n * @param {HTMLAudioElement} audiotag The audiotag\n * @return {boolean} True if audiotag playing, False otherwise.\n */\nexport const isAudiotagPlaying = function(audiotag) {\n\tconst currentAudiotagPlaying = document.CPU.currentAudiotagPlaying;\n\treturn (currentAudiotagPlaying) && (audiotag.isEqualNode(currentAudiotagPlaying));\n};\n\n","import { CpuAudioTagName, CpuControllerTagName, selectorAcceptable, querySelectorDo } from './primitives/utils.js';\nimport { passiveEvent } from './primitives/events.js';\nimport { browserIsDecent } from './primitives/checkers.js';\nimport { warn } from './primitives/console.js';\n\nimport {CpuAudioElement} from './cpu_audio.class.js';\nimport {CpuControllerElement} from './cpu_controller.class.js';\nimport { attach_events_audiotag } from './mediatag/extension.js';\nimport { DocumentCPU } from './document_cpu.js';\nimport {insert_style} from '../tmp/insert_template.js';\nimport { hashOrder } from './trigger/hash_order.js';\n\n/**\n * Entry point\n *\n * @return {Promise} No returned value\n */\nasync function main() {\n\t// TO DO : Try to load here global parameters, cf #185\n\n\tlet global_class_indicator;\n\tif (!browserIsDecent) {\n\t\tglobal_class_indicator = 'without-webcomponents';\n\t\twarn(`WebComponent may NOT behave correctly on this browser. Only timecode hash links are activated.\\nSee https://github.com/dascritch/cpu-audio/ for details`);\n\t\tquerySelectorDo(selectorAcceptable, attach_events_audiotag);\n\t} else {\n\t\tglobal_class_indicator = 'with-webcomponents';\n\t\tif (DocumentCPU.globalCss) {\n\t\t\tinsert_style();\n\t\t}\n\t\twindow.customElements.define(CpuAudioTagName.toLowerCase(), CpuAudioElement);\n\t\twindow.customElements.define(CpuControllerTagName.toLowerCase(), CpuControllerElement);\n\t}\n\tdocument.body.classList.add(`cpu-audio-${global_class_indicator}`);\n\twindow.addEventListener('hashchange', hashOrder, passiveEvent);\n\thashOrder({ at_start : true });\n}\n\nif ((document.CPU) || (window.customElements.get(CpuAudioTagName.toLowerCase()))) {\n\twarn('cpu-audio is called twice');\n} else {\n\t// Here comes document.CPU\n\tHTMLDocument.prototype.CPU = DocumentCPU;\n\n\tdocument.addEventListener('DOMContentLoaded', main, passiveEvent);\n\tif ( document.readyState !== 'loading' ) {\n\t\t// document may already be loaded and DOMContentLoaded fired.\n\t\tmain();\n\t}\n}\n"],"sourceRoot":""}