terom@62: """ terom@62: Templates for HTML output terom@62: """ terom@62: terom@124: import html, version terom@62: from html import tags terom@62: terom@135: import urllib terom@135: terom@135: def quote_path (path) : terom@135: """ terom@135: Return an unicode-safe string with the escaped contents of the given str-able object, suitable for use terom@135: in HTTP URLs. terom@135: terom@135: This should provide correct behaviour for use with filesystem Nodes. terom@135: terom@135: XXX: even this could be abstracted to some kind of "URL" thing terom@135: """ terom@135: terom@135: return urllib.quote(str(path)) terom@135: terom@78: def link_from (source, target) : terom@62: """ terom@135: Returns a partial a tag linking from the given source page to the target page, escaping binary paths. terom@62: """ terom@62: terom@135: return tags.a(href=quote_path(source.path_to(target))) terom@62: terom@78: def image_link (from_page, image, target) : terom@62: """ terom@62: Link to the given image terom@62: """ terom@62: terom@78: return link_from(from_page, target)( terom@135: tags.img(src=quote_path(image.path_from(from_page))) terom@62: ) terom@62: terom@62: def image_page (image) : terom@62: """ terom@62: The per-image view terom@62: """ terom@62: terom@80: return [ terom@136: tags.div(id='image')( terom@62: # title terom@62: tags.h1(image.title) if image.title else None, terom@62: terom@62: # image-links terom@62: tags.p( terom@62: # prev thumb terom@77: image_link(image.html, image.prev.thumb, image.prev.html) if image.prev else None, terom@62: terom@62: # preview terom@77: image_link(image.html, image.preview, image), terom@62: terom@62: # next thumb terom@77: image_link(image.html, image.next.thumb, image.next.html) if image.next else None terom@62: ), terom@62: terom@62: # optional description terom@62: tags.p(image.description) if image.description else None, terom@62: ), terom@62: terom@62: # extended info, metadata terom@136: tags.div(id='info')(*( terom@120: tags.p(("%s: " % name), value) for name, value in image.metadata terom@78: )), terom@80: ] terom@62: terom@62: def folder_link (from_page, folder, page=0) : terom@62: """ terom@62: Returns a link to the given folder from the given page terom@62: """ terom@62: terom@119: return link_from(from_page, folder.html_page(page))(folder.title) terom@62: terom@62: def folder_page_link (folder, page) : terom@62: """ terom@62: Returns a partial a tag from the folder itself to the given page number terom@62: """ terom@62: terom@119: return link_from(folder, folder.html_page(page)) terom@62: terom@62: def folder_paginate (folder, cur_page) : terom@62: """ terom@62: Render the pagination view for a folder, if needed terom@62: """ terom@62: terom@62: if folder.page_count > 1 : terom@62: return tags.div(class_='paginate')( terom@62: tags.ul( terom@62: # prev link terom@62: tags.li(folder_page_link(folder, cur_page - 1)(html.raw("« Prev"))) terom@62: if cur_page > 0 else terom@62: tags.li(tags.span(html.raw("« Prev"))), terom@62: terom@80: (( terom@62: # page link terom@62: tags.li(folder_page_link(folder, page)(page + 1)) terom@62: if page != cur_page else terom@62: tags.li(tags.strong(page + 1)) terom@62: ) for page in xrange(folder.page_count)), terom@62: terom@62: # next link terom@127: tags.li(folder_page_link(folder, cur_page + 1)(html.raw("Next »"))) terom@62: if cur_page < folder.page_count - 1 else terom@127: tags.li(tags.span(html.raw("Next »"))), terom@62: ) terom@62: ) terom@62: terom@62: def folder_page (folder, cur_page) : terom@62: """ terom@62: Render the per-Folder view for the given page terom@62: """ terom@62: terom@62: # render the paginate-view once terom@62: paginate = folder_paginate(folder, cur_page) terom@62: terom@80: return [ terom@62: # title terom@62: tags.h1(folder.title) if folder.title else None, terom@62: terom@62: # subdirs terom@100: tags.div(id='dirs')( terom@62: tags.ul( terom@62: tags.li( terom@62: folder_link(folder, subfolder) terom@62: ) for subfolder in folder.subfolders terom@62: ) if folder.subfolders else None terom@62: ), terom@62: terom@62: # upper paginate terom@62: paginate, terom@62: terom@62: # image thumbnails terom@100: tags.div(id='thumbnails')( terom@100: image_link(folder, image.thumb, image.html) for image in folder.images_for_page(cur_page) terom@100: ), terom@62: terom@62: # lower paginate terom@62: paginate, terom@62: terom@62: # description terom@62: tags.p(id='description')(folder.description) if folder.description else None, terom@62: terom@62: # shorturl terom@80: ] terom@62: terom@119: def breadcrumb_trail (gallery, cur_page) : terom@62: """ terom@62: Yield the breadcrumb elements terom@62: """ terom@62: terom@62: is_first = True terom@62: terom@119: for page in gallery.path_to(cur_page) : terom@62: # spacers terom@62: if is_first : terom@62: is_first = False terom@62: terom@62: else : terom@62: yield html.raw("»") terom@62: terom@62: # link from this page to sub-page terom@119: yield link_from(cur_page, page.html)(page.title) terom@62: terom@62: def breadcrumb (gallery, page) : terom@62: """ terom@62: Build a breadcrumb trail from the gallery root to the given object terom@62: """ terom@62: terom@62: return tags.div(id='breadcrumb')( terom@80: breadcrumb_trail(gallery, page) terom@62: ) terom@62: terom@119: def master (gallery, page, body) : terom@62: """ terom@62: Render the full-page HTML layout for the given page with title and body terom@62: """ terom@62: terom@62: return html.XHTMLDocument( terom@80: head=[ terom@119: tags.title(page.title), terom@62: terom@62: # stylesheet terom@119: tags.link(rel='Stylesheet', type='text/css', href=gallery.stylesheet.path_from(page.html)) terom@80: ], terom@62: terom@80: body=[ terom@62: # top-of-page breadcrumb nav terom@62: breadcrumb(gallery, page), terom@62: terom@62: # other content terom@62: body, terom@62: terom@62: # footer terom@124: tags.p(id='about')( terom@124: "Generated using", terom@124: tags.a(href='http://projects.qmsk.net/degal')('Degal'), terom@124: "version", terom@124: tags.a(href=version.VERSION_URL)(version.VERSION_STRING), terom@124: ) terom@80: ], terom@62: ) terom@62: