flash_and_log(f"Added '{song_data['title']}' to {plist_data['name']}", "success")
- return redirect(request.referrer)
+ return {"status": "success", "messages": get_flashed_messages()}
@app.post("/edit-playlist/<int:playlistid>")
def edit_playlist_post(playlistid):
return targetUrl.origin === currentUrl.origin;
}
+var m_messageBoxTimeout;
+
async function handleAjaxResponse(response) {
if (response.status != 200) {
// Got an error; redirect to the error page
window.location.href = response.url;
}
- // Update URL in browser window
- var url = new URL(response.url);
- // Get page content from response
- var text = await response.text();
- window.history.pushState(text, "", url);
+ if (response.headers.get("content-type") === "application/json")
+ {
+ // JSON response - show message popup
+
+ var data = await response.json();
+ var messageBox = document.getElementById("message-box");
+ messageBox.textContent = data.messages[0];
+
+ if (data.status === "success")
+ {
+ messageBox.style["border-color"] = "var(--blue)";
+ }
+ else
+ {
+ messageBox.style["border-color"] = "red";
+ }
+
+ // Unhide message box for 5 seconds
+ clearTimeout(m_messageBoxTimeout);
+ messageBox.hidden = false;
+ m_messageBoxTimeout = setTimeout(() => {messageBox.hidden = true;}, 5000);
+ }
+ else
+ {
+ // HTML response
+
+ // Update URL in browser window
+ var url = new URL(response.url);
- updatePageState(text);
+ // Get page content from response
+ var text = await response.text();
+ window.history.pushState(text, "", url);
+
+ updatePageState(text);
+ }
}
// Populate page state from history stack when user navigates back
margin: 20px;
}
+#message-box {
+ box-sizing: border-box;
+ margin: 10px;
+ border-width: 3px;
+ border-radius: 10px;
+ border-style: solid;
+ padding: 10px;
+ background-color: var(--yellow);
+}
+
.title-image {
image-rendering: pixelated;
width: 512px;
<link rel="stylesheet" href="/static/styles.css?v=2"/>
<link rel="icon" type="image/x-icon" href="/static/lsp_notes.png?v=1"/>
<script src="/static/player.js?v=1"></script>
- <script src="/static/nav.js?v=1"></script>
+ <script src="/static/nav.js?v=2"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Include coloris library for color picker -->
<!-- Padding to prevent player from obscuring content -->
<div id="scroll-padding"></div>
- <!-- Song Player -->
<div class="player-container" id="player-container">
+ <!-- Message Box -->
+ <div id="message-box" hidden></div>
+
+ <!-- Song Player -->
<div class="player" id="player" hidden>
<div class="player-info">
<img id="player-pfp" class="small-pfp" src="" onerror="this.style.display = 'none'">
<h1>Site News</h1>
+<h2>??</h2>
+<ul>
+ <li>Adding a song to a playlist no longer refreshes the page</li>
+ <li>Fixed a bug where scroll position was maintained after clicking a link</li>
+</ul>
+
+
<h2>2025-03-01 - Increased Entropy</h2>
Normally programming is about bringing order to chaos, but this week I've
added chaos to your song order. There's a new Random page that will randomly
<div class="song-playlist-controls">
<form action="/append-to-playlist" method="post">
<input type="hidden" name="songid" value="{{ song.songid }}" id="playlist-selector-songid"/>
- <select name="playlistid" onchange="this.closest('form').requestSubmit()">
+ <select name="playlistid" onchange="this.closest('form').requestSubmit(); setTimeout(() => {this.selectedIndex = 0}, 0)">
<option value="-1">Add to Playlist...</option>
{% for plist in current_user_playlists -%}
<option value="{{ plist.playlistid }}">{{ plist['name'] }}</option>
def test_append_to_playlist(client):
_create_user_song_and_playlist(client)
- client.post("/append-to-playlist", data={"playlistid": "1", "songid": "1"})
- response = client.get("/")
- assert b"Added 'song title' to my playlist" in response.data
+ response = client.post("/append-to-playlist", data={"playlistid": "1", "songid": "1"})
+ data = response.json
+ assert data["status"] == "success"
+ assert "Added 'song title' to my playlist" in data["messages"]
def test_append_to_playlist_not_logged_in(client):
_create_user_song_and_playlist(client)
SOON
-- Add to playlist in background
-- Pinned profile playlists
- Comments on profile(?), playlists
- Player minimize button
- Break up main.py, test_offline.py
- Image support in comments, descriptions, bios, etc. (rich text?)
-- Profile background/banner image
-- Profile blocks(?)
+- Embeddable songs in bio
- Song sorter for song lists
- Song/User Search
- Jam(s)(??)
- Change password (require email?)
- Autoplay toggle
- Song downloads
+
+CANCEL?
+- Profile background/banner image (tile? scale? text backgrounds?)
+- Pinned profile playlists (where to put? multiple playlists?)
+- Profile blocks(?)