commit 1706852291e1d17fd99f6451034d41324f5fe4f7 Author: Stuart Longland Date: Sun Mar 25 13:40:02 2018 +1000 Port ClearSilver templates to Tornado. This is a first stab, and yes, things are *UGLY*, particularly the JavaScript, which was written almost 10 years ago. As such, it pre-dates versions of IE that play nice with web standards, Promises and lots of other advancements. My knowledge of JavaScript has also greatly improved since then. :-) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8edfd8e --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Vim swapfiles +*.swp +.*.swp + +# Backup files +*~ + +# Python compiled files +*.pyc +*.pyo +__pycache__ + +# setuptools/distutils related +build +dist diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d3f871c --- /dev/null +++ b/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2018, Stuart Longland +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/templates/gallery.thtml b/templates/gallery.thtml new file mode 100644 index 0000000..d4a2d43 --- /dev/null +++ b/templates/gallery.thtml @@ -0,0 +1,45 @@ +{% extends "master.thtml" %} +{# vim: set ts=8 noet sw=8 syn=html fileencoding=utf-8: #} +{% block html_head %} + + Gallery: {{gallery_title}} +{% end %} +{% block html_body %} + + + + + + + + +
Index
+

{{gallery_title}}

+

{{gallery_desc}}

+
+ +

+ {% if photos %} + {% for p in photos %} + {% set hw = p.thumbwidth / 2 %} + {% set hh = p.thumbheight / 2 %} + {% set xpad = 60 - hw %} + {% set ypad = 60 - hh %} + {{p.annotation}} + {% end %} + {% end %} +

