2022-03-21 17:43:24 +13:00
// If you want to use Phoenix channels, run `mix help phx.gen.channel`
// to get started and then uncomment the line below.
// import "./user_socket.js"
// You can include dependencies in two ways.
//
// The simplest option is to put them in assets/vendor and
// import them using relative paths:
//
// import "../vendor/some-package.js"
//
// Alternatively, you can `npm install some-package --prefix assets` and import
// them using a path starting with the package name:
//
// import "some-package"
//
2022-09-08 03:53:36 +12:00
import scrollIntoView from "smooth-scroll-into-view-if-needed" ;
2022-03-21 17:43:24 +13:00
// Include phoenix_html to handle method=PUT/DELETE in forms and buttons.
2022-09-08 03:53:36 +12:00
import "phoenix_html" ;
2022-03-21 17:43:24 +13:00
// Establish Phoenix Socket and LiveView configuration.
2022-09-08 03:53:36 +12:00
import { Socket } from "phoenix" ;
import { LiveSocket } from "phoenix_live_view" ;
import topbar from "../vendor/topbar" ;
2022-03-26 10:17:01 +13:00
2023-02-07 06:35:52 +13:00
function setCookie ( name , value ) {
document . cookie = name + "=" + value + ";path=/;" + "expires=Fri, 31 Dec 9999 23:59:59 GMT;" ;
}
2022-09-06 05:47:12 +12:00
2023-02-07 06:35:52 +13:00
function getCookie ( name ) {
const cookie = document . cookie . split ( "; " ) . find ( ( row ) => row . startsWith ( name + "=" ) )
if ( cookie ) {
return cookie . split ( "=" ) [ 1 ]
}
}
function cookiesAreAllowed ( ) {
return getCookie ( "cookieconsent_status" ) === "allow"
2022-09-06 05:47:12 +12:00
}
2022-10-26 17:53:18 +13:00
function get _platform ( ) {
// 2022 way of detecting. Note : this userAgentData feature is available only in secure contexts (HTTPS)
if ( typeof navigator . userAgentData !== 'undefined' && navigator . userAgentData != null ) {
return navigator . userAgentData . platform ;
}
// Deprecated but still works for most of the browser
if ( typeof navigator . platform !== 'undefined' ) {
if ( typeof navigator . userAgent !== 'undefined' && /android/ . test ( navigator . userAgent . toLowerCase ( ) ) ) {
// android device's navigator.platform is often set as 'linux', so let's use userAgent for them
return 'android' ;
}
return navigator . platform ;
}
return 'unknown' ;
}
let platform = get _platform ( ) ;
let isOSX = /mac/ . test ( platform . toLowerCase ( ) ) ; // Mac desktop
2022-03-26 10:17:01 +13:00
const Hooks = { } ;
2022-09-06 05:29:38 +12:00
let configuredThemeRow ;
2022-09-08 03:53:36 +12:00
if ( cookiesAreAllowed ( ) ) {
2023-02-07 06:35:52 +13:00
configuredThemeRow = getCookie ( "theme" )
2022-09-06 05:29:38 +12:00
}
2022-04-02 11:49:26 +13:00
if ( ! configuredThemeRow ) {
2022-09-08 03:53:36 +12:00
if (
window . matchMedia &&
window . matchMedia ( "(prefers-color-scheme: dark)" ) . matches
) {
2022-09-06 05:29:38 +12:00
setTheme ( "dark" ) ;
2022-04-02 11:49:26 +13:00
} else {
2022-09-06 05:29:38 +12:00
setTheme ( "light" ) ;
2022-04-02 11:49:26 +13:00
}
}
2022-09-08 03:53:36 +12:00
window
. matchMedia ( "(prefers-color-scheme: dark)" )
. addEventListener ( "change" , ( event ) => {
let configuredThemeRow ;
if ( cookiesAreAllowed ( ) ) {
2023-02-07 06:35:52 +13:00
getCookie ( "theme" )
2022-09-08 03:53:36 +12:00
}
2022-04-02 11:49:26 +13:00
2022-09-08 03:53:36 +12:00
if ( ! configuredThemeRow || configuredThemeRow === "theme=system" ) {
setTheme ( "system" ) ;
2022-08-30 16:25:13 +12:00
} else {
2022-09-08 03:53:36 +12:00
if ( configuredThemeRow === "theme=dark" ) {
setTheme ( "dark" ) ;
} else if ( configuredThemeRow === "theme=light" ) {
setTheme ( "light" ) ;
} else {
setTheme ( "system" ) ;
}
2022-08-30 16:25:13 +12:00
}
2022-09-08 03:53:36 +12:00
} ) ;
2022-04-02 11:49:26 +13:00
2022-09-06 05:29:38 +12:00
function setTheme ( theme , set ) {
2022-04-02 11:49:26 +13:00
let setTheme ;
2022-09-08 03:53:36 +12:00
if ( theme == "system" ) {
if (
window . matchMedia &&
window . matchMedia ( "(prefers-color-scheme: dark)" ) . matches
) {
2022-04-02 11:49:26 +13:00
setTheme = "dark" ;
} else {
setTheme = "light" ;
}
2022-08-30 16:25:13 +12:00
} else {
setTheme = theme ;
2022-04-02 11:49:26 +13:00
}
2022-08-30 16:25:13 +12:00
2022-04-02 11:49:26 +13:00
document . documentElement . classList . add ( setTheme ) ;
2022-08-30 16:25:13 +12:00
2022-09-08 03:53:36 +12:00
if ( setTheme === "dark" ) {
2022-04-02 11:49:26 +13:00
document . documentElement . classList . remove ( "light" ) ;
} else {
document . documentElement . classList . remove ( "dark" ) ;
2022-09-08 03:53:36 +12:00
}
2022-04-02 11:49:26 +13:00
2022-09-08 03:53:36 +12:00
if ( set && cookiesAreAllowed ( ) ) {
2023-02-07 06:35:52 +13:00
setCookie ( "theme" , theme )
2022-09-06 05:29:38 +12:00
}
2022-04-02 11:49:26 +13:00
}
2022-03-26 10:17:01 +13:00
Hooks . ColorTheme = {
mounted ( ) {
2022-09-08 03:53:36 +12:00
this . handleEvent ( "set_theme" , ( payload ) => {
setTheme ( payload . theme , true ) ;
} ) ;
} ,
} ;
2022-03-26 10:17:01 +13:00
2022-11-16 14:27:24 +13:00
let scrolled = false ;
Hooks . RightNav = {
mounted ( ) {
this . intersectionObserver =
new IntersectionObserver ( ( entries ) =>
this . onScrollChange ( entries ) , { rootMargin : "-10% 0px -89% 0px" }
) ;
this . observeElements ( )
window . addEventListener ( "hashchange" , ( event ) => { this . handleHashChange ( ) ; } ) ;
} ,
updated ( ) {
this . intersectionObserver . disconnect ( ) ;
this . observeElements ( ) ;
} ,
observeElements ( ) {
for ( el of document . querySelectorAll ( "#docs-window .nav-anchor" ) ) {
this . intersectionObserver . observe ( el ) ;
2022-04-01 09:59:53 +13:00
}
2022-11-16 14:27:24 +13:00
} ,
onScrollChange ( entries ) {
// Wait for scrolling from initial page load to complete
if ( ! scrolled ) { return ; }
for ( entry of entries ) {
if ( entry . isIntersecting ) {
this . setAriaCurrent ( entry . target . id ) ;
2022-04-01 09:59:53 +13:00
}
}
2022-11-16 14:27:24 +13:00
} ,
handleHashChange ( ) {
if ( window . location . hash ) {
this . setAriaCurrent ( window . location . hash . substring ( 1 ) )
2022-04-01 09:59:53 +13:00
2022-11-16 14:27:24 +13:00
// Disable the insersection observer for 1s while the browser
// scrolls the selected element to the top.
scrolled = false ;
setTimeout ( ( ) => { scrolled = true } , 1000 ) ;
}
} ,
setAriaCurrent ( id ) {
const el = document . getElementById ( "right-nav-" + id ) ;
2022-09-08 03:53:36 +12:00
if ( el ) {
2022-11-16 14:27:24 +13:00
for ( elem of document . querySelectorAll ( '#right-nav a[aria-current]' ) ) {
elem . removeAttribute ( 'aria-current' ) ;
2022-04-01 09:59:53 +13:00
}
2022-11-16 14:27:24 +13:00
el . setAttribute ( "aria-current" , "true" ) ;
2022-04-01 09:59:53 +13:00
}
2023-01-25 17:34:22 +13:00
} ,
} ;
2023-02-07 17:29:23 +13:00
Hooks . TextOverflow = {
2023-01-25 17:34:22 +13:00
mounted ( ) {
this . setTitlesForOverflowingLinks ( this . el ) ;
} ,
updated ( ) {
this . setTitlesForOverflowingLinks ( this . el ) ;
} ,
setTitlesForOverflowingLinks ( selector ) {
2023-02-07 17:29:23 +13:00
for ( elem of selector . querySelectorAll ( "a, span.text-ellipsis" ) ) {
2023-01-25 17:34:22 +13:00
if ( elem . offsetWidth < elem . scrollWidth ) {
elem . setAttribute ( "title" , elem . innerHTML . trim ( ) ) ;
}
}
} ,
} ;
2022-04-01 09:59:53 +13:00
2023-02-07 17:29:23 +13:00
Hooks . TableOfContentsTextOverflow = Hooks . TextOverflow ;
2022-09-08 03:53:36 +12:00
let csrfToken = document
. querySelector ( "meta[name='csrf-token']" )
. getAttribute ( "content" ) ;
2022-03-26 10:17:01 +13:00
let liveSocket = new LiveSocket ( "/live" , Socket , {
2022-11-16 14:27:24 +13:00
params : { _csrf _token : csrfToken , user _agent : window . navigator . userAgent } ,
2022-03-26 10:17:01 +13:00
hooks : Hooks ,
metadata : {
keydown : ( e ) => {
return {
key : e . key ,
2022-09-08 03:53:36 +12:00
metaKey : e . metaKey ,
} ;
} ,
} ,
2022-03-26 10:17:01 +13:00
} ) ;
2022-03-21 17:43:24 +13:00
2022-03-29 11:05:19 +13:00
// Show progress bar on live navigation and form submits. Only displays if still
// loading after 120 msec
2022-09-08 03:53:36 +12:00
topbar . config ( { barColors : { 0 : "#29d" } , shadowColor : "rgba(0, 0, 0, .3)" } ) ;
2022-03-29 11:05:19 +13:00
let topBarScheduled = undefined ;
2023-02-02 18:51:54 +13:00
window . addEventListener ( "phx:page-loading-start" , ( { detail } ) => {
2022-09-13 05:44:52 +12:00
scrolled = false ;
2022-10-26 17:28:25 +13:00
// close mobile sidebar on navigation
2022-11-16 14:27:24 +13:00
mobileSideBar = document . getElementById ( "mobile-sidebar-hide" )
if ( mobileSideBar ) {
2022-10-26 17:28:25 +13:00
mobileSideBar . click ( )
}
2023-02-06 15:30:29 +13:00
if ( ! topBarScheduled ) {
topBarScheduled = setTimeout ( ( ) => topbar . show ( ) , 120 ) ;
2022-09-08 03:53:36 +12:00
}
2022-03-29 11:05:19 +13:00
} ) ;
2022-09-13 05:44:52 +12:00
2022-11-16 14:27:24 +13:00
window . addEventListener ( "phx:page-loading-stop" , ( { detail } ) => {
2022-03-29 11:05:19 +13:00
clearTimeout ( topBarScheduled ) ;
2023-02-02 18:51:54 +13:00
topbar . hide ( ) ;
2022-03-29 11:05:19 +13:00
topBarScheduled = undefined ;
2022-11-16 14:27:24 +13:00
let scrollEl ;
if ( detail . kind === "initial" && window . location . hash ) {
scrollEl = document . getElementById ( window . location . hash . substring ( 1 ) ) ;
} else if ( detail . kind == "patch" && ! window . location . hash ) {
scrollEl = document . querySelector ( "#docs-window .nav-anchor" ) || document . querySelector ( "#docs-window h1" ) ;
}
if ( scrollEl ) {
Hooks . RightNav . setAriaCurrent ( scrollEl . id ) ;
// Not using scroll polyfill here - doesn't respect scroll-padding-top CSS
scrollEl . scrollIntoView ( { block : 'start' } )
setTimeout ( ( ) => { scrolled = true ; } , 1000 ) ;
} else {
scrolled = true ;
2022-09-13 05:44:52 +12:00
}
2022-03-29 11:05:19 +13:00
} ) ;
2022-09-08 03:53:36 +12:00
window . addEventListener ( "js:focus" , ( e ) => e . target . focus ( ) ) ;
2022-03-21 17:43:24 +13:00
2022-03-26 16:16:20 +13:00
window . addEventListener ( "phx:js:scroll-to" , ( e ) => {
const target = document . getElementById ( e . detail . id ) ;
2022-11-16 14:27:24 +13:00
const boundary = target . closest ( ".scroll-parent" ) ;
2022-09-08 03:53:36 +12:00
scrollIntoView ( target , {
behavior : "smooth" ,
2022-09-13 05:44:52 +12:00
block : "start" ,
2022-09-08 03:53:36 +12:00
boundary : boundary ,
2022-03-28 10:26:35 +13:00
} ) ;
2022-03-26 16:16:20 +13:00
} ) ;
2022-03-28 10:26:35 +13:00
window . addEventListener ( "phx:selected-versions" , ( e ) => {
2022-09-08 03:53:36 +12:00
if ( cookiesAreAllowed ( ) ) {
const cookie = Object . keys ( e . detail )
. map ( ( key ) => ` ${ key } : ${ e . detail [ key ] } ` )
. join ( "," ) ;
2023-02-07 06:35:52 +13:00
setCookie ( "selected_versions" , cookie )
2022-09-06 05:29:38 +12:00
}
2022-03-28 10:26:35 +13:00
} ) ;
2022-03-26 16:16:20 +13:00
2022-03-30 17:40:17 +13:00
window . addEventListener ( "phx:selected-types" , ( e ) => {
2022-09-08 03:53:36 +12:00
if ( cookiesAreAllowed ( ) ) {
const cookie = e . detail . types . join ( "," ) ;
2023-02-07 06:35:52 +13:00
setCookies ( "selected_types" , cookie )
2022-09-06 05:29:38 +12:00
}
2022-03-30 17:40:17 +13:00
} ) ;
2022-03-30 18:07:17 +13:00
window . addEventListener ( "keydown" , ( event ) => {
2022-09-08 03:53:36 +12:00
if ( ( event . metaKey || event . ctrlKey ) && event . key === "k" ) {
document . getElementById ( "search-button" ) . click ( ) ;
2022-04-02 08:11:17 +13:00
event . preventDefault ( ) ;
2022-03-30 18:07:17 +13:00
}
2022-09-08 03:53:36 +12:00
} ) ;
2022-03-30 18:07:17 +13:00
window . addEventListener ( "keydown" , ( event ) => {
2022-09-08 03:53:36 +12:00
if ( event . key === "Escape" ) {
2022-09-28 16:18:05 +13:00
const closeSearchVersions = document . getElementById ( "close-search-versions" ) ;
2022-11-16 14:27:24 +13:00
if ( closeSearchVersions && closeSearchVersions . offsetParent !== null ) {
2022-09-28 16:18:05 +13:00
closeSearchVersions . click ( )
} else {
document . getElementById ( "close-search" ) . click ( ) ;
}
2022-04-02 08:11:17 +13:00
event . preventDefault ( ) ;
2022-03-30 18:07:17 +13:00
}
2022-09-08 03:53:36 +12:00
} ) ;
2022-11-26 20:53:55 +13:00
2023-02-01 05:13:42 +13:00
window . addEventListener ( "phx:catalogue-call-to-action-dismissed" , ( event ) => {
if ( cookiesAreAllowed ( ) ) {
2023-02-07 06:35:52 +13:00
setCookie ( "catalogue_call_to_action_dismissed" , "true" )
2023-02-01 05:13:42 +13:00
}
} ) ;
2022-11-26 20:53:55 +13:00
window . addEventListener ( "phx:click-on-item" , ( event ) => {
document . getElementById ( event . detail . id ) . click ( ) ;
document . getElementById ( "close-search" ) . click ( ) ;
event . preventDefault ( ) ;
} ) ;
2022-04-02 08:11:17 +13:00
window . addEventListener ( "phx:close-search" , ( event ) => {
2022-09-08 03:53:36 +12:00
document . getElementById ( "close-search" ) . click ( ) ;
2022-04-02 08:11:17 +13:00
event . preventDefault ( ) ;
2022-09-08 03:53:36 +12:00
} ) ;
2022-03-30 18:07:17 +13:00
2022-03-21 17:43:24 +13:00
// connect if there are any LiveViews on the page
2022-09-08 03:53:36 +12:00
liveSocket . connect ( ) ;
2022-03-21 17:43:24 +13:00
// expose liveSocket on window for web console debug logs and latency simulation:
2022-09-13 12:35:59 +12:00
// liveSocket.disableDebug();
2022-03-21 17:43:24 +13:00
// >> liveSocket.enableLatencySim(1000) // enabled for duration of browser session
// >> liveSocket.disableLatencySim()
2022-09-08 03:53:36 +12:00
window . liveSocket = liveSocket ;
2023-01-30 16:21:50 +13:00
window . addEventListener ( "load" , function ( ) {
window . cookieconsent . initialise ( {
content : {
message :
"Hi, this website uses essential cookies for remembering your explicitly set preferences, if you opt-in. We do not use google analytics, but we do use plausible.io, an ethical google analytics alternative which does not use any cookies and collects no personal data." ,
link : null ,
} ,
type : "opt-in" ,
palette : {
popup : {
background : "#000" ,
} ,
button : {
background : "#f1d600" ,
} ,
} ,
} ) ;
} ) ;