commit b451043d51358aaa8843f7ed51fe2c9547fe332e
parent 4a8bb379f5955a44dfdedf282e4773ff2f27daca
Author: Asher Morgan <59518073+ashermorgan@users.noreply.github.com>
Date: Thu, 11 Jul 2024 15:24:38 -0700
Save custom song lyrics in localStorage
Diffstat:
5 files changed, 89 insertions(+), 28 deletions(-)
diff --git a/songs2slides/static/create.css b/songs2slides/static/create.css
@@ -75,7 +75,11 @@ textarea {
.missing summary {
color: var(--error);
}
+summary span {
+ display: none;
+}
.missing summary span {
+ display: inline;
float: right;
font-weight: bold;
}
diff --git a/songs2slides/static/create.js b/songs2slides/static/create.js
@@ -1,11 +1,16 @@
// Global Songs2Slides localStorage prefix
const PREFIX = 's2s'
+// HTML form
+let form = null
+
// Page load/reload handler
addEventListener('pageshow', () => {
// Correct page state after returning via browser back button
document.getElementById('post-submit').hidden = true
+ form = document.getElementById('create-form')
+
if (STEP === 1) {
// Load songs
for (let row of document.querySelectorAll('tbody tr')) {
@@ -18,9 +23,10 @@ addEventListener('pageshow', () => {
raw_song.children[1].children[0].value = song.title
raw_song.children[2].children[0].value = song.artist
}
+ } else if (STEP === 2) {
+ load_lyrics()
} else if (STEP === 3) {
// Load settings
- const form = document.getElementById('create-form')
form['title-slides'].checked = storage_get('title-slides', true)
form['blank-slides'].checked = storage_get('blank-slides', true)
form['output-type'].value = storage_get('output-type', 'html')
@@ -32,9 +38,10 @@ addEventListener('submit', () => {
// Show loading spinner
document.getElementById('post-submit').hidden = false
- if (STEP === 3) {
+ if (STEP === 2) {
+ save_lyrics()
+ } else if (STEP === 3) {
// Save settings
- const form = document.getElementById('create-form')
storage_set('title-slides', form['title-slides'].checked)
storage_set('blank-slides', form['blank-slides'].checked)
storage_set('output-type', form['output-type'].value)
@@ -86,7 +93,47 @@ function save_songs() {
storage_set('songs', songs)
}
-// Step 3 helper functions
+// Step 2 functions
+function get_song_key(title, artist) {
+ return 'lyrics-' + artist.toLowerCase().replaceAll(' ', '-') +
+ '-' + title.toLowerCase().replaceAll(' ', '-')
+}
+
+function save_lyrics() {
+ for (let i = 1; `title-${i}` in form; i++) {
+ const title = form[`title-${i}`].value
+ const artist = form[`artist-${i}`].value
+ const lyrics = form[`lyrics-${i}`].value
+ const key = get_song_key(title, artist)
+ storage_set(key, lyrics)
+ }
+}
+
+function load_lyrics() {
+ songs = document.getElementsByTagName('details')
+ for (let i = 1; `title-${i}` in form; i++) {
+ const title = form[`title-${i}`].value
+ const artist = form[`artist-${i}`].value
+ const key = get_song_key(title, artist)
+ const saved_lyrics = storage_get(key, '')
+ if (saved_lyrics !== '') {
+ form[`lyrics-${i}`].value = saved_lyrics
+ songs[i - 1].classList.remove('missing')
+ songs[i - 1].open = false
+ }
+ }
+
+ // Update missing label
+ const number = document.getElementsByClassName('missing').length
+ document.getElementById('missing-count').textContent = number
+ if (number === 0) {
+ document.getElementById('missing-message').hidden = true
+ } else {
+ document.getElementById('missing-message').hidden = false
+ }
+}
+
+// Local storage helper functions
function storage_get(key, default_value) {
try {
value = JSON.parse(localStorage.getItem(`${PREFIX}.${key}`))
diff --git a/songs2slides/templates/create-step-1.html b/songs2slides/templates/create-step-1.html
@@ -8,7 +8,7 @@
{% endblock head %}
{% block main %}
-<form method="POST" action="{{ url_for('.create_step_2') }}">
+<form id="create-form" method="POST" action="{{ url_for('.create_step_2') }}">
<h1>Step 1: Select Songs</h1>
<p>
diff --git a/songs2slides/templates/create-step-2.html b/songs2slides/templates/create-step-2.html
@@ -14,7 +14,7 @@
%}
{% block main %}
-<form method="POST" action="{{ url_for('.create_step_3') }}">
+<form id="create-form" method="POST" action="{{ url_for('.create_step_3') }}">
<h1>Step 2: Review Lyrics</h1>
<p>
Review the parsed song lyrics below and make any necessary corrections.
@@ -23,12 +23,10 @@
{{ format_hint }}
</p>
- {% if missing > 0 %}
- <p>
- Lyrics must be entered manually for <strong>{{ missing }}
- song{% if missing != 1 %}s{% endif %}</strong>.
+ <p id="missing-message" {% if missing == 0 %} hidden {% endif %}>
+ Lyrics must be entered manually for
+ <span id="missing-count">{{ missing }}</span> song(s).
</p>
- {% endif %}
<div>
{% for song in songs %}
@@ -48,19 +46,16 @@
({{ song.artist }})
{% endif %}
- {% if not song.lyrics %}
- <span>lyrics not found</span>
- {% endif %}
+ <span {% if not song.lyrics %} hidden {% endif %}>
+ lyrics not found
+ </span>
</summary>
- {% if song.lyrics %}
- <textarea name="lyrics-{{ loop.index }}" placeholder="{{format_hint}}"
- aria-label="{{ song.title }} Lyrics">{{ song.lyrics }}</textarea>
- {% else %}
<textarea name="lyrics-{{ loop.index }}" placeholder="{{
- 'Lyrics not found, please enter them here manually.\n\n' +
- format_hint }}" aria-label="{{ song.title }} Lyrics"></textarea>
- {% endif %}
+ 'Lyrics not found, please enter them here manually.\n\n'
+ if not songs.lyrics else '' }}{{ format_hint }}"
+ aria-label="{{ song.title }} Lyrics"
+ >{{ song.lyrics or '' }}</textarea>
</details>
{% endfor %}
</div>
diff --git a/tests/test_e2e.py b/tests/test_e2e.py
@@ -20,11 +20,12 @@ def test_basic(page: Page):
expect(page).to_have_url('http://localhost:5002/create/step-2/')
# Assert missing song message is correct
- expect(page.get_by_text('Lyrics must be entered manually for 1 song.')).to_be_visible()
+ expect(page.get_by_text('Lyrics must be entered manually for 1 song(s).')).to_be_visible()
# Assert songs are loaded
expect(page.get_by_text('Song 1 (Artist A)')).to_be_visible()
- expect(page.get_by_text('Song 1 (Artist A) lyrics not found')).to_be_hidden()
+ expect(page.get_by_text('lyrics not found').first).to_be_hidden()
+ expect(page.get_by_text('lyrics not found').last).to_be_visible()
expect(page.get_by_text('Song 5 lyrics not found')).to_be_visible()
# Assert song lyrics are loaded (Song 1 lyrics still collapsed)
@@ -127,7 +128,9 @@ def test_localStorage(page: Page):
page.get_by_role('button', name='Next').click()
expect(page).to_have_url('http://localhost:5002/create/step-2/')
- # Fill in missing lyrics
+ # Update lyrics
+ page.get_by_text('Song 1 (Artist A)').click()
+ page.get_by_role('textbox').first.fill('custom song 1 lyrics')
page.get_by_role('textbox').last.fill('custom song 5 lyrics')
# Click Next
@@ -166,8 +169,18 @@ def test_localStorage(page: Page):
page.get_by_role('button', name='Next').click()
expect(page).to_have_url('http://localhost:5002/create/step-2/')
- # Fill in missing lyrics
- page.get_by_role('textbox').last.fill('custom song 5 lyrics')
+ # Assert song lyrics are collapsed and not missing
+ expect(page.get_by_role('textbox')).to_have_count(0)
+ expect(page.get_by_text('lyrics not found').first).to_be_hidden()
+ expect(page.get_by_text('lyrics not found').last).to_be_hidden()
+
+ # Uncollapse songs
+ page.get_by_text('Song 1 (Artist A)').click()
+ page.get_by_text('Song 5').click()
+
+ # Assert song lyrics are prefilled
+ expect(page.get_by_role('textbox').first).to_have_value('custom song 1 lyrics')
+ expect(page.get_by_role('textbox').last).to_have_value('custom song 5 lyrics')
# Click Next
page.get_by_role('button', name='Next').click()
@@ -231,7 +244,8 @@ def test_back(page: Page):
# Assert songs are loaded
expect(page.get_by_text('Song 1 (Artist A)')).to_be_visible()
- expect(page.get_by_text('Song 1 (Artist A) lyrics not found')).to_be_hidden()
+ expect(page.get_by_text('lyrics not found').first).to_be_hidden()
+ expect(page.get_by_text('lyrics not found').last).to_be_visible()
expect(page.get_by_text('Song 5 lyrics not found')).to_be_visible()
# Uncollapse Song 1
@@ -253,8 +267,9 @@ def test_back(page: Page):
page.get_by_role('button', name='Back').click()
expect(page).to_have_url('http://localhost:5002/create/step-2/')
- # Uncollapse Song 1
+ # Uncollapse songs
page.get_by_text('Song 1 (Artist A)').click()
+ page.get_by_text('Song 5').click()
# Assert bad song lyrics are still loaded
expect(page.get_by_role('textbox')).to_have_count(2)