Add /clipboard UI for mass-tagging.
This commit is contained in:
parent
4b79308119
commit
5a1d259780
4 changed files with 132 additions and 10 deletions
|
@ -84,6 +84,7 @@ If you are interested in helping, please raise an issue before making any pull r
|
||||||
- Fix album size cache when photo reload metadata and generally improve that validation.
|
- Fix album size cache when photo reload metadata and generally improve that validation.
|
||||||
- Better bookmark url validation.
|
- Better bookmark url validation.
|
||||||
- Create a textbox which gives autocomplete tag names.
|
- Create a textbox which gives autocomplete tag names.
|
||||||
|
- Clean up the textbox hooks & handlers and make them more like stackable decorators (entry with history + bind box to button).
|
||||||
|
|
||||||
### To do list: User permissions
|
### 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.
|
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.
|
||||||
|
|
|
@ -82,7 +82,7 @@ def post_photo_add_remove_tag_core(photo_ids, tagname, add_or_remove):
|
||||||
photo.remove_tag(tag, commit=False)
|
photo.remove_tag(tag, commit=False)
|
||||||
common.P.commit()
|
common.P.commit()
|
||||||
|
|
||||||
response = {'tagname': tag.name}
|
response = {'action': add_or_remove, 'tagname': tag.name}
|
||||||
return jsonify.make_json_response(response)
|
return jsonify.make_json_response(response)
|
||||||
|
|
||||||
@site.route('/photo/<photo_id>/add_tag', methods=['POST'])
|
@site.route('/photo/<photo_id>/add_tag', methods=['POST'])
|
||||||
|
|
|
@ -11,9 +11,56 @@
|
||||||
<script src="/static/photoclipboard.js"></script>
|
<script src="/static/photoclipboard.js"></script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#content_body
|
body
|
||||||
{
|
{
|
||||||
flex-direction: column;
|
display: grid;
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
grid-template-columns: 1fr 300px;
|
||||||
|
grid-template-areas:
|
||||||
|
"header header"
|
||||||
|
"left right";
|
||||||
|
}
|
||||||
|
#header
|
||||||
|
{
|
||||||
|
grid-area: header;
|
||||||
|
}
|
||||||
|
#left
|
||||||
|
{
|
||||||
|
word-break: break-word;
|
||||||
|
grid-area: left;
|
||||||
|
}
|
||||||
|
#right
|
||||||
|
{
|
||||||
|
position: fixed;
|
||||||
|
right: 8px;
|
||||||
|
bottom: 8px;
|
||||||
|
top: 30px;
|
||||||
|
width: 300px;
|
||||||
|
grid-area: right;
|
||||||
|
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: 1fr 1fr 1fr;
|
||||||
|
grid-template-areas:
|
||||||
|
"add_tag_area"
|
||||||
|
"remove_tag_area"
|
||||||
|
"message_area";
|
||||||
|
|
||||||
|
background-color: rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
#add_tag_area
|
||||||
|
{
|
||||||
|
grid-area: add_tag_area;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
#remove_tag_area
|
||||||
|
{
|
||||||
|
grid-area: remove_tag_area;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
#message_area
|
||||||
|
{
|
||||||
|
grid-area: message_area;
|
||||||
|
margin: 8px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
@ -21,11 +68,23 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
{{header.make_header(session=session)}}
|
{{header.make_header(session=session)}}
|
||||||
<div id="content_body">
|
<div id="left">
|
||||||
<span>The clipboard contains <span class="clipboard_count">0</span> items</span>
|
<span>The clipboard contains <span class="clipboard_count">0</span> items</span>
|
||||||
<div id="photo_card_holder">
|
<div id="photo_card_holder">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="right">
|
||||||
|
<div id="add_tag_area">
|
||||||
|
<input type="text" id="add_tag_textbox">
|
||||||
|
<button class="add_tag_button green_button" id="add_tag_button" onclick="submit_add_tag(add_remove_callback);">add</button>
|
||||||
|
</div>
|
||||||
|
<div id="remove_tag_area">
|
||||||
|
<input type="text" id="remove_tag_textbox">
|
||||||
|
<button class="red_button" id="remove_tag_button" onclick="submit_remove_tag(add_remove_callback);">Remove</button>
|
||||||
|
</div>
|
||||||
|
<div id="message_area">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,6 +93,13 @@ var divs = {};
|
||||||
var needed = new Set();
|
var needed = new Set();
|
||||||
var holder = document.getElementById("photo_card_holder");
|
var holder = document.getElementById("photo_card_holder");
|
||||||
|
|
||||||
|
var add_box = document.getElementById("add_tag_textbox");
|
||||||
|
var add_button = document.getElementById("add_tag_button");
|
||||||
|
add_box.onkeydown = function(){entry_with_history_hook(add_box, add_button)};
|
||||||
|
var remove_box = document.getElementById("remove_tag_textbox");
|
||||||
|
var remove_button = document.getElementById("remove_tag_button");
|
||||||
|
remove_box.onkeydown = function(){entry_with_history_hook(remove_box, remove_button)};
|
||||||
|
|
||||||
function recalculate_needed()
|
function recalculate_needed()
|
||||||
{
|
{
|
||||||
needed = new Set();
|
needed = new Set();
|
||||||
|
@ -103,5 +169,60 @@ function myhook()
|
||||||
|
|
||||||
on_clipboard_load_hooks.push(myhook);
|
on_clipboard_load_hooks.push(myhook);
|
||||||
on_clipboard_save_hooks.push(myhook);
|
on_clipboard_save_hooks.push(myhook);
|
||||||
|
|
||||||
|
|
||||||
|
function submit_add_tag(callback)
|
||||||
|
{
|
||||||
|
var box = document.getElementById("add_tag_textbox");
|
||||||
|
var tagname = box.value.trim();
|
||||||
|
if (! tagname)
|
||||||
|
{return}
|
||||||
|
|
||||||
|
box.value = "";
|
||||||
|
return submit_add_remove_tag("add", tagname, callback);
|
||||||
|
}
|
||||||
|
function submit_remove_tag(callback)
|
||||||
|
{
|
||||||
|
var box = document.getElementById("remove_tag_textbox");
|
||||||
|
var tagname = box.value.trim();
|
||||||
|
if (! tagname)
|
||||||
|
{return}
|
||||||
|
|
||||||
|
box.value = "";
|
||||||
|
return submit_add_remove_tag("remove", tagname, callback);
|
||||||
|
}
|
||||||
|
function submit_add_remove_tag(action, tagname, callback)
|
||||||
|
{
|
||||||
|
var url = "/batch/photos/" + action + "_tag";
|
||||||
|
var data = new FormData();
|
||||||
|
var photo_ids = Array.from(photo_clipboard).join(",");
|
||||||
|
data.append("photo_ids", photo_ids);
|
||||||
|
data.append("tagname", tagname);
|
||||||
|
post(url, data, callback);
|
||||||
|
}
|
||||||
|
function add_remove_callback(response)
|
||||||
|
{
|
||||||
|
response = response["data"];
|
||||||
|
var tagname = response["tagname"];
|
||||||
|
var message_positivity;
|
||||||
|
var message_text;
|
||||||
|
|
||||||
|
if ("error_type" in response)
|
||||||
|
{
|
||||||
|
message_positivity = "message_negative";
|
||||||
|
message_text = response["error_message"];
|
||||||
|
}
|
||||||
|
else if ("action" in response)
|
||||||
|
{
|
||||||
|
var action = response["action"];
|
||||||
|
message_positivity = "message_positive";
|
||||||
|
if (action == "add")
|
||||||
|
{message_text = "Added tag " + tagname;}
|
||||||
|
|
||||||
|
else if (action == "remove")
|
||||||
|
{message_text = "Removed tag " + tagname;}
|
||||||
|
}
|
||||||
|
create_message_bubble(message_area, message_positivity, message_text, 8000);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Reference in a new issue