diff --git a/README.md b/README.md index 0ed5427..7713602 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,7 @@ If you are interested in helping, please raise an issue before making any pull r - Use browser localstorage to act as a clipboard for holding photos, so that you can select them on one tab and move them into an album on another, etc. - Perhaps instead of actually deleting objects, they should just have a `deleted` flag, to make easy restoration possible. Also consider regrouping the children of restored Groupables if those children haven't already been reassigned somewhere else. - Add a new table to store permanent history of add/remove of tags on photos, so that accidents or trolling can be reversed. +- Currently, the photo clipboard only stores IDs and therefore when we construct the clipboard tray elements we cannot provide more rich information like filename, the user is only presented with a list of IDs which they probably don't care about. Should the localstorage cache some other more user-friendly information? ### To do list: User permissions Here are some thoughts about the kinds of features that need to exist within the permission system. I don't know how I'll actually manage it just yet. Possibly a `permissions` table in the database with `user_id | permission` where `permission` is some reliably-formatted string. diff --git a/frontends/etiquette_flask/static/common.css b/frontends/etiquette_flask/static/common.css index 351e87a..8bc4aae 100644 --- a/frontends/etiquette_flask/static/common.css +++ b/frontends/etiquette_flask/static/common.css @@ -284,3 +284,30 @@ is hovered over. { background-color: #faa; } + +#clipboard_tray +{ + display: flex; + flex-direction: column; + + position: fixed; + right: 8px; + bottom: 8px; + z-index: 10; + + max-height: 80%; + min-width: 150px; + padding: 2px; + + background-color: #ffffd4; +} +#clipboard_tray_expandbutton +{ + flex: 1 0 auto; + width: 100%; +} +#clipboard_tray_body +{ + width: 300px; + overflow-y: auto; +} diff --git a/frontends/etiquette_flask/static/common.js b/frontends/etiquette_flask/static/common.js index 73f61ee..018aee3 100644 --- a/frontends/etiquette_flask/static/common.js +++ b/frontends/etiquette_flask/static/common.js @@ -292,6 +292,14 @@ function create_album_and_follow(parent) post(url, data, receive_callback); } +function delete_all_children(element) +{ + while (element.firstChild) + { + element.removeChild(element.firstChild); + } +} + function entry_with_history_hook(box, button) { //console.log(event.keyCode); diff --git a/frontends/etiquette_flask/static/photoclipboard.js b/frontends/etiquette_flask/static/photoclipboard.js index af4b02b..fc57e2c 100644 --- a/frontends/etiquette_flask/static/photoclipboard.js +++ b/frontends/etiquette_flask/static/photoclipboard.js @@ -1,5 +1,7 @@ var photo_clipboard = new Set(); +//////////////////////////////////////////////////////////////////////////////// +//--LOAD-SAVE-----------------------------------------------------------------// function load_photo_clipboard(event) { console.log("Loading photo clipboard"); @@ -15,9 +17,6 @@ function load_photo_clipboard(event) { photo_clipboard = new Set(JSON.parse(stored)); } - - var photo_divs = Array.from(document.getElementsByClassName("photo_card")); - photo_divs.forEach(apply_check); return photo_clipboard; } @@ -26,12 +25,16 @@ function save_photo_clipboard() console.log("Saving photo clipboard"); var serialized = JSON.stringify(Array.from(photo_clipboard)); localStorage.setItem("photo_clipboard", serialized); + on_storage(); } -function apply_check(photo_div) + +//////////////////////////////////////////////////////////////////////////////// +//*-CARD MANAGEMENT-----------------------------------------------------------// +function apply_check(photo_card) { - var checkbox = photo_div.getElementsByClassName("photo_card_selector_checkbox")[0]; - if (photo_clipboard.has(photo_div.dataset.id)) + var checkbox = photo_card.getElementsByClassName("photo_card_selector_checkbox")[0]; + if (photo_clipboard.has(photo_card.dataset.id)) { checkbox.checked = true; } @@ -41,6 +44,12 @@ function apply_check(photo_div) } } +function update_checked_cards() +{ + var photo_divs = Array.from(document.getElementsByClassName("photo_card")); + photo_divs.forEach(apply_check); +} + var previous_photo_select; function on_photo_select(event) { @@ -95,9 +104,80 @@ function on_photo_select(event) save_photo_clipboard(); } -function onpageload() + +//////////////////////////////////////////////////////////////////////////////// +//--TRAY MANAGEMENT-----------------------------------------------------------// +function toggle_clipboard_tray_collapsed() { - window.addEventListener("storage", load_photo_clipboard, false); - load_photo_clipboard(); + var tray_body = document.getElementById("clipboard_tray_body"); + if (tray_body.classList.contains("hidden") && photo_clipboard.size > 0) + { + tray_body.classList.remove("hidden"); + update_clipboard_tray(); + } + else + { + tray_body.classList.add("hidden"); + } } -document.addEventListener("DOMContentLoaded", onpageload); + +function on_tray_delete_button(event) +{ + var clipboard_line = event.target.parentElement; + var photo_id = clipboard_line.dataset.id; + photo_clipboard.delete(photo_id); + if (photo_clipboard.size == 0) + { + toggle_clipboard_tray_collapsed(); + } + save_photo_clipboard(); +} + +function update_clipboard_tray() +{ + var tray_button = document.getElementById("clipboard_tray_expandbutton"); + if (tray_button !== null) + { + tray_button.innerText = "Clipboard: " + photo_clipboard.size + " items"; + } + + var tray_body = document.getElementById("clipboard_tray_body"); + if (!clipboard_tray.classList.contains("hidden")) + { + delete_all_children(tray_body); + var photo_ids = Array.from(photo_clipboard); + photo_ids.sort(); + for (var i = 0; i < photo_ids.length; i += 1) + { + var clipboard_line = document.createElement("div"); + clipboard_line.classList.add("clipboard_tray_line"); + clipboard_line.dataset.id = photo_ids[i]; + + var clipboard_line_delete_button = document.createElement("button"); + clipboard_line_delete_button.classList.add("remove_tag_button_perm"); + clipboard_line_delete_button.onclick = on_tray_delete_button; + + var clipboard_line_link = document.createElement("a"); + clipboard_line_link.target = "_blank"; + clipboard_line_link.href = "/photo/" + photo_ids[i]; + clipboard_line_link.innerText = photo_ids[i]; + + clipboard_line.appendChild(clipboard_line_delete_button); + clipboard_line.appendChild(clipboard_line_link); + tray_body.appendChild(clipboard_line); + } + } +} + +function on_storage() +{ + load_photo_clipboard(); + update_checked_cards(); + update_clipboard_tray(); +} +function on_pageload() +{ + window.addEventListener("storage", on_storage, false); + on_storage(); +} +document.addEventListener("DOMContentLoaded", on_pageload); diff --git a/frontends/etiquette_flask/templates/album.html b/frontends/etiquette_flask/templates/album.html index c132c0b..d1917aa 100644 --- a/frontends/etiquette_flask/templates/album.html +++ b/frontends/etiquette_flask/templates/album.html @@ -3,6 +3,7 @@
{% import "photo_card.html" as photo_card %} {% import "header.html" as header %} + {% import "clipboard_tray.html" as clipboard_tray %}