0001"""
0002Asset Tag Helpers
0003
0004Provides functionality for linking an HTML page together with other assets, such as
0005images, javascripts, stylesheets, and feeds.
0006"""
0007
0008
0009import os
0010import re
0011import urlparse
0012import warnings
0013from tags import *
0014from routes import request_config
0015
0016
0017javascript_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
0018 'javascripts')
0019
0020
0021
0022javascript_builtins = ('prototype.js', 'scriptaculous.js')
0023
0024def auto_discovery_link_tag(source, type='rss', **kwargs):
0025 """
0026 Returns a link tag allowing browsers and news readers (that support it) to auto-detect
0027 an RSS or ATOM feed for current page.
0028
0029 ``source``
0030 The URL of the feed. The URL is ultimately prepended with the environment's
0031 ``SCRIPT_NAME`` (the root path of the web application), unless the URL is
0032 fully-fledged (e.g. http://example.com).
0033
0034 ``type``
0035 The type of feed. Specifying 'rss' or 'atom' automatically translates to a type of
0036 'application/rss+xml' or 'application/atom+xml', respectively. Otherwise the type
0037 is used as specified. Defaults to 'rss'.
0038
0039 Examples::
0040
0041 >>> auto_discovery_link_tag('http://feed.com/feed.xml')
0042 '<link href="http://feed.com/feed.xml" rel="alternate" title="RSS" type="application/rss+xml" />'
0043
0044 >>> auto_discovery_link_tag('http://feed.com/feed.xml', type='atom')
0045 '<link href="http://feed.com/feed.xml" rel="alternate" title="ATOM" type="application/atom+xml" />'
0046
0047 >>> auto_discovery_link_tag('app.rss', type='atom', title='atom feed')
0048 '<link href="app.rss" rel="alternate" title="atom feed" type="application/atom+xml" />'
0049
0050 >>> auto_discovery_link_tag('/app.html', type='text/html')
0051 '<link href="/app.html" rel="alternate" title="" type="text/html" />'
0052 """
0053 title = ''
0054 if type.lower() in ('rss', 'atom'):
0055 title = type.upper()
0056 type = 'application/%s+xml' % type.lower()
0057
0058 tag_args = dict(rel='alternate', type=type, title=title,
0059 href=compute_public_path(source))
0060 kwargs.pop('href', None)
0061 kwargs.pop('type', None)
0062 tag_args.update(kwargs)
0063 return tag('link', **tag_args)
0064
0065def image_tag(source, alt=None, size=None, **options):
0066 """
0067 Returns an image tag for the specified ``source``.
0068
0069 ``source``
0070 The source URL of the image. The URL is prepended with '/images/', unless its full
0071 path is specified. The URL is ultimately prepended with the environment's
0072 ``SCRIPT_NAME`` (the root path of the web application), unless the URL is
0073 fully-fledged (e.g. http://example.com).
0074
0075 ``alt``
0076 The img's alt tag. Defaults to the source's filename, title cased.
0077
0078 ``size``
0079 The img's size, specified in the format "XxY". "30x45" becomes
0080 width="30", height="45". "x20" becomes height="20".
0081
0082 Examples::
0083
0084 >>> image_tag('xml.png')
0085 '<img alt="Xml" src="/images/xml.png" />'
0086
0087 >>> image_tag('rss.png', 'rss syndication')
0088 '<img alt="rss syndication" src="/images/rss.png" />'
0089
0090 >>> image_tag("icon.png", size="16x10", alt="Edit Entry")
0091 '<img alt="Edit Entry" height="10" src="/images/icon.png" width="16" />'
0092
0093 >>> image_tag("/icons/icon.gif", size="16x16")
0094 '<img alt="Icon" height="16" src="/icons/icon.gif" width="16" />'
0095
0096 >>> image_tag("/icons/icon.gif", size="16x")
0097 '<img alt="Icon" src="/icons/icon.gif" width="16" />'
0098 """
0099 if not os.path.splitext(source)[1]:
0100 warnings.warn("You've called image_tag with a source that doesn't include an "
0101 "extension. Soon image_tag will no longer automatically append "
0102 "'.png' to your source. Please call image_path('%s.png') "
0103 "instead." % source, DeprecationWarning, 2)
0104 options['src'] = compute_public_path(source, 'images', 'png')
0105
0106 if not alt:
0107 alt = os.path.splitext(os.path.basename(source))[0].title()
0108 options['alt'] = alt
0109
0110 if size and re.match('^(\d+|)x(\d+|)$', size) and size != 'x':
0111 width, height = size.split('x')
0112 if width:
0113 options['width'] = width
0114 if height:
0115 options['height'] = height
0116
0117 return tag('img', **options)
0118
0119def javascript_include_tag(*sources, **options):
0120 """
0121 Returns script include tags for the specified javascript ``sources``.
0122
0123 Each source's URL path is prepended with '/javascripts/' unless their full path is
0124 specified. Each source's URL path is ultimately prepended with the environment's
0125 ``SCRIPT_NAME`` (the root path of the web application), unless the URL path is a
0126 full-fledged URL (e.g. http://example.com). Sources with no filename extension will be
0127 appended with the '.js' extension.
0128
0129 Optionally includes (prepended) WebHelpers' built-in javascripts when passed the
0130 ``builtins=True`` keyword argument.
0131
0132 Specify the keyword argument ``defer=True`` to enable the script defer attribute.
0133
0134 Examples::
0135
0136 >>> print javascript_include_tag(builtins=True)
0137 <script src="/javascripts/prototype.js" type="text/javascript"></script>
0138 <script src="/javascripts/scriptaculous.js" type="text/javascript"></script>
0139
0140 >>> print javascript_include_tag(builtins=True, defer=True)
0141 <script defer="defer" src="/javascripts/prototype.js" type="text/javascript"></script>
0142 <script defer="defer" src="/javascripts/scriptaculous.js" type="text/javascript"></script>
0143
0144 >>> print javascript_include_tag('prototype', '/other-javascripts/util.js')
0145 <script src="/javascripts/prototype.js" type="text/javascript"></script>
0146 <script src="/other-javascripts/util.js" type="text/javascript"></script>
0147
0148 >>> print javascript_include_tag('app', '/test/test.1.js', builtins=True)
0149 <script src="/javascripts/prototype.js" type="text/javascript"></script>
0150 <script src="/javascripts/scriptaculous.js" type="text/javascript"></script>
0151 <script src="/javascripts/app.js" type="text/javascript"></script>
0152 <script src="/test/test.1.js" type="text/javascript"></script>
0153 """
0154 if options.pop('builtins', False):
0155 sources = javascript_builtins + sources
0156 if options.get('defer') == True:
0157 options['defer'] = 'defer'
0158
0159 tags = []
0160 for source in sources:
0161 content_options = dict(type='text/javascript',
0162 src=compute_public_path(source, 'javascripts',
0163 'js'))
0164 content_options.update(options)
0165 tags.append(content_tag('script', None, **content_options))
0166 return '\n'.join(tags)
0167
0168def stylesheet_link_tag(*sources, **options):
0169 """
0170 Returns CSS link tags for the specified stylesheet ``sources``.
0171
0172 Each source's URL path is prepended with '/stylesheets/' unless their full path is
0173 specified. Each source's URL path is ultimately prepended with the environment's
0174 ``SCRIPT_NAME`` (the root path of the web application), unless the URL path is a
0175 full-fledged URL (e.g. http://example.com). Sources with no filename extension will be
0176 appended with the '.css' extension.
0177
0178 Examples::
0179
0180 >>> stylesheet_link_tag('style')
0181 '<link href="/stylesheets/style.css" media="screen" rel="Stylesheet" type="text/css" />'
0182
0183 >>> stylesheet_link_tag('dir/file', media='all')
0184 '<link href="/stylesheets/dir/file.css" media="all" rel="Stylesheet" type="text/css" />'
0185
0186 >>> stylesheet_link_tag('/dir/file', media='all')
0187 '<link href="/dir/file.css" media="all" rel="Stylesheet" type="text/css" />'
0188 """
0189 tag_options = dict(rel='Stylesheet', type='text/css', media='screen')
0190 tag_options.update(options)
0191 tag_options.pop('href', None)
0192
0193 tags = [tag('link', **dict(href=compute_public_path(source, 'stylesheets', 'css'),
0194 **tag_options)) for source in sources]
0195 return '\n'.join(tags)
0196
0197def compute_public_path(source, root_path=None, ext=None):
0198 """
0199 Format the specified source for publishing, via the public directory, if applicable.
0200 """
0201 if ext and not os.path.splitext(os.path.basename(source))[1]:
0202 source = '%s.%s' % (source, ext)
0203
0204
0205 parsed = urlparse.urlparse(source)
0206 if not (parsed[0] and (parsed[1] or parsed[2])):
0207
0208 if not root_path or source.startswith('/'):
0209 source = '%s%s' % (get_script_name(), source)
0210 else:
0211 source = '%s/%s/%s' % (get_script_name(), root_path, source)
0212 return source
0213
0214def get_script_name():
0215 """
0216 Determine the current web application's ``SCRIPT_NAME``.
0217 """
0218 script_name = ''
0219 config = request_config()
0220 if hasattr(config, 'environ'):
0221 script_name = config.environ.get('SCRIPT_NAME', '')
0222 return script_name
0223
0224__all__ = ['javascript_path', 'javascript_builtins', 'auto_discovery_link_tag',
0225 'image_tag', 'javascript_include_tag', 'stylesheet_link_tag']