From 443d93ce18432ed9882048eef9a92297296447a9 Mon Sep 17 00:00:00 2001
From: Ethan Dalool
Date: Sat, 16 Dec 2017 03:47:54 -0800
Subject: [PATCH] Add the clipboard tray where users manage their photo
clipboard.
Appearing on search and album pages, the tray is where you can
remove items from your clipboard without having to click on its
checkbox -- that photo card may not even be on the current page.
---
README.md | 1 +
frontends/etiquette_flask/static/common.css | 27 +++++
frontends/etiquette_flask/static/common.js | 8 ++
.../etiquette_flask/static/photoclipboard.js | 100 ++++++++++++++++--
.../etiquette_flask/templates/album.html | 2 +
.../templates/clipboard_tray.html | 11 ++
.../etiquette_flask/templates/search.html | 9 +-
7 files changed, 143 insertions(+), 15 deletions(-)
create mode 100644 frontends/etiquette_flask/templates/clipboard_tray.html
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 %}
Album {{album.display_name}}
@@ -115,6 +116,7 @@ p
{% endif %}
{% endif %}