Add new page /clipboard, with full photo cards.

master
voussoir 2018-02-17 19:12:34 -08:00
parent ef5bbf5fc3
commit 91d445a877
7 changed files with 154 additions and 1 deletions

View File

@ -79,7 +79,6 @@ If you are interested in helping, please raise an issue before making any pull r
- Currently, the Jinja templates are having a tangling influence on the backend objects, because Jinja cannot import my other modules like bytestring, but it can access the methods of the objects I pass into the template. As a result, the objects have excess helper methods. Consider making them into Jinja filters instead. Which is also kind of ugly but will move that pollution out of the backend at least. - Currently, the Jinja templates are having a tangling influence on the backend objects, because Jinja cannot import my other modules like bytestring, but it can access the methods of the objects I pass into the template. As a result, the objects have excess helper methods. Consider making them into Jinja filters instead. Which is also kind of ugly but will move that pollution out of the backend at least.
- 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. - 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. - 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?
- Improve transaction rollbacking. I'm not satisfied with the @transaction decorator because sometimes I want to use exceptions as control flow without them rolling things back. Context managers are good but it's a matter of how abstracted they should be. - Improve transaction rollbacking. I'm not satisfied with the @transaction decorator because sometimes I want to use exceptions as control flow without them rolling things back. Context managers are good but it's a matter of how abstracted they should be.
### To do list: User permissions ### To do list: User permissions

View File

@ -115,6 +115,40 @@ def post_photo_refresh_metadata(photo_id):
return jsonify.make_json_response({}) return jsonify.make_json_response({})
# Clipboard ########################################################################################
@site.route('/clipboard')
@session_manager.give_token
def get_clipboard_page():
return flask.render_template('clipboard.html')
@site.route('/photo_cards', methods=['POST'])
def get_photo_cards():
photo_ids = request.form.get('photo_ids', None)
if photo_ids is None:
return jsonify.make_json_response({})
photo_ids = etiquette.helpers.comma_space_split(photo_ids)
photos = [common.P_photo(photo_id, response_type='html') for photo_id in photo_ids]
# Photo filenames are prevented from having colons, so using it as a split
# delimiter should be safe.
template = '''
{% import "photo_card.html" as photo_card %}
{% for photo in photos %}
{{photo.id}}:
{{photo_card.create_photo_card(photo)}}
:SPLITME:
{% endfor %}
'''
html = flask.render_template_string(template, photos=photos)
divs = [div.strip() for div in html.split(':SPLITME:')]
divs = [div for div in divs if div]
divs = [div.split(':', 1) for div in divs]
divs = {photo_id.strip(): photo_card.strip() for (photo_id, photo_card) in divs}
response = jsonify.make_json_response(divs)
return response
# Search ########################################################################################### # Search ###########################################################################################
def get_search_core(): def get_search_core():

View File

@ -305,3 +305,8 @@ is hovered over.
width: 300px; width: 300px;
overflow-y: auto; overflow-y: auto;
} }
#clipboard_tray_toolbox
{
display: flex;
flex-direction: column;
}

View File

@ -356,3 +356,10 @@ function entry_with_history_hook(box, button)
box.entry_history_pos = -1; box.entry_history_pos = -1;
} }
} }
function html_to_element(html)
{
var template = document.createElement("template");
template.innerHTML = html;
return template.content.firstChild;
}

View File

@ -173,6 +173,12 @@ function update_clipboard_tray()
Update the clipboard's title bar to the correct number of items and rebuild Update the clipboard's title bar to the correct number of items and rebuild
the rows if the tray is open. the rows if the tray is open.
*/ */
var clipboard_tray = document.getElementById("clipboard_tray");
if (clipboard_tray === null)
{
return;
}
var tray_button = document.getElementById("clipboard_tray_expandbutton"); var tray_button = document.getElementById("clipboard_tray_expandbutton");
if (tray_button !== null) if (tray_button !== null)
{ {

View File

@ -0,0 +1,101 @@
<!DOCTYPE html5>
<html>
<head>
{% import "header.html" as header %}
{% import "clipboard_tray.html" as clipboard_tray %}
<title>Clipboard</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="stylesheet" href="/static/common.css">
<script src="/static/common.js"></script>
<script src="/static/photoclipboard.js"></script>
<style>
</style>
</head>
<body>
{{header.make_header(session=session)}}
<div id="content_body">
<div id="photo_card_holder">
</div>
</div>
</body>
<script type="text/javascript">
var divs = {};
var needed = new Set();
var holder = document.getElementById("photo_card_holder");
function recalculate_needed()
{
needed = new Set();
photo_clipboard.forEach(function(photo_id)
{
if (!(photo_id in divs))
{
needed.add(photo_id);
}
});
}
function refresh_divs()
{
for (var photo_id in divs)
{
var photo_div = divs[photo_id];
var should_keep = photo_clipboard.has(photo_id);
var on_page = holder.contains(photo_div);
if (on_page && !should_keep)
{
holder.removeChild(photo_div)
}
if (!on_page && should_keep)
{
holder.appendChild(photo_div)
}
}
}
function request_more_divs()
{
if (needed.size == 0)
{
return;
}
var url = "/photo_cards";
var data = new FormData();
var photo_ids = Array.from(needed).join(",");
data.append("photo_ids", photo_ids);
function callback(response)
{
if (response["meta"]["status"] !== 200)
{
return;
}
response = response["data"];
var holder = document.getElementById("photo_card_holder");
for (photo_id in response)
{
photo_div = html_to_element(response[photo_id]);
divs[photo_id] = photo_div;
needed.delete(photo_id)
holder.appendChild(photo_div);
}
apply_check_all();
}
post(url, data, callback);
}
function myhook()
{
recalculate_needed();
request_more_divs();
refresh_divs();
}
on_clipboard_load_hooks.push(myhook);
</script>
</html>

View File

@ -7,6 +7,7 @@
>Clipboard: 0 items</button> >Clipboard: 0 items</button>
<div id="clipboard_tray_body" class="hidden"> <div id="clipboard_tray_body" class="hidden">
<div id="clipboard_tray_toolbox"> <div id="clipboard_tray_toolbox">
<a target="_blank" href="/clipboard">Full clipboard</a>
</div> </div>
<div id="clipboard_tray_lines"> <div id="clipboard_tray_lines">
</div> </div>