Refactor fullscreen player to not rely on hacks, use real router
This commit is contained in:
parent
34ccbefa72
commit
3b3387f636
11 changed files with 138 additions and 121 deletions
|
@ -1,7 +1,3 @@
|
||||||
export function requestAnimationFrame(callback) {
|
export function requestAnimationFrame(callback) {
|
||||||
globalThis.requestAnimationFrame(callback);
|
globalThis.requestAnimationFrame(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function preventPopstate() {
|
|
||||||
globalThis.history.pushState({}, "");
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import gleam/option
|
||||||
import gleam/float
|
import gleam/float
|
||||||
import gleam/int
|
import gleam/int
|
||||||
import gleam/result
|
import gleam/result
|
||||||
|
import gleam/set
|
||||||
import gleam/javascript/promise
|
import gleam/javascript/promise
|
||||||
import lustre/element.{text}
|
import lustre/element.{text}
|
||||||
import lustre/element/html.{div, nav, p}
|
import lustre/element/html.{div, nav, p}
|
||||||
|
@ -90,8 +91,10 @@ pub fn init(auth_data: common.AuthData) {
|
||||||
effect.from(fn(dispatch) { router.init(dispatch) })
|
effect.from(fn(dispatch) { router.init(dispatch) })
|
||||||
|> effect.map(Router)
|
|> effect.map(Router)
|
||||||
|
|
||||||
|
let #(path, _query) = router.get_current_path()
|
||||||
|
|
||||||
let initial_view =
|
let initial_view =
|
||||||
router.get_current_path()
|
path
|
||||||
|> router.parse()
|
|> router.parse()
|
||||||
|> result.unwrap(router.TrackList)
|
|> result.unwrap(router.TrackList)
|
||||||
|> route_to_view()
|
|> route_to_view()
|
||||||
|
@ -194,12 +197,33 @@ pub fn update(model: Model, msg) {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Router(router.RouteChanged(route)) -> {
|
Router(router.RouteChanged(route_and_query)) -> {
|
||||||
case route_to_view(route) {
|
case route_to_view(route_and_query.route) {
|
||||||
Ok(view) -> #(Model(..model, view: view), effect.none())
|
Ok(view) -> {
|
||||||
|
let view_updated = Model(..model, view: view)
|
||||||
|
if_player(view_updated, fn(info) {
|
||||||
|
let msg = case
|
||||||
|
set.contains(route_and_query.query, router.FullScreen)
|
||||||
|
{
|
||||||
|
True -> player.FullScreenOpened
|
||||||
|
False -> player.FullScreenClosed
|
||||||
|
}
|
||||||
|
|
||||||
|
let #(player_model, e) =
|
||||||
|
utils.update_child(info.player, msg, player.update, PlayerMsg)
|
||||||
|
|
||||||
|
#(
|
||||||
|
Model(
|
||||||
|
..view_updated,
|
||||||
|
play_status: HasTracks(PlayInfo(..info, player: player_model)),
|
||||||
|
),
|
||||||
|
e,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
Error(_) -> {
|
Error(_) -> {
|
||||||
io.println_error("Unable to change to route:")
|
io.println_error("Unable to change to route:")
|
||||||
io.debug(route)
|
io.debug(route_and_query)
|
||||||
#(model, effect.none())
|
#(model, effect.none())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -223,15 +247,24 @@ pub fn view(model: Model) {
|
||||||
div([attribute.id("authed-view-library")], [
|
div([attribute.id("authed-view-library")], [
|
||||||
nav([attribute.id("library-top-nav")], [
|
nav([attribute.id("library-top-nav")], [
|
||||||
button_group.view("", [], [
|
button_group.view("", [], [
|
||||||
link.button(router.to_hash(router.TrackList), "", [], [
|
link.button(
|
||||||
icon("music-note-beamed", Alt("Tracks")),
|
router.to_hash(router.queryless(router.TrackList)),
|
||||||
]),
|
"",
|
||||||
link.button(router.to_hash(router.ArtistList), "", [], [
|
[],
|
||||||
icon("file-person", Alt("Artists")),
|
[icon("music-note-beamed", Alt("Tracks"))],
|
||||||
]),
|
),
|
||||||
link.button(router.to_hash(router.AlbumList), "", [], [
|
link.button(
|
||||||
icon("disc", Alt("Albums")),
|
router.to_hash(router.queryless(router.ArtistList)),
|
||||||
]),
|
"",
|
||||||
|
[],
|
||||||
|
[icon("file-person", Alt("Artists"))],
|
||||||
|
),
|
||||||
|
link.button(
|
||||||
|
router.to_hash(router.queryless(router.AlbumList)),
|
||||||
|
"",
|
||||||
|
[],
|
||||||
|
[icon("disc", Alt("Albums"))],
|
||||||
|
),
|
||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
case model.view {
|
case model.view {
|
||||||
|
@ -397,7 +430,6 @@ fn route_to_view(route: router.Route) {
|
||||||
router.ArtistList -> Ok(library_view.Artists)
|
router.ArtistList -> Ok(library_view.Artists)
|
||||||
router.AlbumList -> Ok(library_view.Albums)
|
router.AlbumList -> Ok(library_view.Albums)
|
||||||
router.Artist(id) -> Ok(library_view.SingleArtist(id))
|
router.Artist(id) -> Ok(library_view.SingleArtist(id))
|
||||||
// TODO
|
|
||||||
router.Album(id) -> Ok(library_view.SingleAlbum(id))
|
router.Album(id) -> Ok(library_view.SingleAlbum(id))
|
||||||
// TODO
|
// TODO
|
||||||
router.Settings -> Error(Nil)
|
router.Settings -> Error(Nil)
|
||||||
|
|
|
@ -31,7 +31,7 @@ pub fn view(
|
||||||
|
|
||||||
[
|
[
|
||||||
link.link(
|
link.link(
|
||||||
router.to_hash(router.Album(album_id)),
|
router.to_hash(router.queryless(router.Album(album_id))),
|
||||||
"library-item album-item",
|
"library-item album-item",
|
||||||
[attribute.id("album-list-" <> album_id_str)],
|
[attribute.id("album-list-" <> album_id_str)],
|
||||||
[
|
[
|
||||||
|
|
|
@ -72,7 +72,7 @@ fn item_view(
|
||||||
let artist_id_str = int.to_string(artist_id)
|
let artist_id_str = int.to_string(artist_id)
|
||||||
[
|
[
|
||||||
link.link(
|
link.link(
|
||||||
router.to_hash(router.Artist(artist_id)),
|
router.to_hash(router.queryless(router.Artist(artist_id))),
|
||||||
"library-item artist-item",
|
"library-item artist-item",
|
||||||
[attribute.id("artist-list-" <> artist_id_str)],
|
[attribute.id("artist-list-" <> artist_id_str)],
|
||||||
[
|
[
|
||||||
|
|
|
@ -46,7 +46,8 @@ pub type Msg {
|
||||||
ComponentInitialised
|
ComponentInitialised
|
||||||
ActionTriggered(actions.Action)
|
ActionTriggered(actions.Action)
|
||||||
PositionSelected(Int)
|
PositionSelected(Int)
|
||||||
FullScreenEscaped
|
FullScreenOpened
|
||||||
|
FullScreenClosed
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(
|
pub fn init(
|
||||||
|
@ -156,22 +157,6 @@ pub fn update(model: Model, msg) {
|
||||||
let pos = current_track_position()
|
let pos = current_track_position()
|
||||||
#(Model(..model, position: pos), effect.none())
|
#(Model(..model, position: pos), effect.none())
|
||||||
}
|
}
|
||||||
|
|
||||||
actions.ToggleFullScreen -> {
|
|
||||||
let #(new_mode, toggle_effect) = case model.view_mode {
|
|
||||||
model.Small -> #(
|
|
||||||
model.FullScreen,
|
|
||||||
effect.from(fn(dispatch) { register_back_preventor(dispatch) }),
|
|
||||||
)
|
|
||||||
|
|
||||||
model.FullScreen -> {
|
|
||||||
unregister_back_preventor()
|
|
||||||
#(model.Small, effect.none())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#(Model(..model, view_mode: new_mode), toggle_effect)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StartPlay(track_id, track) -> {
|
StartPlay(track_id, track) -> {
|
||||||
|
@ -252,8 +237,10 @@ pub fn update(model: Model, msg) {
|
||||||
|
|
||||||
#(Model(..model, audio_source: option.Some(source)), effect.none())
|
#(Model(..model, audio_source: option.Some(source)), effect.none())
|
||||||
}
|
}
|
||||||
FullScreenEscaped -> {
|
FullScreenOpened -> {
|
||||||
unregister_back_preventor()
|
#(Model(..model, view_mode: model.FullScreen), effect.none())
|
||||||
|
}
|
||||||
|
FullScreenClosed -> {
|
||||||
#(Model(..model, view_mode: model.Small), effect.none())
|
#(Model(..model, view_mode: model.Small), effect.none())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -320,14 +307,6 @@ fn event_timeupdate(_: a) {
|
||||||
Ok(UpdateTime(current_time()))
|
Ok(UpdateTime(current_time()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_back_preventor(dispatch: fn(Msg) -> Nil) {
|
|
||||||
enable_prevent_popstate(fn() { dispatch(FullScreenEscaped) })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unregister_back_preventor() {
|
|
||||||
disable_prevent_popstate()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_play(
|
fn start_play(
|
||||||
settings: common.Settings,
|
settings: common.Settings,
|
||||||
artist: Artist,
|
artist: Artist,
|
||||||
|
@ -403,9 +382,3 @@ fn connect_gain(
|
||||||
|
|
||||||
@external(javascript, "../../../player_ffi.mjs", "linearRampToValue")
|
@external(javascript, "../../../player_ffi.mjs", "linearRampToValue")
|
||||||
fn linear_ramp_to_value(node: GainNode, gain: Float, at: Float) -> Nil
|
fn linear_ramp_to_value(node: GainNode, gain: Float, at: Float) -> Nil
|
||||||
|
|
||||||
@external(javascript, "../../../player_ffi.mjs", "enablePreventPopstate")
|
|
||||||
fn enable_prevent_popstate(callback: fn() -> Nil) -> Nil
|
|
||||||
|
|
||||||
@external(javascript, "../../../player_ffi.mjs", "disablePreventPopstate")
|
|
||||||
fn disable_prevent_popstate() -> Nil
|
|
||||||
|
|
|
@ -12,5 +12,4 @@ pub type Action {
|
||||||
StartUserSkip
|
StartUserSkip
|
||||||
EndUserSkip
|
EndUserSkip
|
||||||
SelectPosition(type_: PositionSelection)
|
SelectPosition(type_: PositionSelection)
|
||||||
ToggleFullScreen
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,11 @@ import elekf/web/components/icon.{Alt, icon}
|
||||||
import elekf/web/components/track_length.{track_length}
|
import elekf/web/components/track_length.{track_length}
|
||||||
import elekf/web/components/button_group
|
import elekf/web/components/button_group
|
||||||
import elekf/web/components/button
|
import elekf/web/components/button
|
||||||
|
import elekf/web/components/link
|
||||||
import elekf/web/components/thumbnail
|
import elekf/web/components/thumbnail
|
||||||
import elekf/web/components/player/actions.{
|
import elekf/web/components/player/actions.{
|
||||||
Commit, EndUserSkip, Ephemeral, NextTrack, Pause, Play, PrevTrack,
|
Commit, EndUserSkip, Ephemeral, NextTrack, Pause, Play, PrevTrack,
|
||||||
SelectPosition, StartUserSkip, ToggleFullScreen,
|
SelectPosition, StartUserSkip,
|
||||||
}
|
}
|
||||||
import elekf/web/components/player/model.{type Model}
|
import elekf/web/components/player/model.{type Model}
|
||||||
|
|
||||||
|
@ -65,12 +66,10 @@ pub fn view(model: Model) {
|
||||||
[attribute.id("player-next"), event.on_click(NextTrack)],
|
[attribute.id("player-next"), event.on_click(NextTrack)],
|
||||||
[icon("skip-forward-fill", Alt("Next"))],
|
[icon("skip-forward-fill", Alt("Next"))],
|
||||||
),
|
),
|
||||||
button.view(
|
link.button(
|
||||||
|
"javascript:history.back()",
|
||||||
"",
|
"",
|
||||||
[
|
[attribute.id("player-fullscreen-toggle")],
|
||||||
attribute.id("player-fullscreen-toggle"),
|
|
||||||
event.on_click(ToggleFullScreen),
|
|
||||||
],
|
|
||||||
[icon("arrows-angle-contract", Alt("Small player"))],
|
[icon("arrows-angle-contract", Alt("Small player"))],
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import gleam/uri
|
import gleam/uri
|
||||||
import gleam/option
|
import gleam/option
|
||||||
import plinth/browser/event
|
|
||||||
import ibroadcast/authed_request.{type RequestConfig}
|
import ibroadcast/authed_request.{type RequestConfig}
|
||||||
import elekf/web/common
|
import elekf/web/common
|
||||||
import elekf/library.{type Library}
|
import elekf/library.{type Library}
|
||||||
|
|
|
@ -8,12 +8,14 @@ import elekf/web/components/icon.{Alt, icon}
|
||||||
import elekf/web/components/track_length.{track_length}
|
import elekf/web/components/track_length.{track_length}
|
||||||
import elekf/web/components/button_group
|
import elekf/web/components/button_group
|
||||||
import elekf/web/components/button
|
import elekf/web/components/button
|
||||||
|
import elekf/web/components/link
|
||||||
import elekf/web/components/thumbnail
|
import elekf/web/components/thumbnail
|
||||||
import elekf/web/components/player/actions.{
|
import elekf/web/components/player/actions.{
|
||||||
Commit, EndUserSkip, Ephemeral, NextTrack, Pause, Play, PrevTrack,
|
Commit, EndUserSkip, Ephemeral, NextTrack, Pause, Play, PrevTrack,
|
||||||
SelectPosition, StartUserSkip, ToggleFullScreen,
|
SelectPosition, StartUserSkip,
|
||||||
}
|
}
|
||||||
import elekf/web/components/player/model.{type Model}
|
import elekf/web/components/player/model.{type Model}
|
||||||
|
import elekf/web/router
|
||||||
|
|
||||||
pub fn view(model: Model) {
|
pub fn view(model: Model) {
|
||||||
let is_playing = model.state == model.Playing
|
let is_playing = model.state == model.Playing
|
||||||
|
@ -67,12 +69,12 @@ pub fn view(model: Model) {
|
||||||
[attribute.id("player-next"), event.on_click(NextTrack)],
|
[attribute.id("player-next"), event.on_click(NextTrack)],
|
||||||
[icon("skip-forward-fill", Alt("Next"))],
|
[icon("skip-forward-fill", Alt("Next"))],
|
||||||
),
|
),
|
||||||
button.view(
|
link.button(
|
||||||
|
router.to_hash(
|
||||||
|
router.current_with_query(router.fullscreen_player()),
|
||||||
|
),
|
||||||
"",
|
"",
|
||||||
[
|
[attribute.id("player-fullscreen-toggle")],
|
||||||
attribute.id("player-fullscreen-toggle"),
|
|
||||||
event.on_click(ToggleFullScreen),
|
|
||||||
],
|
|
||||||
[icon("arrows-angle-expand", Alt("Full screen player"))],
|
[icon("arrows-angle-expand", Alt("Full screen player"))],
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import gleam/int
|
import gleam/int
|
||||||
import gleam/string
|
import gleam/string
|
||||||
import gleam/result
|
import gleam/result
|
||||||
|
import gleam/set
|
||||||
|
import gleam/uri
|
||||||
|
import gleam/list
|
||||||
import plinth/browser/window
|
import plinth/browser/window
|
||||||
|
|
||||||
const artists = "artists"
|
const artists = "artists"
|
||||||
|
@ -9,10 +12,17 @@ const albums = "albums"
|
||||||
|
|
||||||
const settings = "settings"
|
const settings = "settings"
|
||||||
|
|
||||||
pub type Msg {
|
const fullscreen_query = "fullscreen"
|
||||||
RouteChanged(route: Route)
|
|
||||||
|
pub const default_route = TrackList
|
||||||
|
|
||||||
|
pub type Option {
|
||||||
|
FullScreen
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type Query =
|
||||||
|
set.Set(Option)
|
||||||
|
|
||||||
pub type Route {
|
pub type Route {
|
||||||
TrackList
|
TrackList
|
||||||
ArtistList
|
ArtistList
|
||||||
|
@ -22,6 +32,14 @@ pub type Route {
|
||||||
Settings
|
Settings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type RouteWithQuery {
|
||||||
|
RouteWithQuery(route: Route, query: Query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Msg {
|
||||||
|
RouteChanged(route: RouteWithQuery)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn init(dispatch: fn(Msg) -> Nil) {
|
pub fn init(dispatch: fn(Msg) -> Nil) {
|
||||||
window.add_event_listener("hashchange", fn(_e) {
|
window.add_event_listener("hashchange", fn(_e) {
|
||||||
let _ = run(dispatch)
|
let _ = run(dispatch)
|
||||||
|
@ -30,13 +48,14 @@ pub fn init(dispatch: fn(Msg) -> Nil) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(dispatch: fn(Msg) -> Nil) {
|
pub fn run(dispatch: fn(Msg) -> Nil) {
|
||||||
let hash = get_current_path()
|
let #(hash, query) = get_current_path()
|
||||||
|
let query = parse_query(query)
|
||||||
use route <- result.try(parse(hash))
|
use route <- result.try(parse(hash))
|
||||||
Ok(dispatch(RouteChanged(route)))
|
Ok(dispatch(RouteChanged(RouteWithQuery(route, query))))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_hash(route: Route) {
|
pub fn to_hash(route_with_query: RouteWithQuery) {
|
||||||
"#" <> to_string(route)
|
"#" <> to_string(route_with_query)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(route: String) {
|
pub fn parse(route: String) {
|
||||||
|
@ -62,12 +81,40 @@ pub fn parse(route: String) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_path() {
|
pub fn queryless(route: Route) {
|
||||||
result.unwrap(window.get_hash(), "/")
|
RouteWithQuery(route, set.new())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_string(route: Route) {
|
pub fn current_with_query(query: Query) {
|
||||||
let parts = case route {
|
let #(path, _) = get_current_path()
|
||||||
|
let route = result.unwrap(parse(path), default_route)
|
||||||
|
RouteWithQuery(route, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fullscreen_player() {
|
||||||
|
set.new()
|
||||||
|
|> set.insert(FullScreen)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_query(query: List(#(String, String))) {
|
||||||
|
list.fold(query, set.new(), fn(acc, item) {
|
||||||
|
let #(key, _val) = item
|
||||||
|
case key {
|
||||||
|
q if q == fullscreen_query -> set.insert(acc, FullScreen)
|
||||||
|
_ -> acc
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_current_path() {
|
||||||
|
let hash = result.unwrap(window.get_hash(), "/")
|
||||||
|
let #(path, query) = result.unwrap(string.split_once(hash, "?"), #(hash, ""))
|
||||||
|
let query = result.unwrap(uri.parse_query(query), [])
|
||||||
|
#(path, query)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_string(route_with_query: RouteWithQuery) {
|
||||||
|
let parts = case route_with_query.route {
|
||||||
TrackList -> []
|
TrackList -> []
|
||||||
ArtistList -> [artists]
|
ArtistList -> [artists]
|
||||||
AlbumList -> [albums]
|
AlbumList -> [albums]
|
||||||
|
@ -75,6 +122,18 @@ fn to_string(route: Route) {
|
||||||
Album(id) -> [albums, int.to_string(id)]
|
Album(id) -> [albums, int.to_string(id)]
|
||||||
Settings -> [settings]
|
Settings -> [settings]
|
||||||
}
|
}
|
||||||
|
let query_str = query_to_string(route_with_query.query)
|
||||||
|
|
||||||
"/" <> string.join(parts, "/")
|
"/" <> string.join(parts, "/") <> "?" <> query_str
|
||||||
|
}
|
||||||
|
|
||||||
|
fn query_to_string(query: Query) {
|
||||||
|
let query_parts =
|
||||||
|
set.fold(query, [], fn(acc, item) {
|
||||||
|
case item {
|
||||||
|
FullScreen -> [#(fullscreen_query, ""), ..acc]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
uri.query_to_string(query_parts)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import { preventPopstate } from "./browser_ffi.mjs";
|
|
||||||
|
|
||||||
const player_id = "player-elem";
|
const player_id = "player-elem";
|
||||||
const track_id = "player-track";
|
const track_id = "player-track";
|
||||||
|
|
||||||
|
@ -13,21 +11,6 @@ let player;
|
||||||
*/
|
*/
|
||||||
let track;
|
let track;
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
let popstatePreventEnabled = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {boolean}
|
|
||||||
*/
|
|
||||||
let popstateListenerAdded = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @type {(function(): undefined) | null}
|
|
||||||
*/
|
|
||||||
let popstateListenerCallback = null;
|
|
||||||
|
|
||||||
export function registerCallback(event, callback) {
|
export function registerCallback(event, callback) {
|
||||||
getPlayer();
|
getPlayer();
|
||||||
player.addEventListener(event, callback);
|
player.addEventListener(event, callback);
|
||||||
|
@ -85,31 +68,6 @@ export function linearRampToValue(node, gain, at) {
|
||||||
node.gain.linearRampToValueAtTime(gain, at);
|
node.gain.linearRampToValueAtTime(gain, at);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function enablePreventPopstate(callback) {
|
|
||||||
if (!popstateListenerAdded) {
|
|
||||||
window.addEventListener("popstate", popstateListener);
|
|
||||||
popstateListenerAdded = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
popstatePreventEnabled = true;
|
|
||||||
popstateListenerCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function disablePreventPopstate() {
|
|
||||||
popstatePreventEnabled = false;
|
|
||||||
popstateListenerCallback = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function popstateListener() {
|
|
||||||
if (popstatePreventEnabled) {
|
|
||||||
preventPopstate();
|
|
||||||
|
|
||||||
if (popstateListenerCallback) {
|
|
||||||
popstateListenerCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPlayer() {
|
function getPlayer() {
|
||||||
if (player === undefined) {
|
if (player === undefined) {
|
||||||
player = document.getElementById(player_id);
|
player = document.getElementById(player_id);
|
||||||
|
|
Loading…
Reference in a new issue