mirror of
https://github.com/iv-org/invidious.git
synced 2025-12-19 06:29:10 +00:00
Updated styling, formatting, structure of frontend
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
var video_data = JSON.parse(document.getElementById('video_data').textContent);
|
||||
|
||||
var spinnerHTML = '<h3 style="text-align:center"><div class="loading"><i class="icon ion-ios-refresh"></i></div></h3>';
|
||||
var spinnerHTML = '<div class="loading"><i class="icon ion-ios-refresh"></i></div>';
|
||||
var spinnerHTMLwithHR = spinnerHTML + '<hr>';
|
||||
|
||||
String.prototype.supplant = function (o) {
|
||||
@@ -11,14 +11,14 @@ String.prototype.supplant = function (o) {
|
||||
};
|
||||
|
||||
function toggle_comments(event) {
|
||||
var target = event.target;
|
||||
var body = target.parentNode.parentNode.parentNode.children[1];
|
||||
if (body.style.display === 'none') {
|
||||
target.textContent = '[ − ]';
|
||||
body.style.display = '';
|
||||
const target = event.target;
|
||||
const comments = document.querySelector(".comments");
|
||||
if (comments.style.display === 'none') {
|
||||
target.textContent = '−';
|
||||
comments.style.display = '';
|
||||
} else {
|
||||
target.textContent = '[ + ]';
|
||||
body.style.display = 'none';
|
||||
target.textContent = '+';
|
||||
comments.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ function hide_youtube_replies(event) {
|
||||
|
||||
function show_youtube_replies(event) {
|
||||
var target = event.target;
|
||||
console.log(target);
|
||||
|
||||
var sub_text = target.getAttribute('data-inner-text');
|
||||
var inner_text = target.getAttribute('data-sub-text');
|
||||
@@ -75,23 +76,24 @@ function get_youtube_comments() {
|
||||
helpers.xhr('GET', url, {retries: 5, entity_name: 'comments'}, {
|
||||
on200: function (response) {
|
||||
var commentInnerHtml = ' \
|
||||
<div> \
|
||||
<h3> \
|
||||
<a href="javascript:void(0)">[ − ]</a> \
|
||||
<nav class="comments-header"> \
|
||||
<ul> \
|
||||
<li> \
|
||||
<button class="secondary" id="toggle-comments">−</button> \
|
||||
{commentsText} \
|
||||
</h3> \
|
||||
<b> \
|
||||
'
|
||||
</li> \
|
||||
\
|
||||
<li>'
|
||||
if (video_data.support_reddit) {
|
||||
commentInnerHtml += ' <a href="javascript:void(0)" data-comments="reddit"> \
|
||||
commentInnerHtml += ' <button data-comments="reddit"> \
|
||||
{redditComments} \
|
||||
</a> \
|
||||
</button> \
|
||||
'
|
||||
}
|
||||
commentInnerHtml += ' </b> \
|
||||
</div> \
|
||||
<div>{contentHtml}</div> \
|
||||
<hr>'
|
||||
commentInnerHtml += ' </li> \
|
||||
</ul> \
|
||||
</nav> \
|
||||
<div class="comments">{contentHtml}</div>'
|
||||
commentInnerHtml = commentInnerHtml.supplant({
|
||||
contentHtml: response.contentHtml,
|
||||
redditComments: video_data.reddit_comments_text,
|
||||
@@ -104,9 +106,9 @@ function get_youtube_comments() {
|
||||
})
|
||||
});
|
||||
comments.innerHTML = commentInnerHtml;
|
||||
comments.children[0].children[0].children[0].onclick = toggle_comments;
|
||||
document.getElementById("toggle-comments").onclick = toggle_comments;
|
||||
if (video_data.support_reddit) {
|
||||
comments.children[0].children[1].children[0].onclick = swap_comments;
|
||||
comments.children[1].children[1].onclick = swap_comments;
|
||||
}
|
||||
},
|
||||
onNon200: onNon200, // declared above
|
||||
@@ -122,7 +124,7 @@ function get_youtube_comments() {
|
||||
function get_youtube_replies(target, load_more, load_replies) {
|
||||
var continuation = target.getAttribute('data-continuation');
|
||||
|
||||
var body = target.parentNode.parentNode;
|
||||
var body = target.parentNode;
|
||||
var fallback = body.innerHTML;
|
||||
body.innerHTML = spinnerHTML;
|
||||
var baseUrl = video_data.base_url || '/api/v1/comments/'+ video_data.id
|
||||
@@ -140,26 +142,24 @@ function get_youtube_replies(target, load_more, load_replies) {
|
||||
helpers.xhr('GET', url, {}, {
|
||||
on200: function (response) {
|
||||
if (load_more) {
|
||||
body = body.parentNode.parentNode;
|
||||
body = body.parentNode;
|
||||
body.removeChild(body.lastElementChild);
|
||||
body.insertAdjacentHTML('beforeend', response.contentHtml);
|
||||
} else {
|
||||
body.removeChild(body.lastElementChild);
|
||||
|
||||
var p = document.createElement('p');
|
||||
var a = document.createElement('a');
|
||||
p.appendChild(a);
|
||||
var div = document.createElement('div');
|
||||
var button = document.createElement('button');
|
||||
div.appendChild(button);
|
||||
|
||||
a.href = 'javascript:void(0)';
|
||||
a.onclick = hide_youtube_replies;
|
||||
a.setAttribute('data-sub-text', video_data.hide_replies_text);
|
||||
a.setAttribute('data-inner-text', video_data.show_replies_text);
|
||||
a.textContent = video_data.hide_replies_text;
|
||||
button.onclick = hide_youtube_replies;
|
||||
button.setAttribute('data-sub-text', video_data.hide_replies_text);
|
||||
button.setAttribute('data-inner-text', video_data.show_replies_text);
|
||||
button.textContent = video_data.hide_replies_text;
|
||||
|
||||
var div = document.createElement('div');
|
||||
div.innerHTML = response.contentHtml;
|
||||
|
||||
body.appendChild(p);
|
||||
body.appendChild(div);
|
||||
}
|
||||
},
|
||||
@@ -171,4 +171,4 @@ function get_youtube_replies(target, load_more, load_replies) {
|
||||
body.innerHTML = fallback;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,13 +58,13 @@
|
||||
el.onclick = function () { mark_unwatched(el); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="add_playlist_video"]').forEach(function (el) {
|
||||
el.onclick = function () { add_playlist_video(el); };
|
||||
el.onclick = function (e) { add_playlist_video(e); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="add_playlist_item"]').forEach(function (el) {
|
||||
el.onclick = function () { add_playlist_item(el); };
|
||||
el.onclick = function (e) { add_playlist_item(e); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="remove_playlist_item"]').forEach(function (el) {
|
||||
el.onclick = function () { remove_playlist_item(el); };
|
||||
el.onclick = function (e) { remove_playlist_item(e); };
|
||||
});
|
||||
document.querySelectorAll('[data-onclick="revoke_token"]').forEach(function (el) {
|
||||
el.onclick = function () { revoke_token(el); };
|
||||
|
||||
@@ -1,131 +1,197 @@
|
||||
'use strict';
|
||||
var notification_data = JSON.parse(document.getElementById('notification_data').textContent);
|
||||
"use strict";
|
||||
var notification_data = JSON.parse(
|
||||
document.getElementById("notification_data").textContent,
|
||||
);
|
||||
|
||||
/** Boolean meaning 'some tab have stream' */
|
||||
const STORAGE_KEY_STREAM = 'stream';
|
||||
const STORAGE_KEY_STREAM = "stream";
|
||||
/** Number of notifications. May be increased or reset */
|
||||
const STORAGE_KEY_NOTIF_COUNT = 'notification_count';
|
||||
const STORAGE_KEY_NOTIF_COUNT = "notification_count";
|
||||
|
||||
var notifications, delivered;
|
||||
var notifications_mock = { close: function () { } };
|
||||
var notifications_mock = { close: function () {} };
|
||||
|
||||
function get_subscriptions() {
|
||||
helpers.xhr('GET', '/api/v1/auth/subscriptions', {
|
||||
async function get_subscriptions_call() {
|
||||
return new Promise((resolve) => {
|
||||
helpers.xhr(
|
||||
"GET",
|
||||
"/api/v1/auth/subscriptions",
|
||||
{
|
||||
retries: 5,
|
||||
entity_name: 'subscriptions'
|
||||
}, {
|
||||
on200: create_notification_stream
|
||||
});
|
||||
entity_name: "subscriptions",
|
||||
},
|
||||
{
|
||||
on200: function (subscriptions) {
|
||||
create_notification_stream(subscriptions);
|
||||
resolve(subscriptions);
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Start the retry mechanism
|
||||
const get_subscriptions = exponential_backoff(get_subscriptions_call, 100, 1000);
|
||||
|
||||
function create_notification_stream(subscriptions) {
|
||||
// sse.js can't be replaced to EventSource in place as it lack support of payload and headers
|
||||
// see https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource
|
||||
notifications = new SSE(
|
||||
'/api/v1/auth/notifications', {
|
||||
withCredentials: true,
|
||||
payload: 'topics=' + subscriptions.map(function (subscription) { return subscription.authorId; }).join(','),
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
||||
});
|
||||
delivered = [];
|
||||
// sse.js can't be replaced to EventSource in place as it lack support of payload and headers
|
||||
// see https://developer.mozilla.org/en-US/docs/Web/API/EventSource/EventSource
|
||||
notifications = new SSE("/api/v1/auth/notifications", {
|
||||
withCredentials: true,
|
||||
payload:
|
||||
"topics=" +
|
||||
subscriptions
|
||||
.map(function (subscription) {
|
||||
return subscription.authorId;
|
||||
})
|
||||
.join(","),
|
||||
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
||||
});
|
||||
delivered = [];
|
||||
|
||||
var start_time = Math.round(new Date() / 1000);
|
||||
var start_time = Math.round(new Date() / 1000);
|
||||
|
||||
notifications.onmessage = function (event) {
|
||||
if (!event.id) return;
|
||||
notifications.onmessage = function (event) {
|
||||
if (!event.id) return;
|
||||
|
||||
var notification = JSON.parse(event.data);
|
||||
console.info('Got notification:', notification);
|
||||
var notification = JSON.parse(event.data);
|
||||
console.info("Got notification:", notification);
|
||||
|
||||
// Ignore not actual and delivered notifications
|
||||
if (start_time > notification.published || delivered.includes(notification.videoId)) return;
|
||||
// Ignore not actual and delivered notifications
|
||||
if (
|
||||
start_time > notification.published ||
|
||||
delivered.includes(notification.videoId)
|
||||
)
|
||||
return;
|
||||
|
||||
delivered.push(notification.videoId);
|
||||
delivered.push(notification.videoId);
|
||||
|
||||
let notification_count = helpers.storage.get(STORAGE_KEY_NOTIF_COUNT) || 0;
|
||||
notification_count++;
|
||||
helpers.storage.set(STORAGE_KEY_NOTIF_COUNT, notification_count);
|
||||
let notification_count = helpers.storage.get(STORAGE_KEY_NOTIF_COUNT) || 0;
|
||||
notification_count++;
|
||||
helpers.storage.set(STORAGE_KEY_NOTIF_COUNT, notification_count);
|
||||
|
||||
update_ticker_count();
|
||||
update_ticker_count();
|
||||
|
||||
// permission for notifications handled on settings page. JS handler is in handlers.js
|
||||
if (window.Notification && Notification.permission === 'granted') {
|
||||
var notification_text = notification.liveNow ? notification_data.live_now_text : notification_data.upload_text;
|
||||
notification_text = notification_text.replace('`x`', notification.author);
|
||||
// permission for notifications handled on settings page. JS handler is in handlers.js
|
||||
if (window.Notification && Notification.permission === "granted") {
|
||||
var notification_text = notification.liveNow
|
||||
? notification_data.live_now_text
|
||||
: notification_data.upload_text;
|
||||
notification_text = notification_text.replace("`x`", notification.author);
|
||||
|
||||
var system_notification = new Notification(notification_text, {
|
||||
body: notification.title,
|
||||
icon: '/ggpht' + new URL(notification.authorThumbnails[2].url).pathname,
|
||||
img: '/ggpht' + new URL(notification.authorThumbnails[4].url).pathname
|
||||
});
|
||||
var system_notification = new Notification(notification_text, {
|
||||
body: notification.title,
|
||||
icon: "/ggpht" + new URL(notification.authorThumbnails[2].url).pathname,
|
||||
img: "/ggpht" + new URL(notification.authorThumbnails[4].url).pathname,
|
||||
});
|
||||
|
||||
system_notification.onclick = function (e) {
|
||||
open('/watch?v=' + notification.videoId, '_blank');
|
||||
};
|
||||
}
|
||||
};
|
||||
system_notification.onclick = function (e) {
|
||||
open("/watch?v=" + notification.videoId, "_blank");
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
notifications.addEventListener('error', function (e) {
|
||||
console.warn('Something went wrong with notifications, trying to reconnect...');
|
||||
notifications = notifications_mock;
|
||||
setTimeout(get_subscriptions, 1000);
|
||||
});
|
||||
notifications.addEventListener("error", function (e) {
|
||||
console.warn(
|
||||
"Something went wrong with notifications, trying to reconnect...",
|
||||
);
|
||||
notifications = notifications_mock;
|
||||
|
||||
notifications.stream();
|
||||
});
|
||||
|
||||
notifications.stream();
|
||||
}
|
||||
|
||||
function update_ticker_count() {
|
||||
var notification_ticker = document.getElementById('notification_ticker');
|
||||
var notification_ticker = document.getElementById("notification_ticker");
|
||||
|
||||
const notification_count = helpers.storage.get(STORAGE_KEY_STREAM);
|
||||
if (notification_count > 0) {
|
||||
notification_ticker.innerHTML =
|
||||
'<span id="notification_count">' + notification_count + '</span> <i class="icon ion-ios-notifications"></i>';
|
||||
} else {
|
||||
notification_ticker.innerHTML =
|
||||
'<i class="icon ion-ios-notifications-outline"></i>';
|
||||
}
|
||||
const notification_count = helpers.storage.get(STORAGE_KEY_STREAM);
|
||||
if (notification_count > 0) {
|
||||
notification_ticker.innerHTML =
|
||||
'<span id="notification_count">' +
|
||||
notification_count +
|
||||
'</span> <i class="icon ion-ios-notifications"></i>';
|
||||
} else {
|
||||
notification_ticker.innerHTML =
|
||||
'<i class="icon ion-ios-notifications-outline"></i>';
|
||||
}
|
||||
}
|
||||
|
||||
function start_stream_if_needed() {
|
||||
// random wait for other tabs set 'stream' flag
|
||||
setTimeout(function () {
|
||||
if (!helpers.storage.get(STORAGE_KEY_STREAM)) {
|
||||
// if no one set 'stream', set it by yourself and start stream
|
||||
helpers.storage.set(STORAGE_KEY_STREAM, true);
|
||||
notifications = notifications_mock;
|
||||
get_subscriptions();
|
||||
}
|
||||
}, Math.random() * 1000 + 50); // [0.050 .. 1.050) second
|
||||
// random wait for other tabs set 'stream' flag
|
||||
setTimeout(
|
||||
function () {
|
||||
if (!helpers.storage.get(STORAGE_KEY_STREAM)) {
|
||||
// if no one set 'stream', set it by yourself and start stream
|
||||
helpers.storage.set(STORAGE_KEY_STREAM, true);
|
||||
notifications = notifications_mock;
|
||||
get_subscriptions();
|
||||
}
|
||||
},
|
||||
Math.random() * 1000 + 50,
|
||||
); // [0.050 .. 1.050) second
|
||||
}
|
||||
|
||||
addEventListener("storage", function (e) {
|
||||
if (e.key === STORAGE_KEY_NOTIF_COUNT) update_ticker_count();
|
||||
|
||||
addEventListener('storage', function (e) {
|
||||
if (e.key === STORAGE_KEY_NOTIF_COUNT)
|
||||
update_ticker_count();
|
||||
|
||||
// if 'stream' key was removed
|
||||
if (e.key === STORAGE_KEY_STREAM && !helpers.storage.get(STORAGE_KEY_STREAM)) {
|
||||
if (notifications) {
|
||||
// restore it if we have active stream
|
||||
helpers.storage.set(STORAGE_KEY_STREAM, true);
|
||||
} else {
|
||||
start_stream_if_needed();
|
||||
}
|
||||
// if 'stream' key was removed
|
||||
if (
|
||||
e.key === STORAGE_KEY_STREAM &&
|
||||
!helpers.storage.get(STORAGE_KEY_STREAM)
|
||||
) {
|
||||
if (notifications) {
|
||||
// restore it if we have active stream
|
||||
helpers.storage.set(STORAGE_KEY_STREAM, true);
|
||||
} else {
|
||||
start_stream_if_needed();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
addEventListener('load', function () {
|
||||
var notification_count_el = document.getElementById('notification_count');
|
||||
var notification_count = notification_count_el ? parseInt(notification_count_el.textContent) : 0;
|
||||
helpers.storage.set(STORAGE_KEY_NOTIF_COUNT, notification_count);
|
||||
addEventListener("load", function () {
|
||||
var notification_count_el = document.getElementById("notification_count");
|
||||
var notification_count = notification_count_el
|
||||
? parseInt(notification_count_el.textContent)
|
||||
: 0;
|
||||
helpers.storage.set(STORAGE_KEY_NOTIF_COUNT, notification_count);
|
||||
|
||||
if (helpers.storage.get(STORAGE_KEY_STREAM))
|
||||
helpers.storage.remove(STORAGE_KEY_STREAM);
|
||||
start_stream_if_needed();
|
||||
if (helpers.storage.get(STORAGE_KEY_STREAM))
|
||||
helpers.storage.remove(STORAGE_KEY_STREAM);
|
||||
start_stream_if_needed();
|
||||
});
|
||||
|
||||
addEventListener('unload', function () {
|
||||
// let chance to other tabs to be a streamer via firing 'storage' event
|
||||
if (notifications) helpers.storage.remove(STORAGE_KEY_STREAM);
|
||||
addEventListener("unload", function () {
|
||||
// let chance to other tabs to be a streamer via firing 'storage' event
|
||||
if (notifications) helpers.storage.remove(STORAGE_KEY_STREAM);
|
||||
});
|
||||
|
||||
function exponential_backoff(
|
||||
fn,
|
||||
maxRetries = 5,
|
||||
initialDelay = 1000,
|
||||
randomnessFactor = 0.5,
|
||||
) {
|
||||
let attempt = 0;
|
||||
|
||||
return function tryFunction() {
|
||||
fn()
|
||||
.then((response) => {
|
||||
attempt = 0;
|
||||
})
|
||||
.catch((error) => {
|
||||
if (attempt < maxRetries) {
|
||||
attempt++;
|
||||
let delay = initialDelay * Math.pow(2, attempt); // Exponential backoff
|
||||
let randomMultiplier = 1 + Math.random() * randomnessFactor;
|
||||
delay = delay * randomMultiplier;
|
||||
console.log(
|
||||
`Attempt ${attempt} failed. Retrying in ${(delay / 1000).toPrecision(2)} seconds...`,
|
||||
);
|
||||
setTimeout(tryFunction, delay); // Retry after delay
|
||||
} else {
|
||||
console.log("Max retries reached. Operation failed:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
var playlist_data = JSON.parse(document.getElementById('playlist_data').textContent);
|
||||
var payload = 'csrf_token=' + playlist_data.csrf_token;
|
||||
|
||||
function add_playlist_video(target) {
|
||||
var select = target.parentNode.children[0].children[1];
|
||||
function add_playlist_video(event) {
|
||||
const target = event.target;
|
||||
var select = document.querySelector("#playlists");
|
||||
var option = select.children[select.selectedIndex];
|
||||
|
||||
var url = '/playlist_ajax?action_add_video=1&redirect=false' +
|
||||
@@ -12,37 +13,43 @@ function add_playlist_video(target) {
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload}, {
|
||||
on200: function (response) {
|
||||
option.textContent = '✓' + option.textContent;
|
||||
option.textContent = '✓ ' + option.textContent;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function add_playlist_item(target) {
|
||||
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||
tile.style.display = 'none';
|
||||
function add_playlist_item(event) {
|
||||
event.preventDefault();
|
||||
const target = event.target;
|
||||
const video_id = target.getAttribute('data-id');
|
||||
var card = document.querySelector(`#video-card-${video_id}`);
|
||||
card.classList.add("hide");
|
||||
|
||||
var url = '/playlist_ajax?action_add_video=1&redirect=false' +
|
||||
'&video_id=' + target.getAttribute('data-id') +
|
||||
'&video_id=' + video_id +
|
||||
'&playlist_id=' + target.getAttribute('data-plid');
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload}, {
|
||||
onNon200: function (xhr) {
|
||||
tile.style.display = '';
|
||||
card.classList.remove("hide");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function remove_playlist_item(target) {
|
||||
var tile = target.parentNode.parentNode.parentNode.parentNode.parentNode;
|
||||
tile.style.display = 'none';
|
||||
function remove_playlist_item(event) {
|
||||
event.preventDefault();
|
||||
const target = event.target;
|
||||
const video_index = target.getAttribute('data-index');
|
||||
const card = document.querySelector(`.video-card [data-index="${video_index}"]`)
|
||||
card.classList.add("hide");
|
||||
|
||||
var url = '/playlist_ajax?action_remove_video=1&redirect=false' +
|
||||
'&set_video_id=' + target.getAttribute('data-index') +
|
||||
'&set_video_id=' + video_index +
|
||||
'&playlist_id=' + target.getAttribute('data-plid');
|
||||
|
||||
helpers.xhr('POST', url, {payload: payload}, {
|
||||
onNon200: function (xhr) {
|
||||
tile.style.display = '';
|
||||
card.classList.remove("hide");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ var subscribe_data = JSON.parse(document.getElementById('subscribe_data').textCo
|
||||
var payload = 'csrf_token=' + subscribe_data.csrf_token;
|
||||
|
||||
var subscribe_button = document.getElementById('subscribe');
|
||||
subscribe_button.parentNode.action = 'javascript:void(0)';
|
||||
|
||||
if (subscribe_button.getAttribute('data-type') === 'subscribe') {
|
||||
subscribe_button.onclick = subscribe;
|
||||
@@ -11,10 +10,29 @@ if (subscribe_button.getAttribute('data-type') === 'subscribe') {
|
||||
subscribe_button.onclick = unsubscribe;
|
||||
}
|
||||
|
||||
function subscribe() {
|
||||
var fallback = subscribe_button.innerHTML;
|
||||
subscribe_button.onclick = unsubscribe;
|
||||
subscribe_button.innerHTML = '<b>' + subscribe_data.unsubscribe_text + ' | ' + subscribe_data.sub_count_text + '</b>';
|
||||
function toggleSubscribeButton() {
|
||||
subscribe_button.classList.remove("primary");
|
||||
subscribe_button.classList.remove("secondary");
|
||||
subscribe_button.classList.remove("unsubscribe");
|
||||
subscribe_button.classList.remove("subscribe");
|
||||
|
||||
if (subscribe_button.getAttribute('data-type') === 'subscribe') {
|
||||
subscribe_button.textContent = subscribe_data.unsubscribe_text + ' | ' + subscribe_data.sub_count_text;
|
||||
subscribe_button.onclick = unsubscribe;
|
||||
subscribe_button.classList.add("secondary");
|
||||
subscribe_button.classList.add("unsubscribe");
|
||||
} else {
|
||||
subscribe_button.textContent = subscribe_data.subscribe_text + ' | ' + subscribe_data.sub_count_text;
|
||||
subscribe_button.onclick = subscribe;
|
||||
subscribe_button.classList.add("primary");
|
||||
subscribe_button.classList.add("subscribe");
|
||||
}
|
||||
}
|
||||
|
||||
function subscribe(e) {
|
||||
e.preventDefault();
|
||||
var fallback = subscribe_button.textContent;
|
||||
toggleSubscribeButton();
|
||||
|
||||
var url = '/subscription_ajax?action_create_subscription_to_channel=1&redirect=false' +
|
||||
'&c=' + subscribe_data.ucid;
|
||||
@@ -22,15 +40,15 @@ function subscribe() {
|
||||
helpers.xhr('POST', url, {payload: payload, retries: 5, entity_name: 'subscribe request'}, {
|
||||
onNon200: function (xhr) {
|
||||
subscribe_button.onclick = subscribe;
|
||||
subscribe_button.innerHTML = fallback;
|
||||
subscribe_button.textContent = fallback;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function unsubscribe() {
|
||||
var fallback = subscribe_button.innerHTML;
|
||||
subscribe_button.onclick = subscribe;
|
||||
subscribe_button.innerHTML = '<b>' + subscribe_data.subscribe_text + ' | ' + subscribe_data.sub_count_text + '</b>';
|
||||
function unsubscribe(e) {
|
||||
e.preventDefault();
|
||||
var fallback = subscribe_button.textContent;
|
||||
toggleSubscribeButton();
|
||||
|
||||
var url = '/subscription_ajax?action_remove_subscriptions=1&redirect=false' +
|
||||
'&c=' + subscribe_data.ucid;
|
||||
@@ -38,7 +56,7 @@ function unsubscribe() {
|
||||
helpers.xhr('POST', url, {payload: payload, retries: 5, entity_name: 'unsubscribe request'}, {
|
||||
onNon200: function (xhr) {
|
||||
subscribe_button.onclick = unsubscribe;
|
||||
subscribe_button.innerHTML = fallback;
|
||||
subscribe_button.textContent = fallback;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
44
assets/js/theme.js
Normal file
44
assets/js/theme.js
Normal file
@@ -0,0 +1,44 @@
|
||||
const themeSelector = document.querySelector("#theme-selector");
|
||||
themeSelector.addEventListener("change", (event) => {
|
||||
const select = event.target;
|
||||
const selected = select.options[select.selectedIndex].text;
|
||||
applyTheme(selected);
|
||||
});
|
||||
|
||||
const colorSchemeSelector = document.querySelector("#color-scheme");
|
||||
colorSchemeSelector.addEventListener("change", (event) => {
|
||||
const select = event.target;
|
||||
const selected = select.options[select.selectedIndex].text;
|
||||
applyColorScheme(selected);
|
||||
});
|
||||
|
||||
function applyTheme(theme) {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
link.href = `/css/theme-${theme}.css`;
|
||||
link.id = "theme-css";
|
||||
|
||||
const themeCss = document.querySelector("#theme-css");
|
||||
if (themeCss) {
|
||||
themeCss.parentNode.removeChild(themeCss);
|
||||
}
|
||||
|
||||
const head = document.getElementsByTagName("head")[0];
|
||||
head.appendChild(link);
|
||||
}
|
||||
|
||||
function applyColorScheme(colorScheme) {
|
||||
document.body.classList.remove("dark-theme");
|
||||
document.body.classList.remove("light-theme");
|
||||
|
||||
if (colorScheme === "dark" || colorScheme === "light") {
|
||||
document.body.classList.add(`${colorScheme}-theme`);
|
||||
}
|
||||
}
|
||||
|
||||
applyTheme(themeSelector.options[themeSelector.selectedIndex].text);
|
||||
applyColorScheme("dark");
|
||||
|
||||
// <link rel="stylesheet" href="/css/theme-dracula.css" />
|
||||
// <link rel="stylesheet" href="/css/theme-catppuccin-latte.css" />
|
||||
// <link rel="stylesheet" href="/css/ionicons.min.css" />
|
||||
@@ -1,13 +1,13 @@
|
||||
'use strict';
|
||||
var toggle_theme = document.getElementById('toggle_theme');
|
||||
toggle_theme.href = 'javascript:void(0)';
|
||||
|
||||
const STORAGE_KEY_THEME = 'dark_mode';
|
||||
const THEME_DARK = 'dark';
|
||||
const THEME_LIGHT = 'light';
|
||||
|
||||
// TODO: theme state controlled by system
|
||||
toggle_theme.addEventListener('click', function () {
|
||||
toggle_theme.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const isDarkTheme = helpers.storage.get(STORAGE_KEY_THEME) === THEME_DARK;
|
||||
const newTheme = isDarkTheme ? THEME_LIGHT : THEME_DARK;
|
||||
setTheme(newTheme);
|
||||
|
||||
@@ -69,6 +69,8 @@ function get_playlist(plid) {
|
||||
|
||||
helpers.xhr('GET', plid_url, {retries: 5, entity_name: 'playlist'}, {
|
||||
on200: function (response) {
|
||||
if (response === null) return;
|
||||
|
||||
playlist.innerHTML = response.playlistHtml;
|
||||
|
||||
if (!response.nextVideo) return;
|
||||
|
||||
Reference in New Issue
Block a user