diff --git a/Web/Presenters/AuthPresenter.php b/Web/Presenters/AuthPresenter.php index 7edcda7c..6db7758c 100644 --- a/Web/Presenters/AuthPresenter.php +++ b/Web/Presenters/AuthPresenter.php @@ -228,6 +228,7 @@ final class AuthPresenter extends OpenVKPresenter return; } + $this->template->disable_ajax = 1; $this->template->is2faEnabled = $request->getUser()->is2faEnabled(); if($_SERVER["REQUEST_METHOD"] === "POST") { diff --git a/Web/Presenters/NoSpamPresenter.php b/Web/Presenters/NoSpamPresenter.php index 8164d05e..714cac93 100644 --- a/Web/Presenters/NoSpamPresenter.php +++ b/Web/Presenters/NoSpamPresenter.php @@ -38,6 +38,7 @@ final class NoSpamPresenter extends OpenVKPresenter if ($mode === "form") { $this->template->_template = "NoSpam/Index"; + $this->template->disable_ajax = 1; $foundClasses = []; foreach (Finder::findFiles('*.php')->from($targetDir) as $file) { $content = file_get_contents($file->getPathname()); @@ -67,6 +68,7 @@ final class NoSpamPresenter extends OpenVKPresenter $this->template->models = $models; } else if ($mode === "templates") { $this->template->_template = "NoSpam/Templates.xml"; + $this->template->disable_ajax = 1; $filter = []; if ($this->queryParam("id")) { $filter["id"] = (int)$this->queryParam("id"); diff --git a/Web/Presenters/OpenVKPresenter.php b/Web/Presenters/OpenVKPresenter.php index 359ab8b6..1d03a1c2 100644 --- a/Web/Presenters/OpenVKPresenter.php +++ b/Web/Presenters/OpenVKPresenter.php @@ -282,10 +282,9 @@ abstract class OpenVKPresenter extends SimplePresenter $this->redirect("/maintenances/"); } } - - if($this->queryParam('al') == '1') { + + if($_SERVER['HTTP_X_OPENVK_AJAX_QUERY'] == '1' && $this->user->identity) { error_reporting(0); - $this->assertNoCSRF(); header('Content-Type: text/plain; charset=UTF-8'); } diff --git a/Web/Presenters/ReportPresenter.php b/Web/Presenters/ReportPresenter.php index 0c4cbd83..a627efa4 100644 --- a/Web/Presenters/ReportPresenter.php +++ b/Web/Presenters/ReportPresenter.php @@ -43,6 +43,7 @@ final class ReportPresenter extends OpenVKPresenter "perPage" => 15, ]; $this->template->mode = $act ?? "all"; + $this->template->disable_ajax = 1; if ($_SERVER["REQUEST_METHOD"] === "POST") { $reports = []; @@ -78,6 +79,7 @@ final class ReportPresenter extends OpenVKPresenter $this->notFound(); $this->template->report = $report; + $this->template->disable_ajax = 1; } function renderCreate(int $id): void diff --git a/Web/Presenters/templates/@layout.xml b/Web/Presenters/templates/@layout.xml index 2035cc63..5406bf8a 100644 --- a/Web/Presenters/templates/@layout.xml +++ b/Web/Presenters/templates/@layout.xml @@ -198,18 +198,18 @@ {var $canAccessHelpdesk = $thisUser->getChandlerUser()->can("write")->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)} {var $menuLinksAvaiable = sizeof(OPENVK_ROOT_CONF['openvk']['preferences']['menu']['links']) > 0 && $thisUser->getLeftMenuItemStatus('links')} - {_admin} - {_helpdesk} + {_admin} + {_helpdesk} {if $helpdeskTicketNotAnsweredCount > 0} ({$helpdeskTicketNotAnsweredCount}) {/if} - {tr("reports")} + {tr("reports")} {if $reportNotAnsweredCount > 0} ({$reportNotAnsweredCount}) {/if} - + noSpam getId() : 0}, + "disable_ajax": {$disable_ajax ? $disable_ajax : 0}, } diff --git a/Web/Presenters/templates/Audio/EditPlaylist.xml b/Web/Presenters/templates/Audio/EditPlaylist.xml index c6580464..98b9f3f3 100644 --- a/Web/Presenters/templates/Audio/EditPlaylist.xml +++ b/Web/Presenters/templates/Audio/EditPlaylist.xml @@ -70,33 +70,4 @@ - - - - {script "js/al_playlists.js"} {/block} diff --git a/Web/Presenters/templates/Audio/NewPlaylist.xml b/Web/Presenters/templates/Audio/NewPlaylist.xml index f9c04deb..d3d1a281 100644 --- a/Web/Presenters/templates/Audio/NewPlaylist.xml +++ b/Web/Presenters/templates/Audio/NewPlaylist.xml @@ -51,24 +51,6 @@ -
- -
-
-
- {include "player.xml", audio => $audio, hideButtons => true} -
-
- {_add_to_playlist} -
-
-
- -
- {_show_more_audios} -
-
-
@@ -81,35 +63,4 @@
- - - - {script "js/al_playlists.js"} {/block} diff --git a/Web/Presenters/templates/Gifts/Pick.xml b/Web/Presenters/templates/Gifts/Pick.xml index 22345389..53538b78 100644 --- a/Web/Presenters/templates/Gifts/Pick.xml +++ b/Web/Presenters/templates/Gifts/Pick.xml @@ -13,7 +13,7 @@ {block content}
-
+ {_gift} @@ -29,7 +29,7 @@ {tr("gifts_left", $gift->getUsagesLeft($thisUser))} {/if}  -
+
@@ -41,18 +41,3 @@ ]}
{/block} - -{block bodyScripts} - -{/block} \ No newline at end of file diff --git a/Web/Presenters/templates/Group/Followers.xml b/Web/Presenters/templates/Group/Followers.xml index 7a1654d2..6ddece4f 100644 --- a/Web/Presenters/templates/Group/Followers.xml +++ b/Web/Presenters/templates/Group/Followers.xml @@ -82,23 +82,25 @@ {/block} diff --git a/Web/Presenters/templates/Group/View.xml b/Web/Presenters/templates/Group/View.xml index f1eb8fe8..327dd2f5 100644 --- a/Web/Presenters/templates/Group/View.xml +++ b/Web/Presenters/templates/Group/View.xml @@ -318,7 +318,3 @@ {/block} - -{block bodyScripts} - {script "js/al_despacito_wall.js"} -{/block} \ No newline at end of file diff --git a/Web/Presenters/templates/User/View.xml b/Web/Presenters/templates/User/View.xml index b3e34d56..44c7a6ce 100644 --- a/Web/Presenters/templates/User/View.xml +++ b/Web/Presenters/templates/User/View.xml @@ -745,7 +745,3 @@ {include "banned.xml"} {/if} {/block} - -{block bodyScripts} - {script "js/al_despacito_wall.js"} -{/block} diff --git a/Web/static/css/audios.css b/Web/static/css/audios.css index bd60d046..bbb29989 100644 --- a/Web/static/css/audios.css +++ b/Web/static/css/audios.css @@ -13,7 +13,7 @@ } .musicIcon { - background-image: url('/assets/packages/static/openvk/img/audios_controls.png?v=2'); + background-image: url('/assets/packages/static/openvk/img/audios_controls.png?v=6'); background-repeat: no-repeat; cursor: pointer; } @@ -150,7 +150,7 @@ } .bigPlayer .slider, .audioEmbed .track .slider { - width: 18px; + width: 15px; height: 7px; background: #606060; position: absolute; @@ -231,13 +231,13 @@ } .bigPlayer .trackPanel .track .selectableTrack > div { - width: 95%; + width: 96%; position: relative; } .bigPlayer .volumePanel .selectableTrack > div { position: relative; - width: 72% + width: 77%; } .audioEmbed .track > .selectableTrack, .bigPlayer .selectableTrack { @@ -881,3 +881,137 @@ margin-top: 6px; padding: 1px; } + +/* AJAX player */ +#ajax_audio_player { + transition: background .1s ease-out; + background: rgba(44, 44, 44, 0.7); + padding: 1px; + width: 500px; + height: 37px; + position: fixed; + z-index: 99; + border-radius: 3px; +} + +#ajax_audio_player.hidden { + display: none; +} + +#ajax_audio_player #aj_player { + position: relative; + height: 100%; +} + +#ajax_audio_player #aj_player #aj_player_internal_controls { + padding: 7px 8px; + display: flex; + gap: 7px; +} + +#ajax_audio_player.ui-draggable-dragging { + background: rgba(20, 20, 20, 0.9); +} + +#ajax_audio_player #aj_player_close_btn, #ajax_audio_player #aj_player_play { + padding: 3px 0px; +} + +#ajax_audio_player #aj_player_close_btn, +#ajax_audio_player #aj_player_play #aj_player_play_btn, +#ajax_audio_player #aj_player_buttons > div { + background: url('/assets/packages/static/openvk/img/audios_controls.png?v=6'); + background-repeat: no-repeat; + cursor: pointer; +} + +#ajax_audio_player #aj_player_close_btn { + position: absolute; + top: 0; + right: 0; + width: 10px; + height: 9px; + background-position: 0px -77px; + opacity: 0.6; +} + +#ajax_audio_player #aj_player_close_btn:hover { + opacity: 1; +} + +#ajax_audio_player #aj_player_play #aj_player_play_btn { + width: 16px; + height: 16px; + background-position: -147px -28px; +} + +#ajax_audio_player #aj_player_play #aj_player_play_btn.paused { + background-position: -165px -28px; +} + +#ajax_audio_player #aj_player_track { + width: 100%; + position: relative; +} + +#ajax_audio_player #aj_player_track #aj_player_track_name { + display: flex; + justify-content: space-between; +} + +#ajax_audio_player #aj_player_track #aj_player_track_name #aj_player_track_title, +#ajax_audio_player #aj_player_track #aj_player_track_name #aj_player_track_title b, +#ajax_audio_player #aj_player_track #aj_player_track_name #aj_player_track_title span, +#ajax_audio_player #aj_player_track #aj_player_track_name span { + color: white; +} + +#ajax_audio_player .selectableTrack { + width: 100%; + position: relative; + height: 6px; + border-top: #ffffff 1px solid; + user-select: none; +} + +#ajax_audio_player .selectableTrack .slider { + width: 11px; + height: 6px; + background: #ffffff; + position: absolute; +} + +#ajax_audio_player #aj_player_volume { + width: 60px; + padding-top: 15px; + position: relative; +} + +#ajax_audio_player #aj_player_buttons { + display: flex; + flex-direction: row; + align-items: center; + gap: 10px; +} + +#ajax_audio_player #aj_player_buttons #aj_player_previous { + width: 14px; + height: 12px; + background-position: -194px -5px; +} + +#ajax_audio_player #aj_player_buttons #aj_player_repeat { + width: 14px; + height: 13px; + background-position: -233px -5px; +} + +#ajax_audio_player #aj_player_buttons #aj_player_repeat.pressed { + opacity: 0.6; +} + +#ajax_audio_player #aj_player_buttons #aj_player_next { + width: 15px; + height: 12px; + background-position: -214px -5px; +} diff --git a/Web/static/img/audios_controls.png b/Web/static/img/audios_controls.png index 47f39673..2b02c7c0 100644 Binary files a/Web/static/img/audios_controls.png and b/Web/static/img/audios_controls.png differ diff --git a/Web/static/js/al_despacito_wall.js b/Web/static/js/al_despacito_wall.js index 0e198e55..be87b53b 100644 --- a/Web/static/js/al_despacito_wall.js +++ b/Web/static/js/al_despacito_wall.js @@ -1,4 +1,3 @@ -const contentPage = document.querySelector(".page_content"); const rootElement = document.documentElement; // охуенное название файла, КТО ЭТО ПРИДУМАЛ КРАСАВА Я ИЗ КОМНАТЫ С ЭТОГО УЛЕТЕЛ НАХУЙ @@ -8,11 +7,11 @@ let scrolledAndHidden = false; let smallBlockObserver = new IntersectionObserver(entries => { entries.forEach(x => { window.requestAnimationFrame(() => { - let pastHeight = contentPage.getBoundingClientRect().height; + let pastHeight = u('.page_content').nodes[0].getBoundingClientRect().height; if(x.isIntersecting) - contentPage.classList.remove("overscrolled"); + u('.page_content').nodes[0].classList.remove("overscrolled"); else - contentPage.classList.add("overscrolled"); + u('.page_content').nodes[0].classList.add("overscrolled"); // let currentHeight = contentPage.getBoundingClientRect().height; // let ratio = currentHeight / pastHeight; @@ -22,7 +21,7 @@ let smallBlockObserver = new IntersectionObserver(entries => { // То что я задокументировал - работает мегакриво. // Пусть юзер и проскролливает какую-то часть контента, зато не получит // эпилепсии при использовании :) - }, contentPage); + }, u('.page_content').nodes[0]); }); }, { root: null, // screen diff --git a/Web/static/js/al_music.js b/Web/static/js/al_music.js index 1472549a..e8918a3b 100644 --- a/Web/static/js/al_music.js +++ b/Web/static/js/al_music.js @@ -1,5 +1,3 @@ -window.savedAudiosPages = {} - class playersSearcher { constructor(context_type, context_id) { this.context_type = context_type @@ -68,6 +66,18 @@ window.player = new class { return this.__realAudioPlayer } + get linkedInlinePlayer() { + if(!this.__linked_player_id) { + return null; + } + + return u('#' + this.__linked_player_id) + } + + get ajaxPlayer() { + return u('#ajax_audio_player') + } + get uiPlayer() { return u('.bigPlayer') } @@ -86,17 +96,9 @@ window.player = new class { return this.__findByIndex(current + 1) } - get linkedInlinePlayer() { - if(!this.__linked_player_id) { - return null; - } - - return u('#' + this.__linked_player_id) - } - async init(input_context) { let context = Object.assign({ - url: location.pathname + url: location.pathname + location.search }, input_context) this.context.object = !input_context ? null : context this.__realAudioPlayer = document.createElement("audio") @@ -109,8 +111,13 @@ window.player = new class { initEvents() { this.audioPlayer.ontimeupdate = () => { - const time = this.audioPlayer.currentTime; - const ps = ((time * 100) / this.currentTrack.length).toFixed(3) + const current_track = this.currentTrack + if(!current_track) { + return + } + + const time = this.audioPlayer.currentTime + const ps = ((time * 100) / current_track.length).toFixed(3) this.uiPlayer.find(".time").html(fmtTime(time)) this.__updateTime(time) @@ -121,6 +128,11 @@ window.player = new class { this.linkedInlinePlayer.find(".subTracks .lengthTrackWrapper .slider").attr('style', `left:${ ps}%`) this.linkedInlinePlayer.find('.mini_timer .nobold').html(fmtTime(time)) } + + if(this.ajaxPlayer) { + this.ajaxPlayer.find('#aj_player_track_length .slider').attr('style', `left:${ ps}%`) + this.ajaxPlayer.find('#aj_player_track_name #aj_time').html(fmtTime(time)) + } } } @@ -134,6 +146,10 @@ window.player = new class { if(this.linkedInlinePlayer) { this.linkedInlinePlayer.find(".subTracks .volumeTrackWrapper .slider").attr('style', `left:${ ps}%`) } + + if(this.ajaxPlayer) { + this.ajaxPlayer.find('#aj_player_volume .slider').attr('style', `left:${ ps}%`) + } } localStorage.setItem('audio.volume', volume) @@ -162,12 +178,12 @@ window.player = new class { } } - this.audioPlayer.onended = (e) => { + this.audioPlayer.onended = async (e) => { e.preventDefault() if(!this.nextTrack && window.player.context.playedPages.indexOf(1) == -1) { this.loadContext(1, false) - this.setTrack(this.__findByIndex(0).id) + await this.setTrack(this.__findByIndex(0).id) } else { this.playNextTrack() } @@ -243,10 +259,28 @@ window.player = new class { return } + if(window.__current_page_audio_context && (!this.context.object || this.context.object.url != location.pathname + location.search)) { + console.log('Audio | Resetting context because of ajax :3') + + this.__renewContext() + await this.loadContext(window.__current_page_audio_context.page ?? 1) + if(!isNaN(parseInt(location.hash.replace('#', '')))) { + const adp = parseInt(location.hash.replace('#', '')) + await this.loadContext(adp) + } else if((new URL(location.href)).searchParams.p) { + const adp = (new URL(location.href)).searchParams.p + await this.loadContext(adp) + } + + this.__updateFace() + } + this.listen_coef = 0.0 + const old_id = this.current_track_id this.current_track_id = id const c_track = this.currentTrack if(!c_track) { + this.current_track_id = old_id makeError('Error playing audio: track not found') return } @@ -258,9 +292,7 @@ window.player = new class { }; u('.nowPlaying').removeClass('nowPlaying') - if(this.isAtAudiosPage()) { - u(`.audioEmbed[data-realid='${id}'] .audioEntry`).addClass('nowPlaying') - } + this.__highlightActiveTrack() navigator.mediaSession.setPositionState({ duration: this.currentTrack.length @@ -277,6 +309,7 @@ window.player = new class { await this.loadContext(Math.min(...this.context["playedPages"]) - 1, false) } + this.is_closed = false this.__updateFace() u(this.audioPlayer).trigger('volumechange') } @@ -324,12 +357,12 @@ window.player = new class { navigator.mediaSession.playbackState = "paused" } - playPreviousTrack() { + async playPreviousTrack() { if(!this.currentTrack || !this.previousTrack) { return } - this.setTrack(this.previousTrack.id) + await this.setTrack(this.previousTrack.id) if(!this.currentTrack.available || this.currentTrack.withdrawn) { if(!this.previousTrack) { return @@ -341,12 +374,12 @@ window.player = new class { this.play() } - playNextTrack() { + async playNextTrack() { if(!this.currentTrack || !this.nextTrack) { return } - this.setTrack(this.nextTrack.id) + await this.setTrack(this.nextTrack.id) if(!this.currentTrack.available || this.currentTrack.withdrawn) { if(!this.nextTrack) { return @@ -359,15 +392,78 @@ window.player = new class { } // fake shuffle - shuffle() { + async shuffle() { this.tracks.sort(() => Math.random() - 0.59) - this.setTrack(this.tracks.at(0).id) + await this.setTrack(this.tracks.at(0).id) } isAtAudiosPage() { return u('.bigPlayer').length > 0 } + // Добавляем ощущение продуманности. + __highlightActiveTrack() { + u(`.audiosContainer .audioEmbed[data-realid='${this.current_track_id}'] .audioEntry, .audios_padding .audioEmbed[data-realid='${this.current_track_id}'] .audioEntry`).addClass('nowPlaying') + } + + __renewContext() { + let context = Object.assign({ + url: location.pathname + location.search + }, window.__current_page_audio_context) + this.pause() + this.__resetContext() + this.context.object = context + } + + __resetContext() { + this.context = { + object: {}, + pagesCount: 0, + count: 0, + playedPages: [], + } + this.tracks = [] + //this.__realAudioPlayer = document.createElement("audio") + this.listen_coef = 0 + } + + async _handlePageTransition() { + console.log('Audio | Switched page :3') + const state = this.isAtAudiosPage() + if(!state) { + // AJAX audio player + if(this.is_closed) { + return + } + + this.ajaxPlayer.removeClass('hidden') + if(this.ajaxPlayer.length > 0) { + return + } else { + if(this.audioPlayer.paused) { + return + } + this.ajCreate() + this.__updateFace() + } + } else { + this.ajClose() + this.is_closed = false + if(this.tracks.length < 1) { + if(window.__current_page_audio_context) { + await this.init(window.__current_page_audio_context) + } + } + } + + this.__linked_player_id = null + if(this.currentTrack) { + this.__updateFace() + } + this.__highlightActiveTrack() + u(this.audioPlayer).trigger('volumechange') + } + __setFavicon(state = 'playing') { if(state == 'playing') { document.querySelector('link[rel="icon"], link[rel="shortcut icon"]').setAttribute("href", "/assets/packages/static/openvk/img/favicons/favicon24_paused.png") @@ -418,16 +514,28 @@ window.player = new class { if(!this.previousTrack) { prev_button.addClass('lagged') + if(this.ajaxPlayer.length > 0) { + this.ajaxPlayer.find('#aj_player_previous').addClass('lagged') + } } else { prev_button.removeClass('lagged') prev_button.attr('data-title', ovk_proc_strtr(escapeHtml(this.previousTrack.name), 50)) + if(this.ajaxPlayer.length > 0) { + this.ajaxPlayer.find('#aj_player_previous').removeClass('lagged') + } } if(!this.nextTrack) { next_button.addClass('lagged') + if(this.ajaxPlayer.length > 0) { + this.ajaxPlayer.find('#aj_player_next').addClass('lagged') + } } else { next_button.removeClass('lagged') next_button.attr('data-title', ovk_proc_strtr(escapeHtml(this.nextTrack.name), 50)) + if(this.ajaxPlayer.length > 0) { + this.ajaxPlayer.find('#aj_player_next').removeClass('lagged') + } } if(!this.audioPlayer.paused) { @@ -435,11 +543,17 @@ window.player = new class { if(this.linkedInlinePlayer) { this.linkedInlinePlayer.find('.playerButton .playIcon').addClass('paused') } + if(this.ajaxPlayer.length > 0) { + this.ajaxPlayer.find('#aj_player_play_btn').addClass('paused') + } } else { this.uiPlayer.find('.playButton').removeClass('pause') if(this.linkedInlinePlayer) { this.linkedInlinePlayer.find('.playerButton .playIcon').removeClass('paused') } + if(this.ajaxPlayer.length > 0) { + this.ajaxPlayer.find('#aj_player_play_btn').removeClass('paused') + } } this.uiPlayer.find('.trackInfo .trackName span').html(escapeHtml(_c.name)) @@ -450,6 +564,12 @@ window.player = new class { this.uiPlayer.find('.trackInfo .trackPerformers').append( `${performer.escapeHtml()}${(performer != lastPerformer ? ', ' : '')}`) }) + + if(this.ajaxPlayer.length > 0) { + this.ajaxPlayer.find('#aj_player_track_title b').html(escapeHtml(_c.performer)) + this.ajaxPlayer.find('#aj_player_track_title span').html(escapeHtml(_c.name)) + } + u(`.tip_result`).remove() } @@ -501,13 +621,95 @@ window.player = new class { console.log('Listen is not counted ! ! !') } } + + ajClose() { + this.is_closed = true + this.pause() + u('#ajax_audio_player').addClass('hidden') + } + + ajReveal() { + this.is_closed = false + u('#ajax_audio_player').removeClass('hidden') + } + + ajCreate() { + const previous_time_x = localStorage.getItem('audio.lastX') ?? 100 + const previous_time_y = localStorage.getItem('audio.lastY') ?? scrollY + const miniplayer_template = u(` +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `) + u('body').append(miniplayer_template) + miniplayer_template.attr('style', `left:${previous_time_x}px;top:${previous_time_y}px`) + miniplayer_template.find('#aj_player_close_btn').on('click', (e) => { + this.ajClose() + }) + miniplayer_template.find('#aj_player_track_title').on('click', (e) => { + if(window.player && window.player.context && window.player.context.object) { + window.router.route(window.player.context.object.url) + } + }) + $('#ajax_audio_player').draggable({ + cursor: 'grabbing', + containment: 'window', + cancel: '#aj_player_track .selectableTrack, #aj_player_volume .selectableTrack', + stop: function(e) { + if(window.player.ajaxPlayer.length > 0) { + const left = parseInt(window.player.ajaxPlayer.nodes[0].style.left) + const top = parseInt(window.player.ajaxPlayer.nodes[0].style.top) + + localStorage.setItem('audio.lastX', left) + localStorage.setItem('audio.lastY', top) + } + } + }) + } } document.addEventListener("DOMContentLoaded", async () => { await window.player.init(window.__current_page_audio_context) }) -u(document).on('click', '.audioEntry .playerButton > .playIcon', (e) => { +u(document).on('click', '.audioEntry .playerButton > .playIcon', async (e) => { const audioPlayer = u(e.target).closest('.audioEmbed') const id = Number(audioPlayer.attr('data-realid')) if(!window.player) { @@ -540,7 +742,7 @@ u(document).on('click', '.audioEntry .playerButton > .playIcon', (e) => { } if(window.player.current_track_id != id) { - window.player.setTrack(id) + await window.player.setTrack(id) } if(window.player.audioPlayer.paused) { @@ -563,7 +765,7 @@ u(document).on('click', '.audioEntry .playerButton > .playIcon', (e) => { } }) -u(document).on('click', '.bigPlayer .playButton', (e) => { +u(document).on('click', '.bigPlayer .playButton, #ajax_audio_player #aj_player_play_btn', (e) => { if(window.player.audioPlayer.paused) { window.player.play() } else { @@ -571,12 +773,12 @@ u(document).on('click', '.bigPlayer .playButton', (e) => { } }) -u(document).on('click', '.bigPlayer .backButton', (e) => { - window.player.playNextTrack() +u(document).on('click', '.bigPlayer .backButton, #ajax_audio_player #aj_player_next', async (e) => { + await window.player.playNextTrack() }) -u(document).on('click', '.bigPlayer .nextButton', (e) => { - window.player.playPreviousTrack() +u(document).on('click', '.bigPlayer .nextButton, #ajax_audio_player #aj_player_previous', async (e) => { + await window.player.playPreviousTrack() }) u(document).on("click", ".bigPlayer .elapsedTime", (e) => { @@ -588,7 +790,7 @@ u(document).on("click", ".bigPlayer .elapsedTime", (e) => { window.player.__updateTime(window.player.audioPlayer.currentTime) }) -u(document).on("click", ".bigPlayer .additionalButtons .repeatButton", (e) => { +u(document).on("click", ".bigPlayer .additionalButtons .repeatButton, #ajax_audio_player #aj_player_repeat", (e) => { if(window.player.current_track_id == 0) return @@ -601,11 +803,11 @@ u(document).on("click", ".bigPlayer .additionalButtons .repeatButton", (e) => { window.player.audioPlayer.loop = false }) -u(document).on("click", ".bigPlayer .additionalButtons .shuffleButton", (e) => { +u(document).on("click", ".bigPlayer .additionalButtons .shuffleButton", async (e) => { if(window.player.current_track_id == 0) return - window.player.shuffle() + await window.player.shuffle() }) u(document).on("click", ".bigPlayer .additionalButtons .deviceButton", (e) => { @@ -693,7 +895,7 @@ u(document).on('keyup', (e) => { } }) -u(document).on("mousemove click mouseup", ".bigPlayer .trackPanel .selectableTrack, .audioEntry .subTracks .lengthTrackWrapper .selectableTrack", (e) => { +u(document).on("mousemove click mouseup", ".bigPlayer .trackPanel .selectableTrack, .audioEntry .subTracks .lengthTrackWrapper .selectableTrack, #aj_player_track_length .selectableTrack", (e) => { if(window.player.isAtAudiosPage() && window.player.current_track_id == 0) return @@ -724,17 +926,17 @@ u(document).on("mousemove click mouseup", ".bigPlayer .trackPanel .selectableTra parent.find('.tip_result').html(fmtTime(time)).attr('style', `left:min(${width - 15}px, 315.5px)`) }) -u(document).on("mouseout", ".bigPlayer .trackPanel .selectableTrack, .audioEntry .subTracks .lengthTrackWrapper .selectableTrack", (e) => { +u(document).on("mouseout", ".bigPlayer .trackPanel .selectableTrack, .audioEntry .subTracks .lengthTrackWrapper .selectableTrack, #aj_player_track_length .selectableTrack", (e) => { if(window.player.isAtAudiosPage() && window.player.current_track_id == 0) return u(e.target).closest('.selectableTrack').parent().find('.tip_result').remove() }) -u(document).on("mousemove click mouseup", ".bigPlayer .volumePanelTrack .selectableTrack, .audioEntry .subTracks .volumeTrack .selectableTrack", (e) => { +u(document).on("mousemove click mouseup", ".bigPlayer .volumePanelTrack .selectableTrack, .audioEntry .subTracks .volumeTrack .selectableTrack, #aj_player_volume .selectableTrack", (e) => { if(window.player.isAtAudiosPage() && window.player.current_track_id == 0) return - + function __defaultAction(i_volume) { window.player.audioPlayer.volume = i_volume } @@ -761,7 +963,7 @@ u(document).on("mousemove click mouseup", ".bigPlayer .volumePanelTrack .selecta parent.find('.tip_result').html((volume * 100).toFixed(0) + '%').attr('style', `left:${width - 15}px`) }) -u(document).on("mouseout", ".bigPlayer .volumePanelTrack .selectableTrack, .audioEntry .subTracks .volumeTrack .selectableTrack", (e) => { +u(document).on("mouseout", ".bigPlayer .volumePanelTrack .selectableTrack, .audioEntry .subTracks .volumeTrack .selectableTrack, #aj_player_volume .selectableTrack", (e) => { if(window.player.isAtAudiosPage() && window.player.current_track_id == 0) return @@ -924,8 +1126,6 @@ u(document).on("click", ".musicIcon.edit-icon", (e) => { if(url.searchParams.p != null) page = String(url.searchParams.p) - - window.savedAudiosPages[page] = null } else fastError(response.flash.message) } @@ -1483,49 +1683,6 @@ $(document).on("click", ".musicIcon.report-icon", (e) => { Function.noop]) }) -u(document).on("click", ".audiosContainer .paginator a", (e) => { - e.preventDefault() - e.stopPropagation() - - let url = new URL(e.currentTarget.href) - let page = url.searchParams.get("p") - - function searchNode(id) { - let node = document.querySelector(`.audioEmbed[data-realid='${id}'] .audioEntry`) - - if(node != null) { - node.classList.add("nowPlaying") - } - } - - if(window.savedAudiosPages[page] != null) { - history.pushState({}, "", e.currentTarget.href) - document.querySelector(".audiosContainer").innerHTML = window.savedAudiosPages[page].innerHTML - searchNode(window.player.currentTrack != null ? window.player.currentTrack.id : 0) - - return - } - - e.currentTarget.parentNode.classList.add("lagged") - $.ajax({ - type: "GET", - url: e.currentTarget.href, - success: (response) => { - let domparser = new DOMParser() - let result = domparser.parseFromString(response, "text/html") - - document.querySelector(".audiosContainer").innerHTML = result.querySelector(".audiosContainer").innerHTML - history.pushState({}, "", e.currentTarget.href) - window.savedAudiosPages[page] = result.querySelector(".audiosContainer") - searchNode(window.player.currentTrack != null ? window.player.currentTrack.id : 0) - - if(!window.player.context["playedPages"].includes(page)) { - window.player.loadContext(page) - } - } - }) -}) - $(document).on("click", ".addToPlaylist", (e) => { let audios = document.querySelector("input[name='audios']") let id = e.currentTarget.dataset.id diff --git a/Web/static/js/al_wall.js b/Web/static/js/al_wall.js index 74c54002..c0c1ebf5 100644 --- a/Web/static/js/al_wall.js +++ b/Web/static/js/al_wall.js @@ -473,6 +473,7 @@ u(document).on('keydown', '.edit_menu #write', (e) => { e.target.closest('.edit_menu').querySelector('#__edit_save').click() }) +// Migrated from inline start function reportPhoto(photo_id) { uReportMsgTxt = tr("going_to_report_photo"); uReportMsgTxt += "
"+tr("report_question_text"); @@ -539,6 +540,132 @@ function reportUser(user_id) { ]); } +$(document).on("click", "#_photoDelete, #_videoDelete", function(e) { + var formHtml = "
"; + formHtml += ""; + formHtml += "
"; + u("body").append(formHtml); + + MessageBox(tr('warning'), tr('question_confirm'), [ + tr('yes'), + tr('no') + ], [ + (function() { + u("#tmpPhDelF").nodes[0].submit(); + }), + (function() { + u("#tmpPhDelF").remove(); + }), + ]); + + e.stopPropagation() + return e.preventDefault(); +}); +/* @rem-pai why this func wasn't named as "#_deleteDialog"? It looks universal IMO */ + +u(document).on("click", "#_noteDelete", function(e) { + var formHtml = "
"; + formHtml += ""; + formHtml += "
"; + u("body").append(formHtml); + + MessageBox(tr('warning'), tr('question_confirm'), [ + tr('yes'), + tr('no') + ], [ + (function() { + u("#tmpPhDelF").nodes[0].submit(); + }), + (function() { + u("#tmpPhDelF").remove(); + }), + ]); + + e.stopPropagation() + return e.preventDefault(); +}); + +// TODO REWRITE cuz its a little broken +u(document).on("click", "#_pinGroup", async function(e) { + e.preventDefault(); + e.stopPropagation() + + let link = u(this).attr("href"); + let thisButton = u(this); + let groupName = u(this).attr("data-group-name"); + let groupUrl = u(this).attr("data-group-url"); + let list = u('#_groupListPinnedGroups'); + + thisButton.nodes[0].classList.add('loading'); + thisButton.nodes[0].classList.add('disable'); + + let req = await ky(link); + if(req.ok == false) { + NewNotification(tr('error'), tr('error_1'), null); + thisButton.nodes[0].classList.remove('loading'); + thisButton.nodes[0].classList.remove('disable'); + return; + } + + if(!parseAjaxResponse(await req.text())) { + thisButton.nodes[0].classList.remove('loading'); + thisButton.nodes[0].classList.remove('disable'); + return; + } + + // Adding a divider if not already there + if(list.nodes[0].children.length == 0) { + list.nodes[0].append(u('').first()); + } + + // Changing the button name + if(thisButton.html().trim() == tr('remove_from_left_menu')) { + thisButton.html(tr('add_to_left_menu')); + for(let i = 0; i < list.nodes[0].children.length; i++) { + let element = list.nodes[0].children[i]; + if(element.pathname == groupUrl) { + element.remove(); + } + } + }else{ + thisButton.html(tr('remove_from_left_menu')); + list.nodes[0].append(u('' + groupName + '').first()); + } + + // Adding the group to the left group list + if(list.nodes[0].children[0].className != "menu_divider" || list.nodes[0].children.length == 1) { + list.nodes[0].children[0].remove(); + } + + thisButton.nodes[0].classList.remove('loading'); + thisButton.nodes[0].classList.remove('disable'); + + return false; +}); + +u(document).handle("submit", "#_submitUserSubscriptionAction", async function(e) { + e.preventDefault() + e.stopPropagation() + + u(this).nodes[0].parentElement.classList.add('loading'); + u(this).nodes[0].parentElement.classList.add('disable'); + console.log(e.target); + const data = await fetch(u(this).attr('action'), { method: 'POST', body: new FormData(e.target) }); + if (data.ok) { + u(this).nodes[0].parentElement.classList.remove('loading'); + u(this).nodes[0].parentElement.classList.remove('disable'); + if (e.target[0].value == "add") { + u(this).nodes[0].parentElement.innerHTML = tr("friends_add_msg"); + } else if (e.target[0].value == "rej") { + u(this).nodes[0].parentElement.innerHTML = tr("friends_rej_msg"); + } else if (e.target[0].value == "rem") { + u(this).nodes[0].parentElement.innerHTML = tr("friends_rem_msg"); + } + } +}) + +// Migrated from inline end + var tooltipClientTemplate = Handlebars.compile(` @@ -2108,7 +2235,7 @@ async function __processPaginatorNextPage(page) } const new_url = new URL(location.href) - new_url.hash = 'pages/'+page + new_url.hash = page history.replaceState(null, null, new_url) if(typeof __scrollHook != 'undefined') { diff --git a/Web/static/js/openvk.cls.js b/Web/static/js/openvk.cls.js index 9ca50a42..89ed63d7 100644 --- a/Web/static/js/openvk.cls.js +++ b/Web/static/js/openvk.cls.js @@ -39,133 +39,6 @@ function parseAjaxResponse(responseString) { } } -document.addEventListener("DOMContentLoaded", function() { //BEGIN - - $(document).on("click", "#_photoDelete, #_videoDelete", function(e) { - var formHtml = ""; - formHtml += ""; - formHtml += ""; - u("body").append(formHtml); - - MessageBox(tr('warning'), tr('question_confirm'), [ - tr('yes'), - tr('no') - ], [ - (function() { - u("#tmpPhDelF").nodes[0].submit(); - }), - (function() { - u("#tmpPhDelF").remove(); - }), - ]); - - e.stopPropagation() - return e.preventDefault(); - }); - /* @rem-pai why this func wasn't named as "#_deleteDialog"? It looks universal IMO */ - - u(document).on("click", "#_noteDelete", function(e) { - var formHtml = ""; - formHtml += ""; - formHtml += ""; - u("body").append(formHtml); - - MessageBox(tr('warning'), tr('question_confirm'), [ - tr('yes'), - tr('no') - ], [ - (function() { - u("#tmpPhDelF").nodes[0].submit(); - }), - (function() { - u("#tmpPhDelF").remove(); - }), - ]); - - e.stopPropagation() - return e.preventDefault(); - }); - - // TODO REWRITE cuz its a little broken - u(document).on("click", "#_pinGroup", async function(e) { - e.preventDefault(); - e.stopPropagation() - - let link = u(this).attr("href"); - let thisButton = u(this); - let groupName = u(this).attr("data-group-name"); - let groupUrl = u(this).attr("data-group-url"); - let list = u('#_groupListPinnedGroups'); - - thisButton.nodes[0].classList.add('loading'); - thisButton.nodes[0].classList.add('disable'); - - let req = await ky(link); - if(req.ok == false) { - NewNotification(tr('error'), tr('error_1'), null); - thisButton.nodes[0].classList.remove('loading'); - thisButton.nodes[0].classList.remove('disable'); - return; - } - - if(!parseAjaxResponse(await req.text())) { - thisButton.nodes[0].classList.remove('loading'); - thisButton.nodes[0].classList.remove('disable'); - return; - } - - // Adding a divider if not already there - if(list.nodes[0].children.length == 0) { - list.nodes[0].append(u('').first()); - } - - // Changing the button name - if(thisButton.html().trim() == tr('remove_from_left_menu')) { - thisButton.html(tr('add_to_left_menu')); - for(let i = 0; i < list.nodes[0].children.length; i++) { - let element = list.nodes[0].children[i]; - if(element.pathname == groupUrl) { - element.remove(); - } - } - }else{ - thisButton.html(tr('remove_from_left_menu')); - list.nodes[0].append(u('' + groupName + '').first()); - } - - // Adding the group to the left group list - if(list.nodes[0].children[0].className != "menu_divider" || list.nodes[0].children.length == 1) { - list.nodes[0].children[0].remove(); - } - - thisButton.nodes[0].classList.remove('loading'); - thisButton.nodes[0].classList.remove('disable'); - - return false; - }); - - u(document).handle("submit", "#_submitUserSubscriptionAction", async function(e) { - e.preventDefault() - e.stopPropagation() - - u(this).nodes[0].parentElement.classList.add('loading'); - u(this).nodes[0].parentElement.classList.add('disable'); - console.log(e.target); - const data = await fetch(u(this).attr('action'), { method: 'POST', body: new FormData(e.target) }); - if (data.ok) { - u(this).nodes[0].parentElement.classList.remove('loading'); - u(this).nodes[0].parentElement.classList.remove('disable'); - if (e.target[0].value == "add") { - u(this).nodes[0].parentElement.innerHTML = tr("friends_add_msg"); - } else if (e.target[0].value == "rej") { - u(this).nodes[0].parentElement.innerHTML = tr("friends_rej_msg"); - } else if (e.target[0].value == "rem") { - u(this).nodes[0].parentElement.innerHTML = tr("friends_rem_msg"); - } - } - }) -}); //END ONREADY DECLS - function setClubAdminComment(clubId, adminId, hash) { MessageBox("Изменить комментарий к администратору", ` diff --git a/Web/static/js/router.js b/Web/static/js/router.js index fc67ab09..4f9e9039 100644 --- a/Web/static/js/router.js +++ b/Web/static/js/router.js @@ -21,13 +21,21 @@ window.router = new class { _t_scr.setAttribute('integrity', script.getAttribute('integrity')) } - _t_scr.id = script.id + if(script.getAttribute('id')) { + _t_scr.id = script.id + } + + if(script.getAttribute('type')) { + _t_scr.type = script.type + } + //const parent = script.parentNode //const idx = Array.from(parent.children).indexOf(script) if(script.src) { _t_scr.src = script.src } else { + _t_scr.async = false _t_scr.textContent = script.textContent } @@ -44,19 +52,20 @@ window.router = new class { } __appendPage(parsed_content) { + const scripts_to_append = [] const page_body = u(parsed_content.querySelector('.page_body')) const sidebar = u(parsed_content.querySelector('.sidebar')) const page_header = u(parsed_content.querySelector('.page_header')) - if(page_body.length < 1) { - makeError('Invalid page has been loaded') + throw new Error('Invalid page has been loaded') return } + window.__current_page_audio_context = null this.__clearScripts() parsed_content.querySelectorAll('.page_body script, #_js_ep_script').forEach(script => { if(!this.__isScriptAlreadyLoaded(script)) { - this.__appendScript(script) + scripts_to_append.push(script) script.parentNode.removeChild(script) } }) @@ -77,6 +86,12 @@ window.router = new class { u("meta[name=csrf]").attr("value", u(parsed_content.querySelector('meta[name=csrf]')).attr('value')) document.title = parsed_content.title + scripts_to_append.forEach(append_me => { + this.__appendScript(append_me) + }) + } + + async __integratePage() { window.scrollTo(0, 0) bsdnHydrate() @@ -84,9 +99,13 @@ window.router = new class { showMoreObserver.observe(u('.paginator:not(.paginator-at-top)').nodes[0]) } - if(u(`div[class$="_small_block"]`).length > 0 && window.smallBlockObserver) { + if(u(`div[class$="_small_block"]`).length > 0 && typeof smallBlockObserver != 'undefined') { smallBlockObserver.observe(u(`div[class$="_small_block"]`).nodes[0]) } + + if(window.player) { + await window.player._handlePageTransition() + } } __unlinkObservers() { @@ -94,12 +113,16 @@ window.router = new class { showMoreObserver.unobserve(u('.paginator:not(.paginator-at-top)').nodes[0]) } - if(u(`div[class$="_small_block"]`).length > 0 && window.smallBlockObserver) { + if(u(`div[class$="_small_block"]`).length > 0 && typeof smallBlockObserver != 'undefined') { smallBlockObserver.unobserve(u(`div[class$="_small_block"]`).nodes[0]) } } checkUrl(url) { + if(window.openvk.disable_ajax == 1) { + return false + } + if((localStorage.getItem('ux.disable_ajax_routing') ?? 0) == 1 || window.openvk.current_id == 0) { return false } @@ -139,8 +162,6 @@ window.router = new class { const push_url = params.push_state ?? true const next_page_url = new URL(url) - next_page_url.searchParams.append('al', 1) - next_page_url.searchParams.append('hash', this.csrf) if(push_url) { history.pushState({'from_router': 1}, '', url) } else { @@ -149,7 +170,10 @@ window.router = new class { const parser = new DOMParser const next_page_request = await fetch(next_page_url, { - method: 'GET' + method: 'GET', + headers: { + 'X-OpenVK-Ajax-Query': '1', + } }) const next_page_text = await next_page_request.text() const parsed_content = parser.parseFromString(next_page_text, 'text/html') @@ -159,7 +183,15 @@ window.router = new class { this.__closeMsgs() this.__unlinkObservers() - this.__appendPage(parsed_content) + + try { + this.__appendPage(parsed_content) + await this.__integratePage() + } catch(e) { + console.error(e) + next_page_url.searchParams.delete('al', 1) + location.assign(next_page_url) + } } } @@ -170,24 +202,29 @@ u(document).on('click', 'a', async (e) => { let url = target.nodes[0].href if(id) { - if(['act_tab_a', 'ki', '_pinGroup'].indexOf(id) == -1) { + if(['act_tab_a', 'ki', 'used', '_pinGroup', 'profile_link'].indexOf(id) == -1) { console.log('AJAX | Skipping cuz maybe its function call link.') return } } - if(url.indexOf('hash=') != -1) { + /*if(url.indexOf('hash=') != -1) { e.preventDefault() return false + }*/ + + if(target.rel == 'nofollow') { + console.log('AJAX | Skipped because its nofollow') + return } if(!dom_url || dom_url == '#' || dom_url.indexOf('javascript:') != -1) { - console.log('AJAX | Skipped cuz its anchor or function call') + console.log('AJAX | Skipped because its anchor or function call') return } if(target.attr('target') == '_blank') { - console.log('AJAX | Skipping cuz its _blank.') + console.log('AJAX | Skipping because its _blank.') return } @@ -225,7 +262,6 @@ u(document).on('submit', 'form', async (e) => { } const url_object = new URL(url) - url_object.searchParams.append('al', 1) if(method == 'get' || method == 'GET') { url_object.searchParams.append('hash', window.router.csrf) $(form).serializeArray().forEach(param => { @@ -240,7 +276,10 @@ u(document).on('submit', 'form', async (e) => { const form_data = serializeForm(form) const request_object = { - method: method + method: method, + headers: { + 'X-OpenVK-Ajax-Query': '1', + } } if(method != 'GET' && method != 'get') { @@ -271,6 +310,7 @@ u(document).on('submit', 'form', async (e) => { console.log(form_res) window.router.__appendPage(parsed_content) + await window.router.__integratePage() u('#ajloader').removeClass('shown') })