wcs/wcs/qommon/template.ptl

443 lines
15 KiB
Plaintext

# w.c.s. - web application for online forms
# Copyright (C) 2005-2010 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
from cStringIO import StringIO
import os
import glob
try:
import elementtree.ElementTree as ET
except ImportError:
try:
import xml.etree.ElementTree as ET
except ImportError:
ET = None
from quixote import get_session, get_request, get_response, get_publisher
from quixote.directory import Directory
from quixote.util import StaticDirectory, StaticFile
from quixote.html import htmltext, htmlescape
import errors
import ezt
def get_theme_directory(theme_id):
system_location = os.path.join(get_publisher().data_dir, 'themes', theme_id)
local_location = os.path.join(get_publisher().app_dir, 'themes', theme_id)
if os.path.exists(local_location):
location = local_location
elif os.path.exists(system_location):
location = system_location
else:
return None
while os.path.islink(location):
location = os.path.join(os.path.dirname(location), os.readlink(location))
if not os.path.exists(location):
return None
return location
class ThemesDirectory(Directory):
def _q_lookup(self, name):
if name in ('.', '..'):
raise errors.TraversalError()
location = get_theme_directory(name)
if location is None:
raise errors.TraversalError()
if os.path.isdir(location):
return StaticDirectory(location)
else:
return StaticFile(location)
def get_themes_dict():
system_location = os.path.join(get_publisher().data_dir, 'themes')
local_location = os.path.join(get_publisher().app_dir, 'themes')
themes = {}
for theme_xml in glob.glob(os.path.join(system_location, '*/desc.xml')) + \
glob.glob(os.path.join(local_location, '*/desc.xml')):
theme_dict = get_theme_dict(theme_xml)
if not theme_dict:
continue
themes[theme_dict.get('name')] = theme_dict
return themes
def get_theme_dict(theme_xml):
try:
tree = ET.parse(theme_xml).getroot()
except: # parse error
return None
name = tree.attrib['name']
label = tree.findtext('label')
desc = tree.findtext('desc')
author = tree.findtext('author')
icon = os.path.join(os.path.dirname(theme_xml), 'icon.png')
if not os.path.exists(icon):
icon = None
theme = {'name': name, 'label': label, 'desc': desc, 'author': author, 'icon': icon}
theme['keywords'] = []
for keyword in tree.findall('keywords/keyword'):
theme['keywords'].append(keyword.text)
return theme
def get_themes():
# backward compatibility function, it returns a tuple with theme info,
# newer code should use get_themes_dict()
themes = {}
for k, v in get_themes_dict().items():
themes[k] = (v['label'], v['desc'], v['author'], v['icon'])
return themes
def get_current_theme():
from publisher import get_cfg
current_theme = get_cfg('branding', {}).get('theme', 'default')
system_location = os.path.join(get_publisher().data_dir, 'themes', current_theme)
local_location = os.path.join(get_publisher().app_dir, 'themes', current_theme)
for location in (local_location, system_location):
if os.path.exists(location):
return get_theme_dict(os.path.join(location, 'desc.xml'))
default_theme_location = os.path.join(get_publisher().data_dir, 'themes', 'default')
return get_theme_dict(os.path.join(default_theme_location, 'desc.xml'))
DEFAULT_TEMPLATE_EZT = """<!DOCTYPE html>
<html lang="[site_lang]">
<head>
<title>[page_title]</title>
<link rel="stylesheet" type="text/css" href="[css]"/>
[script]
</head>
<body[if-any onload] onload="[onload]"[end]>
<div id="page">
<div id="top"> <h1>[if-any title][title][else][site_name][end]</h1> </div>
<div id="main-content">
[prelude]
[if-any breadcrumb]<p id="breadcrumb">[breadcrumb]</p>[end]
[body]
</div>
<div id="footer">[if-any footer][footer][end]</div>
</div>
</body>
</html>"""
DEFAULT_IFRAME_EZT = """<!DOCTYPE html>
<html lang="[site_lang]">
<head>
<title>[page_title]</title>
<link rel="stylesheet" type="text/css" href="[css]"/>
[script]
</head>
<body[if-any onload] onload="[onload]"[end]>
<div id="main-content">
[prelude]
[if-any breadcrumb]<p id="breadcrumb">[breadcrumb]</p>[end]
[body]
</div>
</body>
</html>"""
ADMIN_TEMPLATE_EZT = """<!DOCTYPE html>
<html lang="[site_lang]">
<head>
<title>[page_title]</title>
<link rel="stylesheet" type="text/css" href="[css]"/>
[if-any extra_css]
<link rel="stylesheet" type="text/css" href="[extra_css]"/>
[end]
[script]
</head>
<body>
<div id="top">
[user_info]
</div>
<div id="main">
<div id="header">
<h1>[site_name]</h1>
<div id="main-menu">[header_menu]</div>
</div>
<div id="main-content">
[if-any breadcrumb]
<p id="breadcrumb">[breadcrumb]</p>
[end]
[body]
</div>
[if-any sidebar]
<div id="sidebar">
[sidebar]
</div>
[end]
[if-any footer]
<div id="footer">
[footer]
</div>
[end]
</div> <!-- #main -->
</body>
</html>"""
default_template = ezt.Template()
default_template.parse(DEFAULT_TEMPLATE_EZT)
default_iframe_template = ezt.Template()
default_iframe_template.parse(DEFAULT_IFRAME_EZT)
admin_template = ezt.Template()
admin_template.parse(ADMIN_TEMPLATE_EZT)
def html_top(title = None, onload = None, script = None, default_org = None,
force_ignore_user = False, scripts = None):
if not hasattr(get_response(), 'filter'):
get_response().filter = {}
if scripts:
if type(script) is list:
script = '\n'.join(
['<script src="%s" type="text/javascript"></script>' % x for x in scripts])
else:
script = scripts
get_response().filter.update(locals())
def error_page [html] (error_message, error_title = None, exception = None, continue_to = None,
location_hint = None):
if not error_title:
error_title = _('Error')
scripts = None
if exception:
root_url = get_publisher().get_root_url()
get_response().add_javascript(['jquery.js', 'interface.js', 'exception.js'])
kwargs = {str('title'): error_title, str('scripts'): scripts}
if location_hint == 'backoffice':
import qommon.backoffice.menu
error_html_top = qommon.backoffice.menu.html_top
kwargs[str('section')] = None
elif location_hint == 'admin':
import qommon.admin.menu
error_html_top = qommon.admin.menu.html_top
kwargs[str('section')] = None
else:
error_html_top = html_top
error_html_top(**kwargs)
'<div class="error-page">'
'<p>%s</p>' % error_message
if exception and get_publisher().logger.error_email:
'<p>%s</p>' % _('It has been sent to the site administrator for analyse.')
if continue_to:
continue_link = '<a href="%s">%s</a>' % continue_to
'<p>%s</p>' % _('Continue to %s') % continue_link
if exception:
'''<p><a id="display-exception">%s</a></p>''' % _('View Error Details')
'<pre id="exception"><code>%s</code></pre>' % exception
'</div>'
def get_default_ezt_template():
from publisher import get_cfg
current_theme = get_cfg('branding', {}).get('theme', 'default')
filename = os.path.join(get_publisher().app_dir, 'themes',
current_theme, 'template.%s.ezt' % get_publisher().APP_NAME)
if os.path.exists(filename):
return file(filename).read()
filename = os.path.join(get_publisher().data_dir, 'themes',
current_theme, 'template.%s.ezt' % get_publisher().APP_NAME)
if os.path.exists(filename):
return file(filename).read()
filename = os.path.join(get_publisher().app_dir, 'themes', current_theme, 'template.ezt')
if os.path.exists(filename):
return file(filename).read()
filename = os.path.join(get_publisher().data_dir, 'themes', current_theme, 'template.ezt')
if os.path.exists(filename):
return file(filename).read()
return DEFAULT_TEMPLATE_EZT
def decorate(body, response):
from publisher import get_cfg
body = str(body)
if get_request().get_header('x-popup') == 'true':
return '''<div class="popup-content"> %s </div>''' % body
if 'rel="popup"' in body:
response.add_javascript(['jquery.js', 'simplemodal/jquery.simplemodal.js', 'popup.js'])
response.add_css_include('qommon.css')
kwargs = {}
for k, v in response.filter.items():
if v:
kwargs[k] = str(v)
if not kwargs.has_key('lang') and hasattr(get_request(), 'language'):
response.filter['lang'] = get_request().language
onload = kwargs.get('onload')
org_name = get_cfg('sp', {}).get('organization_name',
kwargs.get('default_org', get_publisher().APP_NAME))
site_name = get_cfg('misc', {}).get('sitename', org_name)
current_theme = get_cfg('branding', {}).get('theme', get_publisher().default_theme)
include_user = get_cfg('misc', {}).get('include-user-details', False)
if kwargs.get('title'):
title = kwargs.get('title')
page_title = '%s - %s' % (site_name, title)
title_or_orgname = title
else:
page_title = site_name
title = None
title_or_orgname = site_name
script = kwargs.get('script') or ''
script += response.get_css_includes_for_header()
script += response.get_javascript_for_header()
try:
user = get_request().user
except:
user = None
if type(user) in (int, str) and get_session():
try:
user = get_session().get_user_object()
except KeyError:
pass
root_url = get_publisher().get_application_static_files_root_url()
if response.filter.get('admin_ezt'):
header_menu = kwargs.get('header_menu')
user_info = kwargs.get('user_info')
page_title = kwargs.get('sitetitle') + kwargs.get('title', '')
subtitle = kwargs.get('subtitle')
sidebar = kwargs.get('sidebar')
css = root_url + get_publisher().qommon_static_dir + get_publisher().qommon_admin_css
generate_breadcrumb = True
template = admin_template
app_dir_filename = os.path.join(get_publisher().app_dir, 'themes',
current_theme, 'admin.css')
data_dir_filename = os.path.join(get_publisher().data_dir, 'themes',
current_theme, 'admin.css')
for filename in (app_dir_filename, data_dir_filename):
if os.path.exists(filename):
extra_css = root_url + 'themes/%s/admin.css' % current_theme
break
else:
if current_theme == 'default':
css = root_url + 'css/%s.css' % get_publisher().APP_NAME
else:
css = root_url + 'themes/%s/%s.css' % (current_theme, get_publisher().APP_NAME)
prelude = ''
if include_user and not kwargs.get('force_ignore_user'):
session = get_session()
if session and session.user and not str(session.user).startswith(str('anonymous-')):
try:
user = get_publisher().user_class.get(session.user)
except (KeyError, ValueError):
pass
else:
prelude = '<p id="prelude">%s</p>' % (_('Logged in as %s.') % user.name)
template_ezt = get_cfg('branding', {}).get('template')
if response.page_template_key or not template_ezt:
# the theme can provide a default template
possible_filenames = []
if response.page_template_key:
possible_filenames.append('template.%s.%s.ezt' % (
get_publisher().APP_NAME, response.page_template_key))
possible_filenames.append('template.%s.ezt' % response.page_template_key)
possible_filenames.append('template.%s.ezt' % get_publisher().APP_NAME)
possible_filenames.append('template.ezt')
for fname in possible_filenames:
filename = os.path.join(get_publisher().app_dir, 'themes',
current_theme, fname)
if os.path.exists(filename):
template_ezt = file(filename).read()
break
filename = os.path.join(get_publisher().data_dir, 'themes',
current_theme, fname)
if os.path.exists(filename):
template_ezt = file(filename).read()
break
if template_ezt:
generate_breadcrumb = ('[breadcrumb]' in template_ezt)
template = ezt.Template()
template.parse(template_ezt)
else:
generate_breadcrumb = True
if response.page_template_key == 'iframe':
template = default_iframe_template
else:
template = default_template
if generate_breadcrumb:
breadcrumb = ''
if hasattr(response, 'breadcrumb') and response.breadcrumb:
s = []
path = root_url
total_len = sum([len(str(x[1])) for x in response.breadcrumb if x[1] is not None])
for component, label in response.breadcrumb:
if component.startswith('http:') or component.startswith('https:'):
s.append('<a href="%s">%s</a>' % (component, label))
continue
if label is not None:
if type(label) is str:
label = htmlescape(label)
if total_len > 80 and len(label) > 10 and \
response.breadcrumb[-1] != (component, label):
s.append('<a href="%s%s" title="%s">%s</a>' % (
path, component, label, '...'))
else:
s.append('<a href="%s%s">%s</a>' % (path, component, label))
path += component
breadcrumb = ' > '.join(s)
vars = response.filter.copy()
vars.update(get_publisher().substitutions.get_context_variables())
vars.update(locals())
fd = StringIO()
template.generate(fd, vars)
return fd.getvalue()
def process_template(template_ezt, kwargs):
template = ezt.Template()
template.parse(template_ezt)
fd = StringIO()
template.generate(fd, kwargs)
return htmltext(fd.getvalue())