|
|
@@ -20,7 +20,10 @@ document.addEventListener("alpine:init", () => {
|
|
|
history: {},
|
|
|
sortedHistory: [],
|
|
|
openMenus: new Set(), // Track which menus are open
|
|
|
- currentView: 'playlists', // Track current view: 'playlists' or 'history'
|
|
|
+ currentView: 'playlists', // Track current view: 'playlists', 'history', or 'playlist'
|
|
|
+ currentPlaylistName: '', // Track which playlist is being viewed
|
|
|
+ playlistsForDisplay: [], // Computed array for display
|
|
|
+ currentPlaylistVideos: [], // Videos for current playlist view
|
|
|
|
|
|
init() {
|
|
|
this.loadPlaylists();
|
|
|
@@ -60,6 +63,39 @@ document.addEventListener("alpine:init", () => {
|
|
|
} catch (error) {
|
|
|
console.error("Error loading playlists:", error);
|
|
|
}
|
|
|
+ this.updatePlaylistsForDisplay();
|
|
|
+ },
|
|
|
+
|
|
|
+ updatePlaylistsForDisplay() {
|
|
|
+ this.playlistsForDisplay = Object.entries(this.playlists).map(([playlistName, videos]) => {
|
|
|
+ const currentIndex = this.currentIndices[playlistName] || 0;
|
|
|
+ const shouldShowTruncation = currentIndex > 0;
|
|
|
+ const truncationText = shouldShowTruncation
|
|
|
+ ? `(${currentIndex} previous video${currentIndex === 1 ? '' : 's'})`
|
|
|
+ : '';
|
|
|
+
|
|
|
+ // Get visible videos from current index onwards with original indices
|
|
|
+ const visibleVideos = videos.slice(currentIndex).map((video, index) => ({
|
|
|
+ ...video,
|
|
|
+ originalIndex: currentIndex + index
|
|
|
+ }));
|
|
|
+
|
|
|
+ return {
|
|
|
+ name: playlistName,
|
|
|
+ videos: videos,
|
|
|
+ visibleVideos: visibleVideos,
|
|
|
+ shouldShowTruncation: shouldShowTruncation,
|
|
|
+ truncationText: truncationText
|
|
|
+ };
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ updateCurrentPlaylistVideos() {
|
|
|
+ if (!this.currentPlaylistName || !this.playlists[this.currentPlaylistName]) {
|
|
|
+ this.currentPlaylistVideos = [];
|
|
|
+ } else {
|
|
|
+ this.currentPlaylistVideos = this.playlists[this.currentPlaylistName];
|
|
|
+ }
|
|
|
},
|
|
|
|
|
|
async loadHistory() {
|
|
|
@@ -167,6 +203,8 @@ document.addEventListener("alpine:init", () => {
|
|
|
try {
|
|
|
await browser.storage.local.set({ playlists: updatedPlaylists });
|
|
|
this.playlists = updatedPlaylists;
|
|
|
+ this.updatePlaylistsForDisplay();
|
|
|
+ this.updateCurrentPlaylistVideos();
|
|
|
} catch (error) {
|
|
|
console.error("Error removing video:", error);
|
|
|
}
|
|
|
@@ -197,6 +235,8 @@ document.addEventListener("alpine:init", () => {
|
|
|
try {
|
|
|
await browser.storage.local.set({ playlists: updatedPlaylists });
|
|
|
this.playlists = updatedPlaylists;
|
|
|
+ this.updatePlaylistsForDisplay();
|
|
|
+ this.updateCurrentPlaylistVideos();
|
|
|
} catch (error) {
|
|
|
console.error("Error moving video up:", error);
|
|
|
}
|
|
|
@@ -225,6 +265,8 @@ document.addEventListener("alpine:init", () => {
|
|
|
try {
|
|
|
await browser.storage.local.set({ playlists: updatedPlaylists });
|
|
|
this.playlists = updatedPlaylists;
|
|
|
+ this.updatePlaylistsForDisplay();
|
|
|
+ this.updateCurrentPlaylistVideos();
|
|
|
} catch (error) {
|
|
|
console.error("Error moving video down:", error);
|
|
|
}
|
|
|
@@ -448,6 +490,8 @@ document.addEventListener("alpine:init", () => {
|
|
|
try {
|
|
|
await browser.storage.local.set({ playlists });
|
|
|
this.playlists = playlists;
|
|
|
+ this.updatePlaylistsForDisplay();
|
|
|
+ this.updateCurrentPlaylistVideos();
|
|
|
alert("Playlists imported successfully!");
|
|
|
} catch (error) {
|
|
|
console.error("Error updating playlists:", error);
|
|
|
@@ -506,6 +550,40 @@ document.addEventListener("alpine:init", () => {
|
|
|
this.currentView = 'playlists';
|
|
|
},
|
|
|
|
|
|
+ showPlaylist(playlistName) {
|
|
|
+ this.currentView = 'playlist';
|
|
|
+ this.currentPlaylistName = playlistName;
|
|
|
+ this.updateCurrentPlaylistVideos();
|
|
|
+ },
|
|
|
+
|
|
|
+ // Methods for truncated display
|
|
|
+ shouldShowTruncation(playlistName) {
|
|
|
+ const currentIndex = this.currentIndices[playlistName] || 0;
|
|
|
+ return currentIndex > 0;
|
|
|
+ },
|
|
|
+
|
|
|
+ getTruncationText(playlistName) {
|
|
|
+ const currentIndex = this.currentIndices[playlistName] || 0;
|
|
|
+ const count = currentIndex;
|
|
|
+ return `(${count} previous video${count === 1 ? '' : 's'})`;
|
|
|
+ },
|
|
|
+
|
|
|
+ getVisibleVideos(playlistName, videos) {
|
|
|
+ const currentIndex = this.currentIndices[playlistName] || 0;
|
|
|
+ // Show from current video onwards, but keep original indices
|
|
|
+ return videos.slice(currentIndex).map((video, index) => ({
|
|
|
+ ...video,
|
|
|
+ originalIndex: currentIndex + index
|
|
|
+ }));
|
|
|
+ },
|
|
|
+
|
|
|
+ getCurrentPlaylistVideos() {
|
|
|
+ if (!this.currentPlaylistName || !this.playlists[this.currentPlaylistName]) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ return this.playlists[this.currentPlaylistName];
|
|
|
+ },
|
|
|
+
|
|
|
// Button bindings for navigation
|
|
|
historyButton: {
|
|
|
["@click"]() {
|
|
|
@@ -519,6 +597,40 @@ document.addEventListener("alpine:init", () => {
|
|
|
},
|
|
|
},
|
|
|
|
|
|
+ // Event handlers for playlist navigation
|
|
|
+ playlistNameClick: {
|
|
|
+ ["@click"]() {
|
|
|
+ const playlistName = this.$el.dataset.playlistName;
|
|
|
+ this.showPlaylist(playlistName);
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ truncatedVideosClick: {
|
|
|
+ ["@click"]() {
|
|
|
+ const playlistName = this.$el.dataset.playlistName;
|
|
|
+ this.showPlaylist(playlistName);
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ truncatedVideosClick: {
|
|
|
+ ["@click"]() {
|
|
|
+ const playlistName = this.$el.dataset.playlistName;
|
|
|
+ this.showPlaylist(playlistName);
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
+ truncatedVideosDisplay: {
|
|
|
+ ["x-show"]() {
|
|
|
+ const playlistName = this.$el.dataset.playlistName;
|
|
|
+ const playlistData = this.playlistsForDisplay.find(p => p.name === playlistName);
|
|
|
+ return playlistData ? playlistData.shouldShowTruncation : false;
|
|
|
+ },
|
|
|
+ ["@click"]() {
|
|
|
+ const playlistName = this.$el.dataset.playlistName;
|
|
|
+ this.showPlaylist(playlistName);
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
// CSP-compliant view bindings
|
|
|
playlistsHeader: {
|
|
|
["x-show"]() {
|
|
|
@@ -532,6 +644,12 @@ document.addEventListener("alpine:init", () => {
|
|
|
},
|
|
|
},
|
|
|
|
|
|
+ playlistViewHeader: {
|
|
|
+ ["x-show"]() {
|
|
|
+ return this.currentView === 'playlist';
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
playlistsContainer: {
|
|
|
["x-show"]() {
|
|
|
return this.currentView === 'playlists';
|
|
|
@@ -544,6 +662,12 @@ document.addEventListener("alpine:init", () => {
|
|
|
},
|
|
|
},
|
|
|
|
|
|
+ playlistViewContainer: {
|
|
|
+ ["x-show"]() {
|
|
|
+ return this.currentView === 'playlist';
|
|
|
+ },
|
|
|
+ },
|
|
|
+
|
|
|
exportContainer: {
|
|
|
["x-show"]() {
|
|
|
return this.currentView === 'playlists';
|
|
|
@@ -556,5 +680,12 @@ document.addEventListener("alpine:init", () => {
|
|
|
return this.sortedHistory.length === 0;
|
|
|
},
|
|
|
},
|
|
|
+
|
|
|
+ // Playlist view-specific bindings for CSP compliance
|
|
|
+ playlistViewEmptyState: {
|
|
|
+ ["x-show"]() {
|
|
|
+ return this.currentPlaylistVideos.length === 0;
|
|
|
+ },
|
|
|
+ },
|
|
|
}));
|
|
|
});
|