<!DOCTYPE html5> <html> <head> {% import "header.html" as header %} <title>Photo</title> <meta charset="UTF-8"> <link rel="stylesheet" href="/static/common.css"> <script src="/static/common.js"></script> {% set filename = photo.id + photo.dot_extension %} {% set file_link = "/file/" + filename %} <style> #content_body { /* Override common.css */ flex-direction: row; flex: 1; } #left { display: flex; flex-direction: column; } #right { flex: 1; display: flex; } #editor_holder { max-width: 300px; padding: 8px; flex-direction: column; background-color: rgba(0, 0, 0, 0.1); } #editor_area { flex: 3; word-wrap: break-word; } #message_area { flex: 1; } .photo_viewer { display: flex; flex: 1; flex-direction: column; justify-content: center; align-items: center; } .photo_viewer a { display: flex; justify-content: center; align-items: center; } #photo_img_holder { height: 100%; width: 100%; display: flex; justify-content: center; align-items: center; background-repeat: no-repeat; } #photo_img_holder img { max-height: 100%; max-width: 100%; } .photo_viewer audio { width: 100%; } .photo_viewer video { max-width: 100%; max-height: 100%; width: 100%; } #refresh_metadata_button { font-size: 11px; } @media screen and (max-width: 800px) { #content_body { /* When flexing, it tries to contain itself entirely in the screen, forcing #left and #right to squish together. */ flex: none; flex-direction: column-reverse; } #left { /* Display: None will be overridden as soon as the page detects that the screen is in narrow mode and turns off the tag box's autofocus */ display: none; width: initial; max-width: none; margin-top: 8px; } #right { flex: none; height: calc(100% - 20px); } #editor_holder { display: flex; flex-direction: row; max-width: none; } #message_area { flex: 2; height: initial; max-height: none; } } </style> </head> <body> {{header.make_header(session=session)}} <div id="content_body"> <div id="left"> <div id="editor_holder"> <div id="editor_area"> <!-- TAG INFO --> <h4>Tags</h4> <ul id="this_tags"> <li> <input id="add_tag_textbox" type="text" autofocus> <button id="add_tag_button" class="add_tag_button" onclick="submit_tag(receive_callback);">add</button> </li> {% set tags = photo.sorted_tags() %} {% for tag in tags %} <li> <a class="tag_object" href="/search?tag_musts={{tag.name}}">{{tag.qualified_name()}}</a><!-- --><button class="remove_tag_button" onclick="remove_photo_tag('{{photo.id}}', '{{tag.name}}', receive_callback);"> </button> </li> {% endfor %} </ul> <!-- METADATA & DOWNLOAD --> <h4> File info <button id="refresh_metadata_button" class="add_tag_button" onclick="refresh_metadata('{{photo.id}}');">refresh</button> </h4> <ul id="metadata"> {% if photo.author_id %} {% set author = photo.author() %} <li>Author: <a href="/user/{{author.username}}">{{author.username}}</a></li> {% endif %} {% if photo.width %} <li>Dimensions: {{photo.width}}x{{photo.height}} px</li> <li>Aspect ratio: {{photo.ratio}}</li> {% endif %} <li>Size: {{photo.bytestring()}}</li> {% if photo.duration %} <li>Duration: {{photo.duration_string}}</li> {% endif %} <li><a href="/file/{{photo.id}}{{photo.dot_extension}}?download=1">Download as {{photo.id}}.{{photo.extension}}</a></li> <li><a href="/file/{{photo.id}}{{photo.dot_extension}}?download=1&original_filename=1">Download as "{{photo.basename}}"</a></li> </ul> <!-- CONTAINING ALBUMS --> {% set albums = photo.albums() %} {% if albums %} <h4>Albums containing this photo</h4> <ul id="containing albums"> {% for album in albums %} <li><a href="/album/{{album.id}}">{{album.title}}</a></li> {% endfor %} {% endif %} </ul> </div> <div id="message_area"> </div> </div> </div> <div id="right"> <!-- THE PHOTO ITSELF --> <div class="photo_viewer"> {% if photo.simple_mimetype == "image" %} <div id="photo_img_holder"> <img id="photo_img" src="{{file_link}}" alt="{{photo.basename}}" onclick="toggle_hoverzoom()" onload="this.style.opacity=0.99" > </div> {% elif photo.simple_mimetype == "video" %} <video src="{{file_link}}" controls preload=none {%if photo.thumbnail%}poster="/thumbnail/{{photo.id}}.jpg"{%endif%}></video> {% elif photo.simple_mimetype == "audio" %} <audio src="{{file_link}}" controls></audio> {% else %} <a href="{{file_link}}">View {{filename}}</a> {% endif %} </div> </div> </div> </body> <script type="text/javascript"> var content_body = document.getElementById('content_body'); var add_tag_box = document.getElementById('add_tag_textbox'); var add_tag_button = document.getElementById('add_tag_button'); var message_area = document.getElementById('message_area'); add_tag_box.onkeydown = function(){entry_with_history_hook(add_tag_box, add_tag_button)}; function add_photo_tag(photoid, tagname, callback) { if (tagname === ""){return} var url = "/photo/" + photoid + "/add_tag"; var data = new FormData(); data.append("tagname", tagname); return post(url, data, callback); } function remove_photo_tag(photoid, tagname, callback) { if (tagname === ""){return} var url = "/photo/" + photoid + "/remove_tag"; var data = new FormData(); data.append("tagname", tagname); return post(url, data, callback); } function submit_tag(callback) { add_photo_tag('{{photo.id}}', add_tag_box.value, callback); add_tag_box.value = ""; } function receive_callback(response) { var message_text; var message_positivity; var tagname = response["tagname"]; if ("error_type" in response) { message_positivity = "message_negative"; message_text = response["error_message"]; } else { var action; message_positivity = "message_positive"; if (response["_request_url"].includes("add_tag")) { message_text = "Added tag " + tagname; } else if (response["_request_url"].includes("remove_tag")) { message_text = "Removed tag " + tagname; } else { return; } } create_message_bubble(message_area, message_positivity, message_text, 8000); } function refresh_metadata(photoid) { var url= "/photo/" + photoid + "/refresh_metadata"; var data = new FormData(); post(url, data); setTimeout(function(){location.reload();}, 2000); } function enable_hoverzoom() { console.log("enable"); div = document.getElementById("photo_img_holder"); img = document.getElementById("photo_img"); if (img.naturalWidth < div.offsetWidth && img.naturalHeight < div.offsetHeight) { return; } img.style.opacity = 0; img.style.display = "none"; div.style.cursor = "zoom-out"; div.style.backgroundImage = "url('{{file_link}}')"; div.onmousemove = move_hoverzoom; setTimeout(function(){div.onclick = disable_hoverzoom;}, 100); return true; } function disable_hoverzoom() { console.log("disable"); div = document.getElementById("photo_img_holder"); img = document.getElementById("photo_img"); img.style.opacity = 100; div.style.cursor = ""; img.style.display=""; div.style.backgroundImage = "none"; div.onmousemove = null; div.onclick = null; if (getComputedStyle(content_body).flexDirection != "column-reverse") { add_tag_box.focus(); } } function toggle_hoverzoom() { img = document.getElementById("photo_img"); if (img.style.opacity === "0") { disable_hoverzoom(); } else { enable_hoverzoom(); } } photo_img_holder = document.getElementById("photo_img_holder"); photo_img = document.getElementById("photo_img"); function move_hoverzoom(event) { var x; var y; // Adding 5% to perceived position gives us a bit of padding around the image, // so you don't need to navigate a 1px line to see the edge. // We first subtract half of the image dimensions so that the 5% is applied // to both left and right. Otherwise 105% of 0 is still 0 which doesn't // apply padding on the left. var mouse_x = event.offsetX; mouse_x -= (photo_img_holder.offsetWidth / 2); mouse_x *= 1.05; mouse_x += (photo_img_holder.offsetWidth / 2); var mouse_y = event.offsetY; mouse_y -= (photo_img_holder.offsetHeight / 2); mouse_y *= 1.05; mouse_y += (photo_img_holder.offsetHeight / 2); if (photo_img.naturalWidth < photo_img_holder.offsetWidth) { // If the image is smaller than the frame, just center it x = (photo_img.naturalWidth - photo_img_holder.offsetWidth) / 2; } else { // Take the amount of movement necessary (frame width - image width) // times our distance across the image as a percentage. x = (photo_img.naturalWidth - photo_img_holder.offsetWidth) * (mouse_x / photo_img_holder.offsetWidth); } if (photo_img.naturalHeight < photo_img_holder.offsetHeight) { y = (photo_img.naturalHeight - photo_img_holder.offsetHeight) / 2; } else { y = (photo_img.naturalHeight - photo_img_holder.offsetHeight) * (mouse_y / photo_img_holder.offsetHeight); } //console.log(x); photo_img_holder.style.backgroundPosition=(-x)+"px "+(-y)+"px"; } setTimeout( /* When the screen is in column mode, the autofocusing of the tag box snaps the screen down to it, which is annoying. By starting the #left hidden, we have an opportunity to unset the autofocus before showing it. */ function() { var left = document.getElementById("left"); if (getComputedStyle(content_body).flexDirection == "column-reverse") { add_tag_box.autofocus = false; } left.style.display = "flex"; }, 0 ); </script> </html>