+{% end %} diff --git a/templates/generator.thtml b/templates/generator.thtml new file mode 100644 index 0000000..444bb4f --- /dev/null +++ b/templates/generator.thtml @@ -0,0 +1,125 @@ +{% extends "master.thtml" %} +{# vim: set ts=8 noet sw=8 syn=html fileencoding=utf-8: #} +{% block html_head %} + + Image: {{photo.annotation}} ?> ({{photo.name}}) + + + +{% end %} + +{% block html_body %} +
+
+
+ + +

+ Photo gallery images are being generated. Click the left photo + to view the last resized image. +

+{% end %} + +{% block html_body_args %}onload="main();"'{% end %} diff --git a/templates/images/back.png b/templates/images/back.png new file mode 100644 index 0000000..60caccf Binary files /dev/null and b/templates/images/back.png differ diff --git a/templates/images/configure.png b/templates/images/configure.png new file mode 100644 index 0000000..1141564 Binary files /dev/null and b/templates/images/configure.png differ diff --git a/templates/images/finish.png b/templates/images/finish.png new file mode 100644 index 0000000..5b39fa9 Binary files /dev/null and b/templates/images/finish.png differ diff --git a/templates/images/forward.png b/templates/images/forward.png new file mode 100644 index 0000000..d3e6d1e Binary files /dev/null and b/templates/images/forward.png differ diff --git a/templates/images/start.png b/templates/images/start.png new file mode 100644 index 0000000..2a575fd Binary files /dev/null and b/templates/images/start.png differ diff --git a/templates/images/top.png b/templates/images/top.png new file mode 100644 index 0000000..9978728 Binary files /dev/null and b/templates/images/top.png differ diff --git a/templates/images/up.png b/templates/images/up.png new file mode 100644 index 0000000..a5b0944 Binary files /dev/null and b/templates/images/up.png differ diff --git a/templates/index.thtml b/templates/index.thtml new file mode 100644 index 0000000..a1e4adf --- /dev/null +++ b/templates/index.thtml @@ -0,0 +1,19 @@ +{% extends "master.thtml" %} +{# vim: set ts=8 noet sw=8 syn=html fileencoding=utf-8: #} +{% block html_head %} + {{site_name}} +{% end %} +{% block html_body %} +

{{site_name}}

+ + {% if galleries %} + {% for g in galleries %} +
+

{{g.title}}

+

{{g.desc}}

+
+
+ {% end %} + {% end %} +{% end %} diff --git a/templates/lib.js b/templates/lib.js new file mode 100644 index 0000000..a1167e8 --- /dev/null +++ b/templates/lib.js @@ -0,0 +1,208 @@ +function getXHR() { + var httpRequest; + if (window.XMLHttpRequest) { // Mozilla, Safari, ... + httpRequest = new XMLHttpRequest(); + } else if (window.ActiveXObject) { // IE + httpRequest = new ActiveXObject("Microsoft.XMLHTTP"); + } + return httpRequest; +} + +function fetchImage( width, height, rotation ) { + data = getData(); + xhr = getXHR(); + photo_obj = document.getElementById( 'photoimg' ); + + xhr.onreadystatechange = function() { + if ( xhr.readyState == 4) { + document.scroll_en = true; + if ( xhr.status == 200 ) { + eval( 'data=' + xhr.responseText ); + photo_obj.src = + data.uri + '/' + data.photo.resized; + document.data = data; + } + } + showPopupFor(3000, '

Image Loaded' + +'

' + +'The image has been successfully retrieved.

'); + document.scroll_en = true; + }; + + /* Cancel any existing timers */ + if ( document.zoom_timer ) + window.clearTimeout( document.zoom_timer ); + + /* Set a timer to fetch this data after a 3 second delay */ + url = document.location.protocol + "//" + + document.location.hostname + + document.location.pathname + + '?width=' + width + + '&height=' + height + + '&quality=' + data.settings.quality + + '&rotation=' + rotation + + '&json=1'; + + document.zoom_timer = window.setTimeout( function() { + document.scroll_en = false; + document.zoom_timer = false; + document.scroll_en = false; + showPopup('

Loading Image' + +'

' + +'The requested image is being generated...' + +'Please Wait.

'); + xhr.open('GET', url ); + xhr.send(null); + }, 3000 ); +} + +function setZoom( zoom ) { + data = getData(); + + /* Round zoom to 1% */ + zoom = Math.round( zoom*100 )/100; + + document.zoom = zoom; + width = Math.round(data.photo.origwidth*zoom); + height = Math.round(data.photo.origheight*zoom); + + document.getElementById( 'width' ).value = width; + document.getElementById( 'height' ).value = height; + + photo_obj = document.getElementById( 'photoimg' ); + if ( photo_obj ) { + photo_obj.width = width; + photo_obj.height = height; + + /* If the size is bigger than our present image, request a + * bigger one from the server. */ + if ( ( width > data.photo.width ) || + ( height > data.photo.height ) ) { + fetchImage( width, height, data.settings.rotation ); + } + } + showPopupFor(3000,'

Zoom Image' + +'

Zoom photo to '+zoom + +'x magnification.
' + +'Adjust using your mouse\'s scroll wheel then ' + +'wait a moment to see the result.

'); +} + +function resetZoom() { + data = getData(); + if ( document.scroll_en ) + setZoom( document.defaultZoom ); +} + +function adjustZoom( amount ) { + data = getData(); + if ( document.zoom == null ) + document.zoom = data.photo.zoom; + if ( document.scroll_en ) + setZoom( document.zoom + amount ); +} + +function showPopup(body) { + if ( document.popupDiv ) + div = document.popupDiv; + else { + div = document.popupDiv + = document.createElement('div'); + + div.style.position='absolute'; + div.style.right='0px'; + div.style.top='0px'; + div.style.width='30em'; + div.style.height='100px'; + div.style.backgroundColor='#ccc'; + div.style.color='black'; + div.style.borderStyle='dotted'; + div.style.borderColor='black'; + div.style.borderWidth='2px'; + div.style.visibility='hidden'; + document.body.appendChild( div ); + } + div.innerHTML = body; + div.style.visibility='visible'; +} + +function showPopupFor(duration, body) { + showPopup( body ); + if ( document.popup_timer ) + window.clearTimeout( document.popup_timer ); + + document.popup_timer = window.setTimeout( function() { + hidePopup(); + }, duration); +} + +function hidePopup() { + document.popupDiv.style.visibility='hidden'; +} + +function setRotation( angle ) { + data = getData(); + + /* Display a preview */ + preview = document.location.protocol + "//" + + document.location.hostname + + data.CGI.ScriptName + + '/.rotate_preview' + + '?gallery=' + data.gallery.name + + '&photo=' + data.photo.name + + '&rotation=' + angle; + + if ( preview == document.rotationPreview ) + return; + + showPopup('preview' + +'

Rotate Photo

' + +'

Rotate photo by '+angle + +' degrees.
' + +'Adjust using your mouse\'s scroll wheel then ' + +'wait a moment to see the result.

'); + + /* Schedule actual image fetch */ + fetchImage( data.photo.width, data.photo.height, angle ); + rotatefield = document.getElementById( 'rotate' ); + if ( rotatefield ) { + rotatefield.value = angle; + } + document.rotationPreview = preview; + document.rotation = angle; +} + +function adjustRotation(amount) { + data = getData(); + setRotation( parseFloat(document.rotation) + amount ); +} + +function wheelHandler( delta ) { + pan=Math.round(document.getElementById('wheelPan').value); + zoom=Math.round(document.getElementById('wheelZoom').value)/100; + angle=parseFloat(document.getElementById('wheelRotate').value); + + if ( document.getElementById('wheelActionZoom').checked ) + if ( document.scroll_en ) + adjustZoom( delta * zoom ); + if ( document.getElementById('wheelActionHPan').checked ) + window.scrollBy( -delta*pan, 0 ); + if ( document.getElementById('wheelActionVPan').checked ) + window.scrollBy( 0, -delta*pan ); + + if ( document.getElementById('wheelActionRotate').checked ) + if ( document.scroll_en ) + adjustRotation( -delta*angle ); +} +document.scroll_en = true; + +function toggleadj() { + if ( document.adjpanel ) { + document.getElementById('controls').appendChild(document.adjpanel); + delete( document.adjpanel ); + } else { + document.adjpanel = document.getElementById('adjpanel'); + document.getElementById('controls').deleteRow(2); + } +} diff --git a/templates/master.thtml b/templates/master.thtml new file mode 100644 index 0000000..5d84e82 --- /dev/null +++ b/templates/master.thtml @@ -0,0 +1,13 @@ + +{# vim: set ts=8 noet sw=8 syn=html fileencoding=utf-8: #} + + + + + {% block html_head %}{% end %} + + + {% block html_body %}{% end %} + + diff --git a/templates/photo.thtml b/templates/photo.thtml new file mode 100644 index 0000000..0b63009 --- /dev/null +++ b/templates/photo.thtml @@ -0,0 +1,162 @@ +{% extends "master.thtml" %} +{% from json import dumps %} +{# vim: set ts=8 noet sw=8 syn=html fileencoding=utf-8: #} +{% block html_head %} + + Image: {{photo.annotation}} ({{photo.name}}) + + + +{% end %} +{% block html_body %} + + + + + + + + + + + + + + + + +
AlbumAdjustIndex
+ {{photo.annotation}} ({{photo.name}}) +
+
+ + Resize: x + + Rotation: + + Quality: + (100% = PNG) + +
+ + Zoom: + [-0.1] + [-0.01] + [1.0] + [+0.01] + [+0.1] + [reset]
+ + Mouse wheel action: + + + by % + or + + + + + by pixels + + or + + + by degrees +
+
+

{{photo.annotation}}

+ +
+ {{photo.description}} +
+{% end %} + +{% block html_body_args %}onload="toggleadj();"{% end %} diff --git a/templates/style.css b/templates/style.css new file mode 100644 index 0000000..1defb15 --- /dev/null +++ b/templates/style.css @@ -0,0 +1,86 @@ +@media screen { +body { + margin: 10px; + background-color: #333; + color: white; +} + +.controls { + position: fixed; + background-color: #333; + left: 0px; + right: 0px; + top: 0px; +} + +.button { + display: block; + text-align: center; + background-color: #333; + border: 1px solid white; + color: white; + padding: 0.5em; + text-decoration: none; + font-size: large; +} + +.button:hover { + background-color: #666; + color: #fc9; +} + +td.firstlink, td.prevlink, td.nextlink, td.lastlink { + width: 10em; +} + +} + +a { + text-decoration: none; + color: #c96; +} + +a:hover { + color: #ffc; +} + +@media print { + +.controls { + visibility: hidden; + position: fixed; + height: 0px; + width: 0px; + left: 0px; + top: 0px; +} + +} + +.thumbnail { + border: 2px solid #ccc; +} + +.thumbnail:hover { + border: 2px solid #fec; +} + +.status { + text-align: center; +} + +li { + padding-top: 0.5em; + padding-bottom: 0.5em; +} + +.popuptitle { + text-align: center; + font-size: large; + height: 20px; +} + +.popupbody { + text-align: center; + height: 80px; +} diff --git a/templates/wheellib.js b/templates/wheellib.js new file mode 100644 index 0000000..d568b89 --- /dev/null +++ b/templates/wheellib.js @@ -0,0 +1,25 @@ +/* Source: http://adomas.org/javascript-mouse-wheel/ */ +function wheel(event){ + var delta = 0; + if (!event) /* For IE. */ + event = window.event; + if (event.wheelDelta) { /* IE/Opera. */ + delta = event.wheelDelta/120; + if (window.opera) + delta = -delta; + } else if (event.detail) { /** Mozilla case. */ + delta = -event.detail/3; + } + if (delta) + wheelHandler(delta); + if (event.preventDefault) + event.preventDefault(); + event.returnValue = false; +} + +if (window.addEventListener) + /** DOMMouseScroll is for mozilla. */ + window.addEventListener('DOMMouseScroll', wheel, false); +else + /** IE/Opera. */ + window.onmousewheel = document.onmousewheel = wheel;