Add new page /clipboard, with full photo cards.
This commit is contained in:
		
							parent
							
								
									ef5bbf5fc3
								
							
						
					
					
						commit
						91d445a877
					
				
					 7 changed files with 154 additions and 1 deletions
				
			
		|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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(): | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|     { |     { | ||||||
|  |  | ||||||
							
								
								
									
										101
									
								
								frontends/etiquette_flask/templates/clipboard.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								frontends/etiquette_flask/templates/clipboard.html
									
									
									
									
									
										Normal 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> | ||||||
|  | @ -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> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue