diff options
Diffstat (limited to 'nikola')
124 files changed, 5076 insertions, 1727 deletions
diff --git a/nikola/__init__.py b/nikola/__init__.py index 3b6ad2a..94031c9 100644 --- a/nikola/__init__.py +++ b/nikola/__init__.py @@ -1 +1,5 @@ -from nikola import Nikola # NOQA +from __future__ import absolute_import + +from .nikola import Nikola # NOQA +from . import plugins + diff --git a/nikola/data/samplesite/conf.py.in b/nikola/conf.py.in index 8794565..897a941 100755 --- a/nikola/data/samplesite/conf.py.in +++ b/nikola/conf.py.in @@ -1,10 +1,14 @@ # -*- coding: utf-8 -*- - +<%text> +# -*- coding: utf-8 -*- +from __future__ import unicode_literals import os +import time ######################################## # Configuration, please edit ######################################## +</%text> # Data about this site BLOG_AUTHOR = "${BLOG_AUTHOR}" @@ -47,7 +51,7 @@ post_pages = ${POST_PAGES} # Feel free to add or delete extensions to any list, but don't add any new # compilers unless you write the interface for it yourself. # -# 'rest' is reStructuredTextq +# 'rest' is reStructuredText # 'markdown' is MarkDown # 'html' assumes the file is html and just copies it post_compilers = ${POST_COMPILERS} @@ -120,7 +124,7 @@ SLUG_TAG_PATH = True # # If you don't need any of these, just set to [] -REDIRECTIONS = [] +REDIRECTIONS = ${REDIRECTIONS} # Commands to execute to deploy. Can be anything, for example, # you may use rsync: @@ -135,6 +139,10 @@ DEPLOY_COMMANDS = [] OUTPUT_FOLDER = 'output' +# where the "cache" of partial generated content should be located +# default: 'cache' +CACHE_FOLDER = 'cache' + # Filters to apply to the output. # A directory where the keys are either: a file extensions, or # a tuple of file extensions. @@ -157,9 +165,9 @@ FILTERS = { # ".jpg": ["jpegoptim --strip-all -m75 -v %s"], } -############################################################################## +# ############################################################################# # Image Gallery Options -############################################################################## +# ############################################################################# # Galleries are folders in galleries/ # Final location of galleries will be output / GALLERY_PATH / gallery_name @@ -168,9 +176,9 @@ THUMBNAIL_SIZE = 180 MAX_IMAGE_SIZE = 1280 USE_FILENAME_AS_TITLE = True -############################################################################## +# ############################################################################# # HTML fragments and diverse things that are used by the templates -############################################################################## +# ############################################################################# # Data about post-per-page indexes INDEXES_TITLE = "" # If this is empty, the default is BLOG_TITLE @@ -179,6 +187,9 @@ INDEXES_PAGES = "" # If this is empty, the default is 'old posts page %d' trans # Name of the theme to use. Themes are located in themes/theme_name THEME = 'site' +# date format used to display post dates. (str used by datetime.datetime.strftime) +DATE_FORMAT = '%Y-%m-%d %H:%M' + # Show only teasers in the index pages? Defaults to False. # INDEX_TEASERS = False @@ -192,7 +203,10 @@ style="border-width:0; margin-bottom:12px;" src="http://i.creativecommons.org/l/by-nc-sa/2.5/ar/88x31.png"></a>""" # A small copyright notice for the page footer (in HTML) -CONTENT_FOOTER = u'Contents © 2012 <a href="${BLOG_EMAIL}">${BLOG_AUTHOR}</a>' +CONTENT_FOOTER = 'Contents © {date} <a href="mailto:{email}">{author}</a> - Powered by <a href="http://nikola.ralsina.com.ar">Nikola</a>' +CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL, + author=BLOG_AUTHOR, + date=time.gmtime().tm_year) # To enable comments via Disqus, you need to create a forum at # http://disqus.com, and set DISQUS_FORUM to the short name you selected. @@ -221,14 +235,14 @@ SEARCH_FORM = "" # appears on the navigation bar #SEARCH_FORM = """ #<!-- Custom search --> -#<form method="get" id="search" action="http://duckduckgo.com/" """\ -#"""class="navbar-form pull-left"> +#<form method="get" id="search" action="http://duckduckgo.com/" +# class="navbar-form pull-left"> #<input type="hidden" name="sites" value="%s"/> #<input type="hidden" name="k8" value="#444444"/> #<input type="hidden" name="k9" value="#D51920"/> #<input type="hidden" name="kt" value="h"/> -#<input type="text" name="q" maxlength="255" """\ -#"""placeholder="Search…" class="span2" style="margin-top: 4px;"/> +#<input type="text" name="q" maxlength="255" +# placeholder="Search…" class="span2" style="margin-top: 4px;"/> #<input type="submit" value="DuckDuckGo Search" style="visibility: hidden;" /> #</form> #<!-- End of custom search --> @@ -247,6 +261,7 @@ GLOBAL_CONTEXT = { 'blog_title': BLOG_TITLE, 'blog_url': BLOG_URL, 'blog_desc': BLOG_DESCRIPTION, + 'date_format': DATE_FORMAT, 'translations': TRANSLATIONS, 'license': LICENSE, 'search_form': SEARCH_FORM, diff --git a/nikola/console.py b/nikola/console.py new file mode 100644 index 0000000..939b611 --- /dev/null +++ b/nikola/console.py @@ -0,0 +1,7 @@ +from __future__ import print_function, unicode_literals + +from nikola import Nikola +import conf +SITE = Nikola(**conf.__dict__) +SITE.scan_posts() +print("You can now access your configuration as conf and your site engine as SITE") diff --git a/nikola/data/samplesite/README.txt b/nikola/data/samplesite/README.txt index ca94b34..a1220d0 100644 --- a/nikola/data/samplesite/README.txt +++ b/nikola/data/samplesite/README.txt @@ -1,31 +1,20 @@ -How To make This Work ---------------------- +This folder contains the source used to generate a static site by nikola. -The full manual is in stories/manual.txt, but here is the very short version: +Installation and documentation at http://nikola.ralsina.com.ar -1. Install docutils (http://docutils.sourceforge.net) -2. Install Mako (http://makotemplates.org) -3. Install doit (http://python-doit.sourceforge.net) -4. Install PIL (http://www.pythonware.com/products/pil/) -5. Install Pygments (http://pygments.org/) -6. Install unidecode (http://pypi.python.org/pypi/Unidecode/) -7. Install lxml (http://lxml.de/) +Configuration file for the site is `conf.py`. -To build or update the demo site run this command in the nikola's folder:: +To build the site:: - doit + nikola build To see it:: - doit serve -p 8000 + nikola serve And point your browser to http://localhost:8000 -Notes on Requirements ---------------------- -If you don't have PIL, then image galleries will be inefficient because Nikola -will not generate thumbnails. Alternatively, you may install pillow instead of -PIL. +To check all available commands:: -If you don't have pygments, the code-block directive will not highlight syntax. + nikola help diff --git a/nikola/data/samplesite/conf.py b/nikola/data/samplesite/conf.py deleted file mode 100755 index 552eb68..0000000 --- a/nikola/data/samplesite/conf.py +++ /dev/null @@ -1,274 +0,0 @@ -# -*- coding: utf-8 -*- - -import os - -######################################## -# Configuration, please edit -######################################## - -# Data about this site -BLOG_AUTHOR = "Your Name" -BLOG_TITLE = "Demo Site" -BLOG_URL = "http://nikola.ralsina.com.ar" -BLOG_EMAIL = "joe@demo.site" -BLOG_DESCRIPTION = "This is a demo site for Nikola." - -# post_pages contains (wildcard, destination, template, use_in_feed) tuples. -# -# The wildcard is used to generate a list of reSt source files -# (whatever/thing.txt). -# That fragment must have an associated metadata file (whatever/thing.meta), -# and opcionally translated files (example for spanish, with code "es"): -# whatever/thing.txt.es and whatever/thing.meta.es -# -# From those files, a set of HTML fragment files will be generated: -# cache/whatever/thing.html (and maybe cache/whatever/thing.html.es) -# -# These files are combinated with the template to produce rendered -# pages, which will be placed at -# output / TRANSLATIONS[lang] / destination / pagename.html -# -# where "pagename" is specified in the metadata file. -# -# if use_in_feed is True, then those posts will be added to the site's -# rss feeds. -# - -post_pages = ( - ("posts/*.txt", "posts", "post.tmpl", True), - ("stories/*.txt", "stories", "story.tmpl", False), -) - -# One or more folders containing files to be copied as-is into the output. -# The format is a dictionary of "source" "relative destination". -# Default is: -# FILES_FOLDERS = {'files': '' } -# Which means copy 'files' into 'output' - -# A mapping of languages to file-extensions that represent that language. -# Feel free to add or delete extensions to any list, but don't add any new -# compilers unless you write the interface for it yourself. -# -# 'rest' is reStructuredText -# 'markdown' is MarkDown -# 'html' assumes the file is html and just copies it -post_compilers = { - "rest": ('.txt', '.rst'), - "markdown": ('.md', '.mdown', '.markdown'), - "html": ('.html', '.htm') - } - -# Nikola is multilingual! -# -# Currently supported languages are: -# English -> en -# Greek -> gr -# German -> de -# French -> fr -# Russian -> ru -# Spanish -> es -# Italian -> it -# -# If you want to use Nikola with a non-supported language you have to provide -# a module containing the necessary translations -# (p.e. look at the modules at: ./nikola/data/themes/default/messages/fr.py). -# If a specific post is not translated to a language, then the version -# in the default language will be shown instead. - -# What is the default language? -DEFAULT_LANG = "en" - -# What other languages do you have? -# The format is {"translationcode" : "path/to/translation" } -# the path will be used as a prefix for the generated pages location -TRANSLATIONS = { - DEFAULT_LANG: "", - #"gr": "./gr", - #"de": "./de", - #"fr": "./fr", - #"ru": "./ru", - #"es": "./es", - } - -# Paths for different autogenerated bits. These are combined with the -# translation paths. - -# Final locations are: -# output / TRANSLATION[lang] / TAG_PATH / index.html (list of tags) -# output / TRANSLATION[lang] / TAG_PATH / tag.html (list of posts for a tag) -# output / TRANSLATION[lang] / TAG_PATH / tag.xml (RSS feed for a tag) -TAG_PATH = "categories" - -# If TAG_PAGES_ARE_INDEXES is set to True, each tag's page will contain -# the posts themselves. If set to False, it will be just a list of links. -TAG_PAGES_ARE_INDEXES = True - -# Final location is output / TRANSLATION[lang] / INDEX_PATH / index-*.html -INDEX_PATH = "" -# Final locations for the archives are: -# output / TRANSLATION[lang] / ARCHIVE_PATH / ARCHIVE_FILENAME -# output / TRANSLATION[lang] / ARCHIVE_PATH / YEAR / index.html -ARCHIVE_PATH = "" -ARCHIVE_FILENAME = "archive.html" -# Final locations are: -# output / TRANSLATION[lang] / RSS_PATH / rss.xml -RSS_PATH = "" - -# Slug the Tag URL easier for users to type, special characters are -# often removed or replaced as well. -SLUG_TAG_PATH = True - -# A list of redirection tuples, [("foo/from.html", "/bar/to.html")]. -# -# A HTML file will be created in output/foo/from.html that redirects -# to the "/bar/to.html" URL. notice that the "from" side MUST be a -# relative URL. -# -# If you don't need any of these, just set to [] - -REDIRECTIONS = [] - -# Commands to execute to deploy. Can be anything, for example, -# you may use rsync: -# "rsync -rav output/* joe@my.site:/srv/www/site" -# And then do a backup, or ping pingomatic. -# To do manual deployment, set it to [] -DEPLOY_COMMANDS = [] - -# Where the output site should be located -# If you don't use an absolute path, it will be considered as relative -# to the location of conf.py - -OUTPUT_FOLDER = 'output' - -# Filters to apply to the output. -# A directory where the keys are either: a file extensions, or -# a tuple of file extensions. -# -# And the value is a list of commands to be applied in order. -# -# Each command must be either: -# -# A string containing a '%s' which will -# be replaced with a filename. The command *must* produce output -# in place. -# -# Or: -# -# A python callable, which will be called with the filename as -# argument. -# -# By default, there are no filters. -FILTERS = { -# ".jpg": ["jpegoptim --strip-all -m75 -v %s"], -} - -############################################################################## -# Image Gallery Options -############################################################################## - -# Galleries are folders in galleries/ -# Final location of galleries will be output / GALLERY_PATH / gallery_name -GALLERY_PATH = "galleries" -THUMBNAIL_SIZE = 180 -MAX_IMAGE_SIZE = 1280 -USE_FILENAME_AS_TITLE = True - -############################################################################## -# HTML fragments and diverse things that are used by the templates -############################################################################## - -# Data about post-per-page indexes -INDEXES_TITLE = "" # If this is empty, the default is BLOG_TITLE -INDEXES_PAGES = "" # If this is empty, the default is 'old posts page %d' translated - -# Name of the theme to use. Themes are located in themes/theme_name -THEME = 'site' - -# Show only teasers in the index pages? Defaults to False. -# INDEX_TEASERS = False - -# A HTML fragment describing the license, for the sidebar. -# I recomment using the Creative Commons' wizard: -# http://creativecommons.org/choose/ -LICENSE = """ -<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.5/ar/"> -<img alt="Creative Commons License BY-NC-SA" -style="border-width:0; margin-bottom:12px;" -src="http://i.creativecommons.org/l/by-nc-sa/2.5/ar/88x31.png"></a>""" - -# A small copyright notice for the page footer (in HTML) -CONTENT_FOOTER = u'Contents © 2012 Example Joe' - -# To enable comments via Disqus, you need to create a forum at -# http://disqus.com, and set DISQUS_FORUM to the short name you selected. -# If you want to disable comments, set it to False. -DISQUS_FORUM = "nikolademo" - -# Enable Addthis social buttons? -# Defaults to true -# ADD_THIS_BUTTONS = True - -# Modify the number of Post per Index Page -# Defaults to 10 -# INDEX_DISPLAY_POST_COUNT = 10 - -# RSS_LINK is a HTML fragment to link the RSS or Atom feeds. If set to None, -# the base.tmpl will use the feed Nikola generates. However, you may want to -# change it for a feedburner feed or something else. -RSS_LINK = None - -# A search form to search this site, for the sidebar. You can use a google -# custom search (http://www.google.com/cse/) -# Or a duckduckgo search: https://duckduckgo.com/search_box.html -# This example should work for pretty much any site we generate. -SEARCH_FORM = "" -# This search form is better for the "site" theme where it -# appears on the navigation bar -#SEARCH_FORM = """ -#<!-- Custom search --> -#<form method="get" id="search" action="http://duckduckgo.com/" """\ -#"""class="navbar-form pull-left"> -#<input type="hidden" name="sites" value="%s"/> -#<input type="hidden" name="k8" value="#444444"/> -#<input type="hidden" name="k9" value="#D51920"/> -#<input type="hidden" name="kt" value="h"/> -#<input type="text" name="q" maxlength="255" """\ -#"""placeholder="Search…" class="span2" style="margin-top: 4px;"/> -#<input type="submit" value="DuckDuckGo Search" style="visibility: hidden;" /> -#</form> -#<!-- End of custom search --> -#""" % BLOG_URL - -# Google analytics or whatever else you use. Added to the bottom of <body> -# in the default template (base.tmpl). -ANALYTICS = """ - """ - -# Put in global_context things you want available on all your templates. -# It can be anything, data, functions, modules, etc. -GLOBAL_CONTEXT = { - 'analytics': ANALYTICS, - 'blog_author': BLOG_AUTHOR, - 'blog_title': BLOG_TITLE, - 'blog_url': BLOG_URL, - 'blog_desc': BLOG_DESCRIPTION, - 'translations': TRANSLATIONS, - 'license': LICENSE, - 'search_form': SEARCH_FORM, - 'disqus_forum': DISQUS_FORUM, - 'content_footer': CONTENT_FOOTER, - 'rss_path': RSS_PATH, - 'rss_link': RSS_LINK, - # Locale-dependent links for the sidebar - # You should provide a key-value pair for each used language. - 'sidebar_links': { - DEFAULT_LANG: ( - ('/' + os.path.join(ARCHIVE_PATH, ARCHIVE_FILENAME), 'Archives'), - ('/categories/index.html', 'Tags'), - ('/stories/about-nikola.html', 'About Nikola'), - ('/stories/handbook.html', 'The Nikola Handbook'), - ('http://nikola.ralsina.com.ar', 'Powered by Nikola!'), - ), - } - } diff --git a/nikola/data/samplesite/posts/1.txt b/nikola/data/samplesite/posts/1.txt index 4e583db..5741e05 100644 --- a/nikola/data/samplesite/posts/1.txt +++ b/nikola/data/samplesite/posts/1.txt @@ -9,5 +9,7 @@ and build a site using it. Congratulations! * You can read the manual `here </stories/handbook.html>`__ * You can learn more about Nikola at http://nikola.ralsina.com.ar * You can see a demo photo gallery `here </galleries/demo/>`__ +* Demo usage of listings `here </stories/listings-demo.html>`__ +* Demo of slideshows `here </stories/slides-demo.html>`__ Send feedback to ralsina@netmanagers.com.ar! diff --git a/nikola/data/samplesite/stories/listings-demo.txt b/nikola/data/samplesite/stories/listings-demo.txt new file mode 100644 index 0000000..7875f17 --- /dev/null +++ b/nikola/data/samplesite/stories/listings-demo.txt @@ -0,0 +1,10 @@ +.. title: Listings Demo +.. slug: listings-demo +.. date: 2012/12/15 10:16:20 +.. tags: +.. link: +.. description: + +Nikola intends to let you show code easily via listings: + +.. listing:: hello.py python diff --git a/nikola/data/samplesite/stories/slides-demo.txt b/nikola/data/samplesite/stories/slides-demo.txt new file mode 100644 index 0000000..fb1356b --- /dev/null +++ b/nikola/data/samplesite/stories/slides-demo.txt @@ -0,0 +1,17 @@ +.. title: Slides Demo +.. slug: slides-demo +.. date: 2012/12/27 10:16:20 +.. tags: +.. link: +.. description: + +Nikola intends to let you do slideshows easily: + +.. slides:: + + /galleries/demo/tesla_conducts_lg.jpg + /galleries/demo/tesla_lightning2_lg.jpg + /galleries/demo/tesla4_lg.jpg + /galleries/demo/tesla_lightning1_lg.jpg + /galleries/demo/tesla_tower1_lg.jpg + diff --git a/nikola/data/themes/default/assets/css/bootstrap-responsive.css b/nikola/data/themes/default/assets/css/bootstrap-responsive.css index daafa91..a3352d7 100644 --- a/nikola/data/themes/default/assets/css/bootstrap-responsive.css +++ b/nikola/data/themes/default/assets/css/bootstrap-responsive.css @@ -1,5 +1,5 @@ /*! - * Bootstrap Responsive v2.1.0 + * Bootstrap Responsive v2.2.2 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 @@ -8,6 +8,10 @@ * Designed and built with all the love in the world @twitter by @mdo and @fat. */ +@-ms-viewport { + width: device-width; +} + .clearfix { *zoom: 1; } @@ -107,6 +111,7 @@ } [class*="span"] { float: left; + min-height: 1px; margin-left: 30px; } .container, @@ -214,6 +219,9 @@ .row-fluid [class*="span"]:first-child { margin-left: 0; } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.564102564102564%; + } .row-fluid .span12 { width: 100%; *width: 99.94680851063829%; @@ -453,6 +461,7 @@ } [class*="span"] { float: left; + min-height: 1px; margin-left: 20px; } .container, @@ -560,6 +569,9 @@ .row-fluid [class*="span"]:first-child { margin-left: 0; } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.7624309392265194%; + } .row-fluid .span12 { width: 100%; *width: 99.94680851063829%; @@ -780,7 +792,8 @@ padding-left: 20px; } .navbar-fixed-top, - .navbar-fixed-bottom { + .navbar-fixed-bottom, + .navbar-static-top { margin-right: -20px; margin-left: -20px; } @@ -811,11 +824,15 @@ margin-left: 0; } [class*="span"], + .uneditable-input[class*="span"], .row-fluid [class*="span"] { display: block; float: none; - width: auto; + width: 100%; margin-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; } .span12, .row-fluid .span12 { @@ -824,6 +841,9 @@ -moz-box-sizing: border-box; box-sizing: border-box; } + .row-fluid [class*="offset"]:first-child { + margin-left: 0; + } .input-large, .input-xlarge, .input-xxlarge, @@ -845,6 +865,9 @@ display: inline-block; width: auto; } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 0; + } .modal { position: fixed; top: 20px; @@ -853,8 +876,11 @@ width: auto; margin: 0; } + .modal.fade { + top: -100px; + } .modal.fade.in { - top: auto; + top: 20px; } } @@ -870,7 +896,7 @@ input[type="radio"] { border: 1px solid #ccc; } - .form-horizontal .control-group > label { + .form-horizontal .control-label { float: none; width: auto; padding-top: 0; @@ -886,6 +912,16 @@ padding-right: 10px; padding-left: 10px; } + .media .pull-left, + .media .pull-right { + display: block; + float: none; + margin-bottom: 10px; + } + .media-object { + margin-right: 0; + margin-left: 0; + } .modal { top: 10px; right: 10px; @@ -944,14 +980,14 @@ display: none; } .nav-collapse .nav .nav-header { - color: #555555; + color: #777777; text-shadow: none; } .nav-collapse .nav > li > a, .nav-collapse .dropdown-menu a { padding: 9px 15px; font-weight: bold; - color: #555555; + color: #777777; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; @@ -970,6 +1006,10 @@ .nav-collapse .dropdown-menu a:hover { background-color: #f2f2f2; } + .navbar-inverse .nav-collapse .nav > li > a, + .navbar-inverse .nav-collapse .dropdown-menu a { + color: #999999; + } .navbar-inverse .nav-collapse .nav > li > a:hover, .navbar-inverse .nav-collapse .dropdown-menu a:hover { background-color: #111111; @@ -982,7 +1022,7 @@ position: static; top: auto; left: auto; - display: block; + display: none; float: none; max-width: none; padding: 0; @@ -996,6 +1036,9 @@ -moz-box-shadow: none; box-shadow: none; } + .nav-collapse .open > .dropdown-menu { + display: block; + } .nav-collapse .dropdown-menu:before, .nav-collapse .dropdown-menu:after { display: none; @@ -1003,6 +1046,10 @@ .nav-collapse .dropdown-menu .divider { display: none; } + .nav-collapse .nav > li > .dropdown-menu:before, + .nav-collapse .nav > li > .dropdown-menu:after { + display: none; + } .nav-collapse .navbar-form, .nav-collapse .navbar-search { float: none; @@ -1014,6 +1061,11 @@ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); } + .navbar-inverse .nav-collapse .navbar-form, + .navbar-inverse .nav-collapse .navbar-search { + border-top-color: #111111; + border-bottom-color: #111111; + } .navbar .nav-collapse .nav.pull-right { float: none; margin-left: 0; diff --git a/nikola/data/themes/default/assets/css/bootstrap.css b/nikola/data/themes/default/assets/css/bootstrap.css index 0664207..8ab3cef 100644 --- a/nikola/data/themes/default/assets/css/bootstrap.css +++ b/nikola/data/themes/default/assets/css/bootstrap.css @@ -1,5 +1,5 @@ /*! - * Bootstrap v2.1.0 + * Bootstrap v2.2.2 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 @@ -67,6 +67,7 @@ sub { } img { + width: auto\9; height: auto; max-width: 100%; vertical-align: middle; @@ -74,7 +75,8 @@ img { -ms-interpolation-mode: bicubic; } -#map_canvas img { +#map_canvas img, +.google-maps img { max-width: none; } @@ -100,13 +102,24 @@ input::-moz-focus-inner { } button, -input[type="button"], +html input[type="button"], input[type="reset"], input[type="submit"] { cursor: pointer; -webkit-appearance: button; } +label, +select, +button, +input[type="button"], +input[type="reset"], +input[type="submit"], +input[type="radio"], +input[type="checkbox"] { + cursor: pointer; +} + input[type="search"] { -webkit-box-sizing: content-box; -moz-box-sizing: content-box; @@ -124,6 +137,58 @@ textarea { vertical-align: top; } +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 0.5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } +} + .clearfix { *zoom: 1; } @@ -215,6 +280,7 @@ a:hover { [class*="span"] { float: left; + min-height: 1px; margin-left: 20px; } @@ -353,6 +419,10 @@ a:hover { margin-left: 0; } +.row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.127659574468085%; +} + .row-fluid .span12 { width: 100%; *width: 99.94680851063829%; @@ -583,7 +653,7 @@ p { .lead { margin-bottom: 20px; - font-size: 20px; + font-size: 21px; font-weight: 200; line-height: 30px; } @@ -608,6 +678,42 @@ cite { color: #999999; } +a.muted:hover { + color: #808080; +} + +.text-warning { + color: #c09853; +} + +a.text-warning:hover { + color: #a47e3c; +} + +.text-error { + color: #b94a48; +} + +a.text-error:hover { + color: #953b39; +} + +.text-info { + color: #3a87ad; +} + +a.text-info:hover { + color: #2d6987; +} + +.text-success { + color: #468847; +} + +a.text-success:hover { + color: #356635; +} + h1, h2, h3, @@ -617,7 +723,7 @@ h6 { margin: 10px 0; font-family: inherit; font-weight: bold; - line-height: 1; + line-height: 20px; color: inherit; text-rendering: optimizelegibility; } @@ -633,42 +739,42 @@ h6 small { color: #999999; } -h1 { - font-size: 36px; +h1, +h2, +h3 { line-height: 40px; } +h1 { + font-size: 38.5px; +} + h2 { - font-size: 30px; - line-height: 40px; + font-size: 31.5px; } h3 { - font-size: 24px; - line-height: 40px; + font-size: 24.5px; } h4 { - font-size: 18px; - line-height: 20px; + font-size: 17.5px; } h5 { font-size: 14px; - line-height: 20px; } h6 { - font-size: 12px; - line-height: 20px; + font-size: 11.9px; } h1 small { - font-size: 24px; + font-size: 24.5px; } h2 small { - font-size: 18px; + font-size: 17.5px; } h3 small { @@ -708,6 +814,19 @@ ol.unstyled { list-style: none; } +ul.inline, +ol.inline { + margin-left: 0; + list-style: none; +} + +ul.inline > li, +ol.inline > li { + display: inline-block; + padding-right: 5px; + padding-left: 5px; +} + dl { margin-bottom: 20px; } @@ -725,9 +844,24 @@ dd { margin-left: 10px; } +.dl-horizontal { + *zoom: 1; +} + +.dl-horizontal:before, +.dl-horizontal:after { + display: table; + line-height: 0; + content: ""; +} + +.dl-horizontal:after { + clear: both; +} + .dl-horizontal dt { float: left; - width: 120px; + width: 160px; overflow: hidden; clear: left; text-align: right; @@ -736,7 +870,7 @@ dd { } .dl-horizontal dd { - margin-left: 130px; + margin-left: 180px; } hr { @@ -746,7 +880,8 @@ hr { border-bottom: 1px solid #ffffff; } -abbr[title] { +abbr[title], +abbr[data-original-title] { cursor: help; border-bottom: 1px dotted #999999; } @@ -828,6 +963,7 @@ pre { code { padding: 2px 4px; color: #d14; + white-space: nowrap; background-color: #f7f7f9; border: 1px solid #e1e1e8; } @@ -857,6 +993,8 @@ pre.prettyprint { pre code { padding: 0; color: inherit; + white-space: pre; + white-space: pre-wrap; background-color: transparent; border: 0; } @@ -935,18 +1073,20 @@ input[type="color"], display: inline-block; height: 20px; padding: 4px 6px; - margin-bottom: 9px; + margin-bottom: 10px; font-size: 14px; line-height: 20px; color: #555555; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; + vertical-align: middle; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; } input, -textarea { - width: 210px; +textarea, +.uneditable-input { + width: 206px; } textarea { @@ -1012,7 +1152,6 @@ input[type="checkbox"] { margin-top: 1px \9; *margin-top: 0; line-height: normal; - cursor: pointer; } input[type="file"], @@ -1039,7 +1178,7 @@ input[type="file"] { select { width: 220px; background-color: #ffffff; - border: 1px solid #bbb; + border: 1px solid #cccccc; } select[multiple], @@ -1094,14 +1233,14 @@ textarea::-webkit-input-placeholder { .radio, .checkbox { - min-height: 18px; - padding-left: 18px; + min-height: 20px; + padding-left: 20px; } .radio input[type="radio"], .checkbox input[type="checkbox"] { float: left; - margin-left: -18px; + margin-left: -20px; } .controls > .radio:first-child, @@ -1268,10 +1407,16 @@ textarea.span1, clear: both; } -.controls-row [class*="span"] { +.controls-row [class*="span"], +.row-fluid .controls-row [class*="span"] { float: left; } +.controls-row .checkbox[class*="span"], +.controls-row .radio[class*="span"] { + padding-top: 5px; +} + input[disabled], select[disabled], textarea[disabled], @@ -1289,7 +1434,7 @@ input[type="checkbox"][readonly] { background-color: transparent; } -.control-group.warning > label, +.control-group.warning .control-label, .control-group.warning .help-block, .control-group.warning .help-inline { color: #c09853; @@ -1301,14 +1446,17 @@ input[type="checkbox"][readonly] { .control-group.warning select, .control-group.warning textarea { color: #c09853; +} + +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { border-color: #c09853; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } -.control-group.warning .checkbox:focus, -.control-group.warning .radio:focus, .control-group.warning input:focus, .control-group.warning select:focus, .control-group.warning textarea:focus { @@ -1325,7 +1473,7 @@ input[type="checkbox"][readonly] { border-color: #c09853; } -.control-group.error > label, +.control-group.error .control-label, .control-group.error .help-block, .control-group.error .help-inline { color: #b94a48; @@ -1337,14 +1485,17 @@ input[type="checkbox"][readonly] { .control-group.error select, .control-group.error textarea { color: #b94a48; +} + +.control-group.error input, +.control-group.error select, +.control-group.error textarea { border-color: #b94a48; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } -.control-group.error .checkbox:focus, -.control-group.error .radio:focus, .control-group.error input:focus, .control-group.error select:focus, .control-group.error textarea:focus { @@ -1361,7 +1512,7 @@ input[type="checkbox"][readonly] { border-color: #b94a48; } -.control-group.success > label, +.control-group.success .control-label, .control-group.success .help-block, .control-group.success .help-inline { color: #468847; @@ -1373,14 +1524,17 @@ input[type="checkbox"][readonly] { .control-group.success select, .control-group.success textarea { color: #468847; +} + +.control-group.success input, +.control-group.success select, +.control-group.success textarea { border-color: #468847; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); } -.control-group.success .checkbox:focus, -.control-group.success .radio:focus, .control-group.success input:focus, .control-group.success select:focus, .control-group.success textarea:focus { @@ -1397,16 +1551,55 @@ input[type="checkbox"][readonly] { border-color: #468847; } -input:focus:required:invalid, -textarea:focus:required:invalid, -select:focus:required:invalid { +.control-group.info .control-label, +.control-group.info .help-block, +.control-group.info .help-inline { + color: #3a87ad; +} + +.control-group.info .checkbox, +.control-group.info .radio, +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + color: #3a87ad; +} + +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + border-color: #3a87ad; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.info input:focus, +.control-group.info select:focus, +.control-group.info textarea:focus { + border-color: #2d6987; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; +} + +.control-group.info .input-prepend .add-on, +.control-group.info .input-append .add-on { + color: #3a87ad; + background-color: #d9edf7; + border-color: #3a87ad; +} + +input:focus:invalid, +textarea:focus:invalid, +select:focus:invalid { color: #b94a48; border-color: #ee5f5b; } -input:focus:required:invalid:focus, -textarea:focus:required:invalid:focus, -select:focus:required:invalid:focus { +input:focus:invalid:focus, +textarea:focus:invalid:focus, +select:focus:invalid:focus { border-color: #e9322d; -webkit-box-shadow: 0 0 6px #f8b9b7; -moz-box-shadow: 0 0 6px #f8b9b7; @@ -1463,15 +1656,25 @@ select:focus:required:invalid:focus { .input-append select, .input-prepend select, .input-append .uneditable-input, +.input-prepend .uneditable-input, +.input-append .dropdown-menu, +.input-prepend .dropdown-menu { + font-size: 14px; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, .input-prepend .uneditable-input { position: relative; margin-bottom: 0; *margin-left: 0; - font-size: 14px; vertical-align: top; - -webkit-border-radius: 0 3px 3px 0; - -moz-border-radius: 0 3px 3px 0; - border-radius: 0 3px 3px 0; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; } .input-append input:focus, @@ -1502,8 +1705,9 @@ select:focus:required:invalid:focus { .input-append .add-on, .input-prepend .add-on, .input-append .btn, -.input-prepend .btn { - margin-left: -1px; +.input-prepend .btn, +.input-append .btn-group > .dropdown-toggle, +.input-prepend .btn-group > .dropdown-toggle { vertical-align: top; -webkit-border-radius: 0; -moz-border-radius: 0; @@ -1523,24 +1727,39 @@ select:focus:required:invalid:focus { .input-prepend .add-on:first-child, .input-prepend .btn:first-child { - -webkit-border-radius: 3px 0 0 3px; - -moz-border-radius: 3px 0 0 3px; - border-radius: 3px 0 0 3px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; } .input-append input, .input-append select, .input-append .uneditable-input { - -webkit-border-radius: 3px 0 0 3px; - -moz-border-radius: 3px 0 0 3px; - border-radius: 3px 0 0 3px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input + .btn-group .btn:last-child, +.input-append select + .btn-group .btn:last-child, +.input-append .uneditable-input + .btn-group .btn:last-child { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append .add-on, +.input-append .btn, +.input-append .btn-group { + margin-left: -1px; } .input-append .add-on:last-child, -.input-append .btn:last-child { - -webkit-border-radius: 0 3px 3px 0; - -moz-border-radius: 0 3px 3px 0; - border-radius: 0 3px 3px 0; +.input-append .btn:last-child, +.input-append .btn-group:last-child > .dropdown-toggle { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; } .input-prepend.input-append input, @@ -1551,20 +1770,32 @@ select:focus:required:invalid:focus { border-radius: 0; } +.input-prepend.input-append input + .btn-group .btn, +.input-prepend.input-append select + .btn-group .btn, +.input-prepend.input-append .uneditable-input + .btn-group .btn { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + .input-prepend.input-append .add-on:first-child, .input-prepend.input-append .btn:first-child { margin-right: -1px; - -webkit-border-radius: 3px 0 0 3px; - -moz-border-radius: 3px 0 0 3px; - border-radius: 3px 0 0 3px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; } .input-prepend.input-append .add-on:last-child, .input-prepend.input-append .btn:last-child { margin-left: -1px; - -webkit-border-radius: 0 3px 3px 0; - -moz-border-radius: 0 3px 3px 0; - border-radius: 0 3px 3px 0; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .btn-group:first-child { + margin-left: 0; } input.search-query { @@ -1706,7 +1937,7 @@ legend + .control-group { .form-horizontal .control-label { float: left; - width: 140px; + width: 160px; padding-top: 5px; text-align: right; } @@ -1714,21 +1945,29 @@ legend + .control-group { .form-horizontal .controls { *display: inline-block; *padding-left: 20px; - margin-left: 160px; + margin-left: 180px; *margin-left: 0; } .form-horizontal .controls:first-child { - *padding-left: 160px; + *padding-left: 180px; } .form-horizontal .help-block { - margin-top: 10px; margin-bottom: 0; } +.form-horizontal input + .help-block, +.form-horizontal select + .help-block, +.form-horizontal textarea + .help-block, +.form-horizontal .uneditable-input + .help-block, +.form-horizontal .input-prepend + .help-block, +.form-horizontal .input-append + .help-block { + margin-top: 10px; +} + .form-horizontal .form-actions { - padding-left: 160px; + padding-left: 180px; } table { @@ -1773,6 +2012,10 @@ table { border-top: 2px solid #dddddd; } +.table .table { + background-color: #ffffff; +} + .table-condensed th, .table-condensed td { padding: 4px 5px; @@ -1805,39 +2048,48 @@ table { border-top: 0; } -.table-bordered thead:first-child tr:first-child th:first-child, -.table-bordered tbody:first-child tr:first-child td:first-child { +.table-bordered thead:first-child tr:first-child > th:first-child, +.table-bordered tbody:first-child tr:first-child > td:first-child { -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topleft: 4px; } -.table-bordered thead:first-child tr:first-child th:last-child, -.table-bordered tbody:first-child tr:first-child td:last-child { +.table-bordered thead:first-child tr:first-child > th:last-child, +.table-bordered tbody:first-child tr:first-child > td:last-child { -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-topright: 4px; } -.table-bordered thead:last-child tr:last-child th:first-child, -.table-bordered tbody:last-child tr:last-child td:first-child, -.table-bordered tfoot:last-child tr:last-child td:first-child { - -webkit-border-radius: 0 0 0 4px; - -moz-border-radius: 0 0 0 4px; - border-radius: 0 0 0 4px; +.table-bordered thead:last-child tr:last-child > th:first-child, +.table-bordered tbody:last-child tr:last-child > td:first-child, +.table-bordered tfoot:last-child tr:last-child > td:first-child { -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomleft: 4px; } -.table-bordered thead:last-child tr:last-child th:last-child, -.table-bordered tbody:last-child tr:last-child td:last-child, -.table-bordered tfoot:last-child tr:last-child td:last-child { +.table-bordered thead:last-child tr:last-child > th:last-child, +.table-bordered tbody:last-child tr:last-child > td:last-child, +.table-bordered tfoot:last-child tr:last-child > td:last-child { -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; -moz-border-radius-bottomright: 4px; } +.table-bordered tfoot + tbody:last-child tr:last-child td:first-child { + -webkit-border-bottom-left-radius: 0; + border-bottom-left-radius: 0; + -moz-border-radius-bottomleft: 0; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 0; + border-bottom-right-radius: 0; + -moz-border-radius-bottomright: 0; +} + .table-bordered caption + thead tr:first-child th:first-child, .table-bordered caption + tbody tr:first-child td:first-child, .table-bordered colgroup + thead tr:first-child th:first-child, @@ -1853,11 +2105,11 @@ table { .table-bordered colgroup + tbody tr:first-child td:last-child { -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; - -moz-border-right-topleft: 4px; + -moz-border-radius-topright: 4px; } -.table-striped tbody tr:nth-child(odd) td, -.table-striped tbody tr:nth-child(odd) th { +.table-striped tbody > tr:nth-child(odd) > td, +.table-striped tbody > tr:nth-child(odd) > th { background-color: #f9f9f9; } @@ -1866,167 +2118,129 @@ table { background-color: #f5f5f5; } -table [class*=span], -.row-fluid table [class*=span] { +table td[class*="span"], +table th[class*="span"], +.row-fluid table td[class*="span"], +.row-fluid table th[class*="span"] { display: table-cell; float: none; margin-left: 0; } -table .span1 { +.table td.span1, +.table th.span1 { float: none; width: 44px; margin-left: 0; } -table .span2 { +.table td.span2, +.table th.span2 { float: none; width: 124px; margin-left: 0; } -table .span3 { +.table td.span3, +.table th.span3 { float: none; width: 204px; margin-left: 0; } -table .span4 { +.table td.span4, +.table th.span4 { float: none; width: 284px; margin-left: 0; } -table .span5 { +.table td.span5, +.table th.span5 { float: none; width: 364px; margin-left: 0; } -table .span6 { +.table td.span6, +.table th.span6 { float: none; width: 444px; margin-left: 0; } -table .span7 { +.table td.span7, +.table th.span7 { float: none; width: 524px; margin-left: 0; } -table .span8 { +.table td.span8, +.table th.span8 { float: none; width: 604px; margin-left: 0; } -table .span9 { +.table td.span9, +.table th.span9 { float: none; width: 684px; margin-left: 0; } -table .span10 { +.table td.span10, +.table th.span10 { float: none; width: 764px; margin-left: 0; } -table .span11 { +.table td.span11, +.table th.span11 { float: none; width: 844px; margin-left: 0; } -table .span12 { +.table td.span12, +.table th.span12 { float: none; width: 924px; margin-left: 0; } -table .span13 { - float: none; - width: 1004px; - margin-left: 0; -} - -table .span14 { - float: none; - width: 1084px; - margin-left: 0; -} - -table .span15 { - float: none; - width: 1164px; - margin-left: 0; -} - -table .span16 { - float: none; - width: 1244px; - margin-left: 0; -} - -table .span17 { - float: none; - width: 1324px; - margin-left: 0; -} - -table .span18 { - float: none; - width: 1404px; - margin-left: 0; -} - -table .span19 { - float: none; - width: 1484px; - margin-left: 0; -} - -table .span20 { - float: none; - width: 1564px; - margin-left: 0; +.table tbody tr.success td { + background-color: #dff0d8; } -table .span21 { - float: none; - width: 1644px; - margin-left: 0; +.table tbody tr.error td { + background-color: #f2dede; } -table .span22 { - float: none; - width: 1724px; - margin-left: 0; +.table tbody tr.warning td { + background-color: #fcf8e3; } -table .span23 { - float: none; - width: 1804px; - margin-left: 0; +.table tbody tr.info td { + background-color: #d9edf7; } -table .span24 { - float: none; - width: 1884px; - margin-left: 0; +.table-hover tbody tr.success:hover td { + background-color: #d0e9c6; } -.table tbody tr.success td { - background-color: #dff0d8; +.table-hover tbody tr.error:hover td { + background-color: #ebcccc; } -.table tbody tr.error td { - background-color: #f2dede; +.table-hover tbody tr.warning:hover td { + background-color: #faf2cc; } -.table tbody tr.info td { - background-color: #d9edf7; +.table-hover tbody tr.info:hover td { + background-color: #c4e3f3; } [class^="icon-"], @@ -2046,12 +2260,18 @@ table .span24 { /* White icons with optional class, or on hover/active states of certain elements */ .icon-white, -.nav > .active > a > [class^="icon-"], -.nav > .active > a > [class*=" icon-"], +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], .dropdown-menu > li > a:hover > [class^="icon-"], .dropdown-menu > li > a:hover > [class*=" icon-"], .dropdown-menu > .active > a > [class^="icon-"], -.dropdown-menu > .active > a > [class*=" icon-"] { +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"] { background-image: url("../img/glyphicons-halflings-white.png"); } @@ -2689,7 +2909,7 @@ table .span24 { border-bottom: 1px solid #ffffff; } -.dropdown-menu a { +.dropdown-menu li > a { display: block; padding: 3px 20px; clear: both; @@ -2704,7 +2924,6 @@ table .span24 { .dropdown-submenu:hover > a { color: #ffffff; text-decoration: none; - background-color: #0088cc; background-color: #0081c2; background-image: -moz-linear-gradient(top, #0088cc, #0077b3); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); @@ -2712,23 +2931,22 @@ table .span24 { background-image: -o-linear-gradient(top, #0088cc, #0077b3); background-image: linear-gradient(to bottom, #0088cc, #0077b3); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); } .dropdown-menu .active > a, .dropdown-menu .active > a:hover { color: #ffffff; text-decoration: none; - background-color: #0088cc; background-color: #0081c2; - background-image: linear-gradient(to bottom, #0088cc, #0077b3); background-image: -moz-linear-gradient(top, #0088cc, #0077b3); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); background-repeat: repeat-x; outline: 0; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); } .dropdown-menu .disabled > a, @@ -2740,6 +2958,8 @@ table .span24 { text-decoration: none; cursor: default; background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .open { @@ -2759,7 +2979,7 @@ table .span24 { .navbar-fixed-bottom .dropdown .caret { border-top: 0; border-bottom: 4px solid #000000; - content: "\2191"; + content: ""; } .dropup .dropdown-menu, @@ -2783,10 +3003,20 @@ table .span24 { border-radius: 0 6px 6px 6px; } -.dropdown-submenu:hover .dropdown-menu { +.dropdown-submenu:hover > .dropdown-menu { display: block; } +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + -webkit-border-radius: 5px 5px 5px 0; + -moz-border-radius: 5px 5px 5px 0; + border-radius: 5px 5px 5px 0; +} + .dropdown-submenu > a:after { display: block; float: right; @@ -2805,12 +3035,25 @@ table .span24 { border-left-color: #ffffff; } +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + .dropdown .dropdown-menu .nav-header { padding-right: 20px; padding-left: 20px; } .typeahead { + z-index: 1051; margin-top: 2px; -webkit-border-radius: 4px; -moz-border-radius: 4px; @@ -2866,7 +3109,6 @@ table .span24 { position: relative; height: 0; overflow: hidden; - overflow: visible \9; -webkit-transition: height 0.35s ease; -moz-transition: height 0.35s ease; -o-transition: height 0.35s ease; @@ -2907,12 +3149,11 @@ button.close { .btn { display: inline-block; *display: inline; - padding: 4px 14px; + padding: 4px 12px; margin-bottom: 0; *margin-left: .3em; font-size: 14px; line-height: 20px; - *line-height: 20px; color: #333333; text-align: center; text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); @@ -2920,22 +3161,22 @@ button.close { cursor: pointer; background-color: #f5f5f5; *background-color: #e6e6e6; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); - background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); background-repeat: repeat-x; border: 1px solid #bbbbbb; *border: 0; - border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); border-bottom-color: #a2a2a2; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); *zoom: 1; -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); @@ -2964,10 +3205,6 @@ button.close { .btn:hover { color: #333333; text-decoration: none; - background-color: #e6e6e6; - *background-color: #d9d9d9; - /* Buttons in IE7 don't get borders, so darken on hover */ - background-position: 0 -15px; -webkit-transition: background-position 0.1s linear; -moz-transition: background-position 0.1s linear; @@ -2983,8 +3220,6 @@ button.close { .btn.active, .btn:active { - background-color: #e6e6e6; - background-color: #d9d9d9 \9; background-image: none; outline: 0; -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); @@ -2995,7 +3230,6 @@ button.close { .btn.disabled, .btn[disabled] { cursor: default; - background-color: #e6e6e6; background-image: none; opacity: 0.65; filter: alpha(opacity=65); @@ -3005,32 +3239,42 @@ button.close { } .btn-large { - padding: 9px 14px; - font-size: 16px; - line-height: normal; - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - border-radius: 5px; + padding: 11px 19px; + font-size: 17.5px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; } -.btn-large [class^="icon-"] { - margin-top: 2px; +.btn-large [class^="icon-"], +.btn-large [class*=" icon-"] { + margin-top: 4px; } .btn-small { - padding: 3px 9px; - font-size: 12px; - line-height: 18px; + padding: 2px 10px; + font-size: 11.9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } -.btn-small [class^="icon-"] { +.btn-small [class^="icon-"], +.btn-small [class*=" icon-"] { margin-top: 0; } +.btn-mini [class^="icon-"], +.btn-mini [class*=" icon-"] { + margin-top: -1px; +} + .btn-mini { - padding: 2px 6px; - font-size: 11px; - line-height: 16px; + padding: 0 6px; + font-size: 10.5px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; } .btn-block { @@ -3047,6 +3291,12 @@ button.close { margin-top: 5px; } +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + .btn-primary.active, .btn-warning.active, .btn-danger.active, @@ -3066,16 +3316,16 @@ button.close { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #006dcc; *background-color: #0044cc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); background-image: linear-gradient(to bottom, #0088cc, #0044cc); - background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-repeat: repeat-x; border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-primary:hover, @@ -3098,16 +3348,16 @@ button.close { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #faa732; *background-color: #f89406; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); background-image: -webkit-linear-gradient(top, #fbb450, #f89406); background-image: -o-linear-gradient(top, #fbb450, #f89406); background-image: linear-gradient(to bottom, #fbb450, #f89406); - background-image: -moz-linear-gradient(top, #fbb450, #f89406); background-repeat: repeat-x; border-color: #f89406 #f89406 #ad6704; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-warning:hover, @@ -3130,16 +3380,16 @@ button.close { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #da4f49; *background-color: #bd362f; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); - background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); background-repeat: repeat-x; border-color: #bd362f #bd362f #802420; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-danger:hover, @@ -3162,16 +3412,16 @@ button.close { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #5bb75b; *background-color: #51a351; + background-image: -moz-linear-gradient(top, #62c462, #51a351); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); background-image: -webkit-linear-gradient(top, #62c462, #51a351); background-image: -o-linear-gradient(top, #62c462, #51a351); background-image: linear-gradient(to bottom, #62c462, #51a351); - background-image: -moz-linear-gradient(top, #62c462, #51a351); background-repeat: repeat-x; border-color: #51a351 #51a351 #387038; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-success:hover, @@ -3194,16 +3444,16 @@ button.close { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #49afcd; *background-color: #2f96b4; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); - background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); background-repeat: repeat-x; border-color: #2f96b4 #2f96b4 #1f6377; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-info:hover, @@ -3226,16 +3476,16 @@ button.close { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #363636; *background-color: #222222; + background-image: -moz-linear-gradient(top, #444444, #222222); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); background-image: -webkit-linear-gradient(top, #444444, #222222); background-image: -o-linear-gradient(top, #444444, #222222); background-image: linear-gradient(to bottom, #444444, #222222); - background-image: -moz-linear-gradient(top, #444444, #222222); background-repeat: repeat-x; border-color: #222222 #222222 #000000; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .btn-inverse:hover, @@ -3284,7 +3534,8 @@ input[type="submit"].btn.btn-mini { } .btn-link, -.btn-link:active { +.btn-link:active, +.btn-link[disabled] { background-color: transparent; background-image: none; -webkit-box-shadow: none; @@ -3307,11 +3558,20 @@ input[type="submit"].btn.btn-mini { background-color: transparent; } +.btn-link[disabled]:hover { + color: #333333; + text-decoration: none; +} + .btn-group { position: relative; + display: inline-block; + *display: inline; *margin-left: .3em; font-size: 0; white-space: nowrap; + vertical-align: middle; + *zoom: 1; } .btn-group:first-child { @@ -3328,17 +3588,9 @@ input[type="submit"].btn.btn-mini { font-size: 0; } -.btn-toolbar .btn-group { - display: inline-block; - *display: inline; - /* IE7 inline-block hack */ - - *zoom: 1; -} - -.btn-toolbar .btn + .btn, -.btn-toolbar .btn-group + .btn, -.btn-toolbar .btn + .btn-group { +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group { margin-left: 5px; } @@ -3354,20 +3606,21 @@ input[type="submit"].btn.btn-mini { } .btn-group > .btn, -.btn-group > .dropdown-menu { +.btn-group > .dropdown-menu, +.btn-group > .popover { font-size: 14px; } .btn-group > .btn-mini { - font-size: 11px; + font-size: 10.5px; } .btn-group > .btn-small { - font-size: 12px; + font-size: 11.9px; } .btn-group > .btn-large { - font-size: 16px; + font-size: 17.5px; } .btn-group > .btn:first-child { @@ -3504,8 +3757,7 @@ input[type="submit"].btn.btn-mini { } .dropup .btn-large .caret { - border-top: 0; - border-bottom: 5px solid #000000; + border-bottom-width: 5px; } .btn-primary .caret, @@ -3526,39 +3778,39 @@ input[type="submit"].btn.btn-mini { *zoom: 1; } -.btn-group-vertical .btn { +.btn-group-vertical > .btn { display: block; float: none; - width: 100%; + max-width: 100%; -webkit-border-radius: 0; -moz-border-radius: 0; border-radius: 0; } -.btn-group-vertical .btn + .btn { +.btn-group-vertical > .btn + .btn { margin-top: -1px; margin-left: 0; } -.btn-group-vertical .btn:first-child { +.btn-group-vertical > .btn:first-child { -webkit-border-radius: 4px 4px 0 0; -moz-border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0; } -.btn-group-vertical .btn:last-child { +.btn-group-vertical > .btn:last-child { -webkit-border-radius: 0 0 4px 4px; -moz-border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px; } -.btn-group-vertical .btn-large:first-child { +.btn-group-vertical > .btn-large:first-child { -webkit-border-radius: 6px 6px 0 0; -moz-border-radius: 6px 6px 0 0; border-radius: 6px 6px 0 0; } -.btn-group-vertical .btn-large:last-child { +.btn-group-vertical > .btn-large:last-child { -webkit-border-radius: 0 0 6px 6px; -moz-border-radius: 0 0 6px 6px; border-radius: 0 0 6px 6px; @@ -3567,7 +3819,6 @@ input[type="submit"].btn.btn-mini { .alert { padding: 8px 35px 8px 14px; margin-bottom: 20px; - color: #c09853; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); background-color: #fcf8e3; border: 1px solid #fbeed5; @@ -3576,6 +3827,11 @@ input[type="submit"].btn.btn-mini { border-radius: 4px; } +.alert, +.alert h4 { + color: #c09853; +} + .alert h4 { margin: 0; } @@ -3593,6 +3849,10 @@ input[type="submit"].btn.btn-mini { border-color: #d6e9c6; } +.alert-success h4 { + color: #468847; +} + .alert-danger, .alert-error { color: #b94a48; @@ -3600,12 +3860,21 @@ input[type="submit"].btn.btn-mini { border-color: #eed3d7; } +.alert-danger h4, +.alert-error h4 { + color: #b94a48; +} + .alert-info { color: #3a87ad; background-color: #d9edf7; border-color: #bce8f1; } +.alert-info h4 { + color: #3a87ad; +} + .alert-block { padding-top: 14px; padding-bottom: 14px; @@ -3635,6 +3904,10 @@ input[type="submit"].btn.btn-mini { background-color: #eeeeee; } +.nav > li > a > img { + max-width: none; +} + .nav > .pull-right { float: right; } @@ -3678,7 +3951,8 @@ input[type="submit"].btn.btn-mini { background-color: #0088cc; } -.nav-list [class^="icon-"] { +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { margin-right: 2px; } @@ -4018,7 +4292,6 @@ input[type="submit"].btn.btn-mini { *z-index: 2; margin-bottom: 20px; overflow: visible; - color: #555555; } .navbar-inner { @@ -4036,18 +4309,31 @@ input[type="submit"].btn.btn-mini { -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); + *zoom: 1; -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); } +.navbar-inner:before, +.navbar-inner:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-inner:after { + clear: both; +} + .navbar .container { width: auto; } .nav-collapse.collapse { height: auto; + overflow: visible; } .navbar .brand { @@ -4057,7 +4343,7 @@ input[type="submit"].btn.btn-mini { margin-left: -20px; font-size: 20px; font-weight: 200; - color: #555555; + color: #777777; text-shadow: 0 1px 0 #ffffff; } @@ -4068,10 +4354,11 @@ input[type="submit"].btn.btn-mini { .navbar-text { margin-bottom: 0; line-height: 40px; + color: #777777; } .navbar-link { - color: #555555; + color: #777777; } .navbar-link:hover { @@ -4087,11 +4374,13 @@ input[type="submit"].btn.btn-mini { .navbar .btn, .navbar .btn-group { - margin-top: 6px; + margin-top: 5px; } -.navbar .btn-group .btn { - margin: 0; +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn { + margin-top: 0; } .navbar-form { @@ -4132,7 +4421,7 @@ input[type="submit"].btn.btn-mini { .navbar-form .input-append, .navbar-form .input-prepend { - margin-top: 6px; + margin-top: 5px; white-space: nowrap; } @@ -4162,7 +4451,6 @@ input[type="submit"].btn.btn-mini { .navbar-static-top { position: static; - width: 100%; margin-bottom: 0; } @@ -4182,9 +4470,12 @@ input[type="submit"].btn.btn-mini { } .navbar-fixed-top .navbar-inner, -.navbar-fixed-bottom .navbar-inner, .navbar-static-top .navbar-inner { - border: 0; + border-width: 0 0 1px; +} + +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; } .navbar-fixed-top .navbar-inner, @@ -4208,9 +4499,9 @@ input[type="submit"].btn.btn-mini { .navbar-fixed-top .navbar-inner, .navbar-static-top .navbar-inner { - -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); - -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1), 0 1px 10px rgba(0, 0, 0, 0.1); + -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); } .navbar-fixed-bottom { @@ -4218,9 +4509,9 @@ input[type="submit"].btn.btn-mini { } .navbar-fixed-bottom .navbar-inner { - -webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); - -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); - box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.1), 0 -1px 10px rgba(0, 0, 0, 0.1); + -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); } .navbar .nav { @@ -4233,6 +4524,7 @@ input[type="submit"].btn.btn-mini { .navbar .nav.pull-right { float: right; + margin-right: 0; } .navbar .nav > li { @@ -4242,7 +4534,7 @@ input[type="submit"].btn.btn-mini { .navbar .nav > li > a { float: none; padding: 10px 15px 10px; - color: #555555; + color: #777777; text-decoration: none; text-shadow: 0 1px 0 #ffffff; } @@ -4279,16 +4571,16 @@ input[type="submit"].btn.btn-mini { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #ededed; *background-color: #e5e5e5; + background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); - background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); background-repeat: repeat-x; border-color: #e5e5e5 #e5e5e5 #bfbfbf; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); @@ -4364,6 +4656,11 @@ input[type="submit"].btn.btn-mini { border-bottom: 0; } +.navbar .nav li.dropdown > a:hover .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + .navbar .nav li.dropdown.open > .dropdown-toggle, .navbar .nav li.dropdown.active > .dropdown-toggle, .navbar .nav li.dropdown.open.active > .dropdown-toggle { @@ -4372,8 +4669,8 @@ input[type="submit"].btn.btn-mini { } .navbar .nav li.dropdown > .dropdown-toggle .caret { - border-top-color: #555555; - border-bottom-color: #555555; + border-top-color: #777777; + border-bottom-color: #777777; } .navbar .nav li.dropdown.open > .dropdown-toggle .caret, @@ -4412,10 +4709,6 @@ input[type="submit"].btn.btn-mini { border-radius: 6px 0 6px 6px; } -.navbar-inverse { - color: #999999; -} - .navbar-inverse .navbar-inner { background-color: #1b1b1b; background-image: -moz-linear-gradient(top, #222222, #111111); @@ -4425,7 +4718,7 @@ input[type="submit"].btn.btn-mini { background-image: linear-gradient(to bottom, #222222, #111111); background-repeat: repeat-x; border-color: #252525; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); } .navbar-inverse .brand, @@ -4439,6 +4732,14 @@ input[type="submit"].btn.btn-mini { color: #ffffff; } +.navbar-inverse .brand { + color: #999999; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + .navbar-inverse .nav > li > a:focus, .navbar-inverse .nav > li > a:hover { color: #ffffff; @@ -4472,6 +4773,11 @@ input[type="submit"].btn.btn-mini { background-color: #111111; } +.navbar-inverse .nav li.dropdown > a:hover .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + .navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { border-top-color: #999999; border-bottom-color: #999999; @@ -4527,16 +4833,16 @@ input[type="submit"].btn.btn-mini { text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); background-color: #0e0e0e; *background-color: #040404; + background-image: -moz-linear-gradient(top, #151515, #040404); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); background-image: -webkit-linear-gradient(top, #151515, #040404); background-image: -o-linear-gradient(top, #151515, #040404); background-image: linear-gradient(to bottom, #151515, #040404); - background-image: -moz-linear-gradient(top, #151515, #040404); background-repeat: repeat-x; border-color: #040404 #040404 #000000; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); - filter: progid:dximagetransform.microsoft.gradient(enabled=false); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); } .navbar-inverse .btn-navbar:hover, @@ -4564,24 +4870,23 @@ input[type="submit"].btn.btn-mini { border-radius: 4px; } -.breadcrumb li { +.breadcrumb > li { display: inline-block; *display: inline; text-shadow: 0 1px 0 #ffffff; *zoom: 1; } -.breadcrumb .divider { +.breadcrumb > li > .divider { padding: 0 5px; color: #ccc; } -.breadcrumb .active { +.breadcrumb > .active { color: #999999; } .pagination { - height: 40px; margin: 20px 0; } @@ -4590,63 +4895,69 @@ input[type="submit"].btn.btn-mini { *display: inline; margin-bottom: 0; margin-left: 0; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; *zoom: 1; -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); } -.pagination li { +.pagination ul > li { display: inline; } -.pagination a, -.pagination span { +.pagination ul > li > a, +.pagination ul > li > span { float: left; - padding: 0 14px; - line-height: 38px; + padding: 4px 12px; + line-height: 20px; text-decoration: none; background-color: #ffffff; border: 1px solid #dddddd; border-left-width: 0; } -.pagination a:hover, -.pagination .active a, -.pagination .active span { +.pagination ul > li > a:hover, +.pagination ul > .active > a, +.pagination ul > .active > span { background-color: #f5f5f5; } -.pagination .active a, -.pagination .active span { +.pagination ul > .active > a, +.pagination ul > .active > span { color: #999999; cursor: default; } -.pagination .disabled span, -.pagination .disabled a, -.pagination .disabled a:hover { +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover { color: #999999; cursor: default; background-color: transparent; } -.pagination li:first-child a, -.pagination li:first-child span { +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { border-left-width: 1px; - -webkit-border-radius: 3px 0 0 3px; - -moz-border-radius: 3px 0 0 3px; - border-radius: 3px 0 0 3px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; } -.pagination li:last-child a, -.pagination li:last-child span { - -webkit-border-radius: 0 3px 3px 0; - -moz-border-radius: 0 3px 3px 0; - border-radius: 0 3px 3px 0; +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; } .pagination-centered { @@ -4657,6 +4968,68 @@ input[type="submit"].btn.btn-mini { text-align: right; } +.pagination-large ul > li > a, +.pagination-large ul > li > span { + padding: 11px 19px; + font-size: 17.5px; +} + +.pagination-large ul > li:first-child > a, +.pagination-large ul > li:first-child > span { + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.pagination-large ul > li:last-child > a, +.pagination-large ul > li:last-child > span { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.pagination-mini ul > li:first-child > a, +.pagination-small ul > li:first-child > a, +.pagination-mini ul > li:first-child > span, +.pagination-small ul > li:first-child > span { + -webkit-border-bottom-left-radius: 3px; + border-bottom-left-radius: 3px; + -webkit-border-top-left-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-topleft: 3px; +} + +.pagination-mini ul > li:last-child > a, +.pagination-small ul > li:last-child > a, +.pagination-mini ul > li:last-child > span, +.pagination-small ul > li:last-child > span { + -webkit-border-top-right-radius: 3px; + border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-bottomright: 3px; +} + +.pagination-small ul > li > a, +.pagination-small ul > li > span { + padding: 2px 10px; + font-size: 11.9px; +} + +.pagination-mini ul > li > a, +.pagination-mini ul > li > span { + padding: 0 6px; + font-size: 10.5px; +} + .pager { margin: 20px 0; text-align: center; @@ -4679,7 +5052,8 @@ input[type="submit"].btn.btn-mini { display: inline; } -.pager a { +.pager li > a, +.pager li > span { display: inline-block; padding: 5px 14px; background-color: #fff; @@ -4689,42 +5063,29 @@ input[type="submit"].btn.btn-mini { border-radius: 15px; } -.pager a:hover { +.pager li > a:hover { text-decoration: none; background-color: #f5f5f5; } -.pager .next a { +.pager .next > a, +.pager .next > span { float: right; } -.pager .previous a { +.pager .previous > a, +.pager .previous > span { float: left; } -.pager .disabled a, -.pager .disabled a:hover { +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > span { color: #999999; cursor: default; background-color: #fff; } -.modal-open .dropdown-menu { - z-index: 2050; -} - -.modal-open .dropdown.open { - *z-index: 2050; -} - -.modal-open .popover { - z-index: 2060; -} - -.modal-open .tooltip { - z-index: 2080; -} - .modal-backdrop { position: fixed; top: 0; @@ -4747,12 +5108,11 @@ input[type="submit"].btn.btn-mini { .modal { position: fixed; - top: 50%; + top: 10%; left: 50%; z-index: 1050; width: 560px; - margin: -250px 0 0 -280px; - overflow: auto; + margin-left: -280px; background-color: #ffffff; border: 1px solid #999; border: 1px solid rgba(0, 0, 0, 0.3); @@ -4760,6 +5120,7 @@ input[type="submit"].btn.btn-mini { -webkit-border-radius: 6px; -moz-border-radius: 6px; border-radius: 6px; + outline: none; -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); @@ -4777,7 +5138,7 @@ input[type="submit"].btn.btn-mini { } .modal.fade.in { - top: 50%; + top: 10%; } .modal-header { @@ -4795,6 +5156,7 @@ input[type="submit"].btn.btn-mini { } .modal-body { + position: relative; max-height: 400px; padding: 15px; overflow-y: auto; @@ -4839,6 +5201,10 @@ input[type="submit"].btn.btn-mini { margin-left: -1px; } +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} + .tooltip { position: absolute; z-index: 1030; @@ -4931,6 +5297,8 @@ input[type="submit"].btn.btn-mini { display: none; width: 236px; padding: 1px; + text-align: left; + white-space: normal; background-color: #ffffff; border: 1px solid #ccc; border: 1px solid rgba(0, 0, 0, 0.2); @@ -4946,7 +5314,7 @@ input[type="submit"].btn.btn-mini { } .popover.top { - margin-bottom: 10px; + margin-top: -10px; } .popover.right { @@ -4958,7 +5326,7 @@ input[type="submit"].btn.btn-mini { } .popover.left { - margin-right: 10px; + margin-left: -10px; } .popover-title { @@ -4978,85 +5346,87 @@ input[type="submit"].btn.btn-mini { padding: 9px 14px; } -.popover-content p, -.popover-content ul, -.popover-content ol { - margin-bottom: 0; -} - .popover .arrow, .popover .arrow:after { position: absolute; - display: inline-block; + display: block; width: 0; height: 0; border-color: transparent; border-style: solid; } +.popover .arrow { + border-width: 11px; +} + .popover .arrow:after { - z-index: -1; + border-width: 10px; content: ""; } .popover.top .arrow { - bottom: -10px; + bottom: -11px; left: 50%; - margin-left: -10px; - border-top-color: #ffffff; - border-width: 10px 10px 0; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, 0.25); + border-bottom-width: 0; } .popover.top .arrow:after { - bottom: -1px; - left: -11px; - border-top-color: rgba(0, 0, 0, 0.25); - border-width: 11px 11px 0; + bottom: 1px; + margin-left: -10px; + border-top-color: #ffffff; + border-bottom-width: 0; } .popover.right .arrow { top: 50%; - left: -10px; - margin-top: -10px; - border-right-color: #ffffff; - border-width: 10px 10px 10px 0; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, 0.25); + border-left-width: 0; } .popover.right .arrow:after { - bottom: -11px; - left: -1px; - border-right-color: rgba(0, 0, 0, 0.25); - border-width: 11px 11px 11px 0; + bottom: -10px; + left: 1px; + border-right-color: #ffffff; + border-left-width: 0; } .popover.bottom .arrow { - top: -10px; + top: -11px; left: 50%; - margin-left: -10px; - border-bottom-color: #ffffff; - border-width: 0 10px 10px; + margin-left: -11px; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-top-width: 0; } .popover.bottom .arrow:after { - top: -1px; - left: -11px; - border-bottom-color: rgba(0, 0, 0, 0.25); - border-width: 0 11px 11px; + top: 1px; + margin-left: -10px; + border-bottom-color: #ffffff; + border-top-width: 0; } .popover.left .arrow { top: 50%; - right: -10px; - margin-top: -10px; - border-left-color: #ffffff; - border-width: 10px 0 10px 10px; + right: -11px; + margin-top: -11px; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, 0.25); + border-right-width: 0; } .popover.left .arrow:after { - right: -1px; - bottom: -11px; - border-left-color: rgba(0, 0, 0, 0.25); - border-width: 11px 0 11px 11px; + right: 1px; + bottom: -10px; + border-left-color: #ffffff; + border-right-width: 0; } .thumbnails { @@ -5122,8 +5492,47 @@ a.thumbnail:hover { color: #555555; } +.media, +.media-body { + overflow: hidden; + *overflow: visible; + zoom: 1; +} + +.media, +.media .media { + margin-top: 15px; +} + +.media:first-child { + margin-top: 0; +} + +.media-object { + display: block; +} + +.media-heading { + margin: 0 0 5px; +} + +.media .pull-left { + margin-right: 10px; +} + +.media .pull-right { + margin-left: 10px; +} + +.media-list { + margin-left: 0; + list-style: none; +} + .label, .badge { + display: inline-block; + padding: 2px 4px; font-size: 11.844px; font-weight: bold; line-height: 14px; @@ -5135,19 +5544,24 @@ a.thumbnail:hover { } .label { - padding: 1px 4px 2px; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; } .badge { - padding: 1px 9px 2px; + padding-right: 9px; + padding-left: 9px; -webkit-border-radius: 9px; -moz-border-radius: 9px; border-radius: 9px; } +.label:empty, +.badge:empty { + display: none; +} + a.label:hover, a.badge:hover { color: #ffffff; @@ -5275,7 +5689,7 @@ a.badge:hover { -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); @@ -5296,7 +5710,7 @@ a.badge:hover { background-image: -o-linear-gradient(top, #149bdf, #0480be); background-image: linear-gradient(to bottom, #149bdf, #0480be); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); @@ -5345,7 +5759,7 @@ a.badge:hover { background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); } .progress-danger.progress-striped .bar, @@ -5367,7 +5781,7 @@ a.badge:hover { background-image: -o-linear-gradient(top, #62c462, #57a957); background-image: linear-gradient(to bottom, #62c462, #57a957); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); } .progress-success.progress-striped .bar, @@ -5389,7 +5803,7 @@ a.badge:hover { background-image: -o-linear-gradient(top, #5bc0de, #339bb9); background-image: linear-gradient(to bottom, #5bc0de, #339bb9); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); } .progress-info.progress-striped .bar, @@ -5411,7 +5825,7 @@ a.badge:hover { background-image: -o-linear-gradient(top, #fbb450, #f89406); background-image: linear-gradient(to bottom, #fbb450, #f89406); background-repeat: repeat-x; - filter: progid:dximagetransform.microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); } .progress-warning.progress-striped .bar, @@ -5466,7 +5880,7 @@ a.badge:hover { overflow: hidden; } -.carousel .item { +.carousel-inner > .item { position: relative; display: none; -webkit-transition: 0.6s ease-in-out left; @@ -5475,46 +5889,46 @@ a.badge:hover { transition: 0.6s ease-in-out left; } -.carousel .item > img { +.carousel-inner > .item > img { display: block; line-height: 1; } -.carousel .active, -.carousel .next, -.carousel .prev { +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { display: block; } -.carousel .active { +.carousel-inner > .active { left: 0; } -.carousel .next, -.carousel .prev { +.carousel-inner > .next, +.carousel-inner > .prev { position: absolute; top: 0; width: 100%; } -.carousel .next { +.carousel-inner > .next { left: 100%; } -.carousel .prev { +.carousel-inner > .prev { left: -100%; } -.carousel .next.left, -.carousel .prev.right { +.carousel-inner > .next.left, +.carousel-inner > .prev.right { left: 0; } -.carousel .active.left { +.carousel-inner > .active.left { left: -100%; } -.carousel .active.right { +.carousel-inner > .active.right { left: 100%; } @@ -5578,6 +5992,10 @@ a.badge:hover { .hero-unit { padding: 60px; margin-bottom: 30px; + font-size: 18px; + font-weight: 200; + line-height: 30px; + color: inherit; background-color: #eeeeee; -webkit-border-radius: 6px; -moz-border-radius: 6px; @@ -5592,11 +6010,8 @@ a.badge:hover { color: inherit; } -.hero-unit p { - font-size: 18px; - font-weight: 200; +.hero-unit li { line-height: 30px; - color: inherit; } .pull-right { diff --git a/nikola/data/themes/default/assets/css/slides.css b/nikola/data/themes/default/assets/css/slides.css new file mode 100644 index 0000000..272c83e --- /dev/null +++ b/nikola/data/themes/default/assets/css/slides.css @@ -0,0 +1,11 @@ +.slides_container { + display: block; + margin-left: auto; + margin-right: auto; + max-width: 80%; + width: 400px; + height: 300px; +} +.slide-current { + font-weight: bold; +} diff --git a/nikola/data/themes/default/assets/js/bootstrap.js b/nikola/data/themes/default/assets/js/bootstrap.js index 7f303eb..6c15a58 100644 --- a/nikola/data/themes/default/assets/js/bootstrap.js +++ b/nikola/data/themes/default/assets/js/bootstrap.js @@ -1,5 +1,5 @@ /* =================================================== - * bootstrap-transition.js v2.1.0 + * bootstrap-transition.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#transitions * =================================================== * Copyright 2012 Twitter, Inc. @@ -20,13 +20,13 @@ !function ($) { - $(function () { + "use strict"; // jshint ;_; - "use strict"; // jshint ;_; + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ - /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) - * ======================================================= */ + $(function () { $.support.transition = (function () { @@ -58,7 +58,7 @@ }) }(window.jQuery);/* ========================================================== - * bootstrap-alert.js v2.1.0 + * bootstrap-alert.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#alerts * ========================================================== * Copyright 2012 Twitter, Inc. @@ -127,6 +127,8 @@ /* ALERT PLUGIN DEFINITION * ======================= */ + var old = $.fn.alert + $.fn.alert = function (option) { return this.each(function () { var $this = $(this) @@ -139,15 +141,22 @@ $.fn.alert.Constructor = Alert + /* ALERT NO CONFLICT + * ================= */ + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + /* ALERT DATA-API * ============== */ - $(function () { - $('body').on('click.alert.data-api', dismiss, Alert.prototype.close) - }) + $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) }(window.jQuery);/* ============================================================ - * bootstrap-button.js v2.1.0 + * bootstrap-button.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#buttons * ============================================================ * Copyright 2012 Twitter, Inc. @@ -199,7 +208,7 @@ } Button.prototype.toggle = function () { - var $parent = this.$element.parent('[data-toggle="buttons-radio"]') + var $parent = this.$element.closest('[data-toggle="buttons-radio"]') $parent && $parent .find('.active') @@ -212,6 +221,8 @@ /* BUTTON PLUGIN DEFINITION * ======================== */ + var old = $.fn.button + $.fn.button = function (option) { return this.each(function () { var $this = $(this) @@ -230,19 +241,26 @@ $.fn.button.Constructor = Button + /* BUTTON NO CONFLICT + * ================== */ + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + /* BUTTON DATA-API * =============== */ - $(function () { - $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) { - var $btn = $(e.target) - if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') - $btn.button('toggle') - }) + $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') }) }(window.jQuery);/* ========================================================== - * bootstrap-carousel.js v2.1.0 + * bootstrap-carousel.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#carousel * ========================================================== * Copyright 2012 Twitter, Inc. @@ -272,7 +290,6 @@ var Carousel = function (element, options) { this.$element = $(element) this.options = options - this.options.slide && this.slide(this.options.slide) this.options.pause == 'hover' && this.$element .on('mouseenter', $.proxy(this.pause, this)) .on('mouseleave', $.proxy(this.cycle, this)) @@ -337,9 +354,7 @@ , direction = type == 'next' ? 'left' : 'right' , fallback = type == 'next' ? 'first' : 'last' , that = this - , e = $.Event('slide', { - relatedTarget: $next[0] - }) + , e this.sliding = true @@ -347,6 +362,10 @@ $next = $next.length ? $next : this.$element.find('.item')[fallback]() + e = $.Event('slide', { + relatedTarget: $next[0] + }) + if ($next.hasClass('active')) return if ($.support.transition && this.$element.hasClass('slide')) { @@ -382,6 +401,8 @@ /* CAROUSEL PLUGIN DEFINITION * ========================== */ + var old = $.fn.carousel + $.fn.carousel = function (option) { return this.each(function () { var $this = $(this) @@ -403,21 +424,27 @@ $.fn.carousel.Constructor = Carousel + /* CAROUSEL NO CONFLICT + * ==================== */ + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + /* CAROUSEL DATA-API * ================= */ - $(function () { - $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) { - var $this = $(this), href - , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 - , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data()) - $target.carousel(options) - e.preventDefault() - }) + $(document).on('click.carousel.data-api', '[data-slide]', function (e) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = $.extend({}, $target.data(), $this.data()) + $target.carousel(options) + e.preventDefault() }) }(window.jQuery);/* ============================================================= - * bootstrap-collapse.js v2.1.0 + * bootstrap-collapse.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#collapse * ============================================================= * Copyright 2012 Twitter, Inc. @@ -538,8 +565,10 @@ } - /* COLLAPSIBLE PLUGIN DEFINITION - * ============================== */ + /* COLLAPSE PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.collapse $.fn.collapse = function (option) { return this.each(function () { @@ -558,23 +587,30 @@ $.fn.collapse.Constructor = Collapse - /* COLLAPSIBLE DATA-API + /* COLLAPSE NO CONFLICT * ==================== */ - $(function () { - $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { - var $this = $(this), href - , target = $this.attr('data-target') - || e.preventDefault() - || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 - , option = $(target).data('collapse') ? 'toggle' : $this.data() - $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') - $(target).collapse(option) - }) + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + /* COLLAPSE DATA-API + * ================= */ + + $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + $(target).collapse(option) }) }(window.jQuery);/* ============================================================ - * bootstrap-dropdown.js v2.1.0 + * bootstrap-dropdown.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#dropdowns * ============================================================ * Copyright 2012 Twitter, Inc. @@ -628,9 +664,10 @@ if (!isActive) { $parent.toggleClass('open') - $this.focus() } + $this.focus() + return false } @@ -657,7 +694,7 @@ if (!isActive || (isActive && e.keyCode == 27)) return $this.click() - $items = $('[role=menu] li:not(.divider) a', $parent) + $items = $('[role=menu] li:not(.divider):visible a', $parent) if (!$items.length) return @@ -675,8 +712,9 @@ } function clearMenus() { - getParent($(toggle)) - .removeClass('open') + $(toggle).each(function () { + getParent($(this)).removeClass('open') + }) } function getParent($this) { @@ -685,7 +723,7 @@ if (!selector) { selector = $this.attr('href') - selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 } $parent = $(selector) @@ -698,6 +736,8 @@ /* DROPDOWN PLUGIN DEFINITION * ========================== */ + var old = $.fn.dropdown + $.fn.dropdown = function (option) { return this.each(function () { var $this = $(this) @@ -710,20 +750,27 @@ $.fn.dropdown.Constructor = Dropdown + /* DROPDOWN NO CONFLICT + * ==================== */ + + $.fn.dropdown.noConflict = function () { + $.fn.dropdown = old + return this + } + + /* APPLY TO STANDARD DROPDOWN ELEMENTS * =================================== */ - $(function () { - $('html') - .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus) - $('body') - .on('click.dropdown touchstart.dropdown.data-api', '.dropdown', function (e) { e.stopPropagation() }) - .on('click.dropdown.data-api touchstart.dropdown.data-api' , toggle, Dropdown.prototype.toggle) - .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) - }) + $(document) + .on('click.dropdown.data-api touchstart.dropdown.data-api', clearMenus) + .on('click.dropdown touchstart.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('touchstart.dropdown.data-api', '.dropdown-menu', function (e) { e.stopPropagation() }) + .on('click.dropdown.data-api touchstart.dropdown.data-api' , toggle, Dropdown.prototype.toggle) + .on('keydown.dropdown.data-api touchstart.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) }(window.jQuery);/* ========================================================= - * bootstrap-modal.js v2.1.0 + * bootstrap-modal.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#modals * ========================================================= * Copyright 2012 Twitter, Inc. @@ -773,8 +820,6 @@ if (this.isShown || e.isDefaultPrevented()) return - $('body').addClass('modal-open') - this.isShown = true this.escape() @@ -796,13 +841,12 @@ that.$element .addClass('in') .attr('aria-hidden', false) - .focus() that.enforceFocus() transition ? - that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) : - that.$element.trigger('shown') + that.$element.one($.support.transition.end, function () { that.$element.focus().trigger('shown') }) : + that.$element.focus().trigger('shown') }) } @@ -820,8 +864,6 @@ this.isShown = false - $('body').removeClass('modal-open') - this.escape() $(document).off('focusin.modal') @@ -891,9 +933,11 @@ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />') .appendTo(document.body) - if (this.options.backdrop != 'static') { - this.$backdrop.click($.proxy(this.hide, this)) - } + this.$backdrop.click( + this.options.backdrop == 'static' ? + $.proxy(this.$element[0].focus, this.$element[0]) + : $.proxy(this.hide, this) + ) if (doAnimate) this.$backdrop[0].offsetWidth // force reflow @@ -920,6 +964,8 @@ /* MODAL PLUGIN DEFINITION * ======================= */ + var old = $.fn.modal + $.fn.modal = function (option) { return this.each(function () { var $this = $(this) @@ -940,28 +986,36 @@ $.fn.modal.Constructor = Modal + /* MODAL NO CONFLICT + * ================= */ + + $.fn.modal.noConflict = function () { + $.fn.modal = old + return this + } + + /* MODAL DATA-API * ============== */ - $(function () { - $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) { - var $this = $(this) - , href = $this.attr('href') - , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7 - , option = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()) + $(document).on('click.modal.data-api', '[data-toggle="modal"]', function (e) { + var $this = $(this) + , href = $this.attr('href') + , $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7 + , option = $target.data('modal') ? 'toggle' : $.extend({ remote:!/#/.test(href) && href }, $target.data(), $this.data()) - e.preventDefault() + e.preventDefault() - $target - .modal(option) - .one('hide', function () { - $this.focus() - }) - }) + $target + .modal(option) + .one('hide', function () { + $this.focus() + }) }) -}(window.jQuery);/* =========================================================== - * bootstrap-tooltip.js v2.1.0 +}(window.jQuery); +/* =========================================================== + * bootstrap-tooltip.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#tooltips * Inspired by the original jQuery.tipsy by Jason Frame * =========================================================== @@ -1081,9 +1135,9 @@ inside = /in/.test(placement) $tip - .remove() + .detach() .css({ top: 0, left: 0, display: 'block' }) - .appendTo(inside ? this.$element : document.body) + .insertAfter(this.$element) pos = this.getPosition(inside) @@ -1106,7 +1160,7 @@ } $tip - .css(tp) + .offset(tp) .addClass(placement) .addClass('in') } @@ -1128,18 +1182,18 @@ function removeWithAnimation() { var timeout = setTimeout(function () { - $tip.off($.support.transition.end).remove() + $tip.off($.support.transition.end).detach() }, 500) $tip.one($.support.transition.end, function () { clearTimeout(timeout) - $tip.remove() + $tip.detach() }) } $.support.transition && this.$tip.hasClass('fade') ? removeWithAnimation() : - $tip.remove() + $tip.detach() return this } @@ -1197,8 +1251,9 @@ this.enabled = !this.enabled } - , toggle: function () { - this[this.tip().hasClass('in') ? 'hide' : 'show']() + , toggle: function (e) { + var self = $(e.currentTarget)[this.type](this._options).data(this.type) + self[self.tip().hasClass('in') ? 'hide' : 'show']() } , destroy: function () { @@ -1211,6 +1266,8 @@ /* TOOLTIP PLUGIN DEFINITION * ========================= */ + var old = $.fn.tooltip + $.fn.tooltip = function ( option ) { return this.each(function () { var $this = $(this) @@ -1231,12 +1288,20 @@ , trigger: 'hover' , title: '' , delay: 0 - , html: true + , html: false } -}(window.jQuery); -/* =========================================================== - * bootstrap-popover.js v2.1.0 + + /* TOOLTIP NO CONFLICT + * =================== */ + + $.fn.tooltip.noConflict = function () { + $.fn.tooltip = old + return this + } + +}(window.jQuery);/* =========================================================== + * bootstrap-popover.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#popovers * =========================================================== * Copyright 2012 Twitter, Inc. @@ -1281,7 +1346,7 @@ , content = this.getContent() $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title) - $tip.find('.popover-content > *')[this.options.html ? 'html' : 'text'](content) + $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content) $tip.removeClass('fade top bottom left right in') } @@ -1318,6 +1383,8 @@ /* POPOVER PLUGIN DEFINITION * ======================= */ + var old = $.fn.popover + $.fn.popover = function (option) { return this.each(function () { var $this = $(this) @@ -1334,11 +1401,20 @@ placement: 'right' , trigger: 'click' , content: '' - , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>' + , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"></div></div></div>' }) + + /* POPOVER NO CONFLICT + * =================== */ + + $.fn.popover.noConflict = function () { + $.fn.popover = old + return this + } + }(window.jQuery);/* ============================================================= - * bootstrap-scrollspy.js v2.1.0 + * bootstrap-scrollspy.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#scrollspy * ============================================================= * Copyright 2012 Twitter, Inc. @@ -1398,7 +1474,7 @@ , $href = /^#\w/.test(href) && $(href) return ( $href && $href.length - && [[ $href.position().top, href ]] ) || null + && [[ $href.position().top + self.$scrollElement.scrollTop(), href ]] ) || null }) .sort(function (a, b) { return a[0] - b[0] }) .each(function () { @@ -1460,6 +1536,8 @@ /* SCROLLSPY PLUGIN DEFINITION * =========================== */ + var old = $.fn.scrollspy + $.fn.scrollspy = function (option) { return this.each(function () { var $this = $(this) @@ -1477,6 +1555,15 @@ } + /* SCROLLSPY NO CONFLICT + * ===================== */ + + $.fn.scrollspy.noConflict = function () { + $.fn.scrollspy = old + return this + } + + /* SCROLLSPY DATA-API * ================== */ @@ -1488,7 +1575,7 @@ }) }(window.jQuery);/* ======================================================== - * bootstrap-tab.js v2.1.0 + * bootstrap-tab.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#tabs * ======================================================== * Copyright 2012 Twitter, Inc. @@ -1538,7 +1625,7 @@ if ( $this.parent('li').hasClass('active') ) return - previous = $ul.find('.active a').last()[0] + previous = $ul.find('.active:last a')[0] e = $.Event('show', { relatedTarget: previous @@ -1599,6 +1686,8 @@ /* TAB PLUGIN DEFINITION * ===================== */ + var old = $.fn.tab + $.fn.tab = function ( option ) { return this.each(function () { var $this = $(this) @@ -1611,18 +1700,25 @@ $.fn.tab.Constructor = Tab + /* TAB NO CONFLICT + * =============== */ + + $.fn.tab.noConflict = function () { + $.fn.tab = old + return this + } + + /* TAB DATA-API * ============ */ - $(function () { - $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { - e.preventDefault() - $(this).tab('show') - }) + $(document).on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { + e.preventDefault() + $(this).tab('show') }) }(window.jQuery);/* ============================================================= - * bootstrap-typeahead.js v2.1.0 + * bootstrap-typeahead.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#typeahead * ============================================================= * Copyright 2012 Twitter, Inc. @@ -1656,8 +1752,8 @@ this.sorter = this.options.sorter || this.sorter this.highlighter = this.options.highlighter || this.highlighter this.updater = this.options.updater || this.updater - this.$menu = $(this.options.menu).appendTo('body') this.source = this.options.source + this.$menu = $(this.options.menu) this.shown = false this.listen() } @@ -1679,16 +1775,18 @@ } , show: function () { - var pos = $.extend({}, this.$element.offset(), { + var pos = $.extend({}, this.$element.position(), { height: this.$element[0].offsetHeight }) - this.$menu.css({ - top: pos.top + pos.height - , left: pos.left - }) + this.$menu + .insertAfter(this.$element) + .css({ + top: pos.top + pos.height + , left: pos.left + }) + .show() - this.$menu.show() this.shown = true return this } @@ -1797,7 +1895,7 @@ .on('keypress', $.proxy(this.keypress, this)) .on('keyup', $.proxy(this.keyup, this)) - if ($.browser.webkit || $.browser.msie) { + if (this.eventSupported('keydown')) { this.$element.on('keydown', $.proxy(this.keydown, this)) } @@ -1806,6 +1904,15 @@ .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) } + , eventSupported: function(eventName) { + var isSupported = eventName in this.$element + if (!isSupported) { + this.$element.setAttribute(eventName, 'return;') + isSupported = typeof this.$element[eventName] === 'function' + } + return isSupported + } + , move: function (e) { if (!this.shown) return @@ -1831,7 +1938,7 @@ } , keydown: function (e) { - this.suppressKeyPressRepeat = !~$.inArray(e.keyCode, [40,38,9,13,27]) + this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]) this.move(e) } @@ -1844,6 +1951,9 @@ switch(e.keyCode) { case 40: // down arrow case 38: // up arrow + case 16: // shift + case 17: // ctrl + case 18: // alt break case 9: // tab @@ -1887,6 +1997,8 @@ /* TYPEAHEAD PLUGIN DEFINITION * =========================== */ + var old = $.fn.typeahead + $.fn.typeahead = function (option) { return this.each(function () { var $this = $(this) @@ -1908,21 +2020,28 @@ $.fn.typeahead.Constructor = Typeahead - /* TYPEAHEAD DATA-API + /* TYPEAHEAD NO CONFLICT + * =================== */ + + $.fn.typeahead.noConflict = function () { + $.fn.typeahead = old + return this + } + + + /* TYPEAHEAD DATA-API * ================== */ - $(function () { - $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { - var $this = $(this) - if ($this.data('typeahead')) return - e.preventDefault() - $this.typeahead($this.data()) - }) + $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { + var $this = $(this) + if ($this.data('typeahead')) return + e.preventDefault() + $this.typeahead($this.data()) }) }(window.jQuery); /* ========================================================== - * bootstrap-affix.js v2.1.0 + * bootstrap-affix.js v2.2.2 * http://twitter.github.com/bootstrap/javascript.html#affix * ========================================================== * Copyright 2012 Twitter, Inc. @@ -1951,7 +2070,9 @@ var Affix = function (element, options) { this.options = $.extend({}, $.fn.affix.defaults, options) - this.$window = $(window).on('scroll.affix.data-api', $.proxy(this.checkPosition, this)) + this.$window = $(window) + .on('scroll.affix.data-api', $.proxy(this.checkPosition, this)) + .on('click.affix.data-api', $.proxy(function () { setTimeout($.proxy(this.checkPosition, this), 1) }, this)) this.$element = $(element) this.checkPosition() } @@ -1989,6 +2110,8 @@ /* AFFIX PLUGIN DEFINITION * ======================= */ + var old = $.fn.affix + $.fn.affix = function (option) { return this.each(function () { var $this = $(this) @@ -2006,6 +2129,15 @@ } + /* AFFIX NO CONFLICT + * ================= */ + + $.fn.affix.noConflict = function () { + $.fn.affix = old + return this + } + + /* AFFIX DATA-API * ============== */ diff --git a/nikola/data/themes/default/assets/js/slides.jquery.js b/nikola/data/themes/default/assets/js/slides.jquery.js new file mode 100755 index 0000000..f2e09c8 --- /dev/null +++ b/nikola/data/themes/default/assets/js/slides.jquery.js @@ -0,0 +1,555 @@ +/* +* Slides, A Slideshow Plugin for jQuery +* Intructions: http://slidesjs.com +* By: Nathan Searles, http://nathansearles.com +* Version: 1.1.9 +* Updated: September 5th, 2011 +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +(function($){ + $.fn.slides = function( option ) { + // override defaults with specified option + option = $.extend( {}, $.fn.slides.option, option ); + + return this.each(function(){ + // wrap slides in control container, make sure slides are block level + $('.' + option.container, $(this)).children().wrapAll('<div class="slides_control"/>'); + + var elem = $(this), + control = $('.slides_control',elem), + total = control.children().size(), + width = control.children().outerWidth(), + height = control.children().outerHeight(), + start = option.start - 1, + effect = option.effect.indexOf(',') < 0 ? option.effect : option.effect.replace(' ', '').split(',')[0], + paginationEffect = option.effect.indexOf(',') < 0 ? effect : option.effect.replace(' ', '').split(',')[1], + next = 0, prev = 0, number = 0, current = 0, loaded, active, clicked, position, direction, imageParent, pauseTimeout, playInterval; + + // is there only one slide? + if (total < 2) { + // Fade in .slides_container + $('.' + option.container, $(this)).fadeIn(option.fadeSpeed, option.fadeEasing, function(){ + // let the script know everything is loaded + loaded = true; + // call the loaded funciton + option.slidesLoaded(); + }); + // Hide the next/previous buttons + $('.' + option.next + ', .' + option.prev).fadeOut(0); + return false; + } + + // animate slides + function animate(direction, effect, clicked) { + if (!active && loaded) { + active = true; + // start of animation + option.animationStart(current + 1); + switch(direction) { + case 'next': + // change current slide to previous + prev = current; + // get next from current + 1 + next = current + 1; + // if last slide, set next to first slide + next = total === next ? 0 : next; + // set position of next slide to right of previous + position = width*2; + // distance to slide based on width of slides + direction = -width*2; + // store new current slide + current = next; + break; + case 'prev': + // change current slide to previous + prev = current; + // get next from current - 1 + next = current - 1; + // if first slide, set next to last slide + next = next === -1 ? total-1 : next; + // set position of next slide to left of previous + position = 0; + // distance to slide based on width of slides + direction = 0; + // store new current slide + current = next; + break; + case 'pagination': + // get next from pagination item clicked, convert to number + next = parseInt(clicked,10); + // get previous from pagination item with class of current + prev = $('.' + option.paginationClass + ' li.'+ option.currentClass +' a', elem).attr('href').match('[^#/]+$'); + // if next is greater then previous set position of next slide to right of previous + if (next > prev) { + position = width*2; + direction = -width*2; + } else { + // if next is less then previous set position of next slide to left of previous + position = 0; + direction = 0; + } + // store new current slide + current = next; + break; + } + + // fade animation + if (effect === 'fade') { + // fade animation with crossfade + if (option.crossfade) { + // put hidden next above current + control.children(':eq('+ next +')', elem).css({ + zIndex: 10 + // fade in next + }).fadeIn(option.fadeSpeed, option.fadeEasing, function(){ + if (option.autoHeight) { + // animate container to height of next + control.animate({ + height: control.children(':eq('+ next +')', elem).outerHeight() + }, option.autoHeightSpeed, function(){ + // hide previous + control.children(':eq('+ prev +')', elem).css({ + display: 'none', + zIndex: 0 + }); + // reset z index + control.children(':eq('+ next +')', elem).css({ + zIndex: 0 + }); + // end of animation + option.animationComplete(next + 1); + active = false; + }); + } else { + // hide previous + control.children(':eq('+ prev +')', elem).css({ + display: 'none', + zIndex: 0 + }); + // reset zindex + control.children(':eq('+ next +')', elem).css({ + zIndex: 0 + }); + // end of animation + option.animationComplete(next + 1); + active = false; + } + }); + } else { + // fade animation with no crossfade + control.children(':eq('+ prev +')', elem).fadeOut(option.fadeSpeed, option.fadeEasing, function(){ + // animate to new height + if (option.autoHeight) { + control.animate({ + // animate container to height of next + height: control.children(':eq('+ next +')', elem).outerHeight() + }, option.autoHeightSpeed, + // fade in next slide + function(){ + control.children(':eq('+ next +')', elem).fadeIn(option.fadeSpeed, option.fadeEasing); + }); + } else { + // if fixed height + control.children(':eq('+ next +')', elem).fadeIn(option.fadeSpeed, option.fadeEasing, function(){ + // fix font rendering in ie, lame + if($.browser.msie) { + $(this).get(0).style.removeAttribute('filter'); + } + }); + } + // end of animation + option.animationComplete(next + 1); + active = false; + }); + } + // slide animation + } else { + // move next slide to right of previous + control.children(':eq('+ next +')').css({ + left: position, + display: 'block' + }); + // animate to new height + if (option.autoHeight) { + control.animate({ + left: direction, + height: control.children(':eq('+ next +')').outerHeight() + },option.slideSpeed, option.slideEasing, function(){ + control.css({ + left: -width + }); + control.children(':eq('+ next +')').css({ + left: width, + zIndex: 5 + }); + // reset previous slide + control.children(':eq('+ prev +')').css({ + left: width, + display: 'none', + zIndex: 0 + }); + // end of animation + option.animationComplete(next + 1); + active = false; + }); + // if fixed height + } else { + // animate control + control.animate({ + left: direction + },option.slideSpeed, option.slideEasing, function(){ + // after animation reset control position + control.css({ + left: -width + }); + // reset and show next + control.children(':eq('+ next +')').css({ + left: width, + zIndex: 5 + }); + // reset previous slide + control.children(':eq('+ prev +')').css({ + left: width, + display: 'none', + zIndex: 0 + }); + // end of animation + option.animationComplete(next + 1); + active = false; + }); + } + } + // set current state for pagination + if (option.pagination) { + // remove current class from all + $('.'+ option.paginationClass +' li.' + option.currentClass, elem).removeClass(option.currentClass); + // add current class to next + $('.' + option.paginationClass + ' li:eq('+ next +')', elem).addClass(option.currentClass); + } + } + } // end animate function + + function stop() { + // clear interval from stored id + clearInterval(elem.data('interval')); + } + + function pause() { + if (option.pause) { + // clear timeout and interval + clearTimeout(elem.data('pause')); + clearInterval(elem.data('interval')); + // pause slide show for option.pause amount + pauseTimeout = setTimeout(function() { + // clear pause timeout + clearTimeout(elem.data('pause')); + // start play interval after pause + playInterval = setInterval( function(){ + animate("next", effect); + },option.play); + // store play interval + elem.data('interval',playInterval); + },option.pause); + // store pause interval + elem.data('pause',pauseTimeout); + } else { + // if no pause, just stop + stop(); + } + } + + // 2 or more slides required + if (total < 2) { + return; + } + + // error corection for start slide + if (start < 0) { + start = 0; + } + + if (start > total) { + start = total - 1; + } + + // change current based on start option number + if (option.start) { + current = start; + } + + // randomizes slide order + if (option.randomize) { + control.randomize(); + } + + // make sure overflow is hidden, width is set + $('.' + option.container, elem).css({ + overflow: 'hidden', + // fix for ie + position: 'relative' + }); + + // set css for slides + control.children().css({ + position: 'absolute', + top: 0, + left: control.children().outerWidth(), + zIndex: 0, + display: 'none' + }); + + // set css for control div + control.css({ + position: 'relative', + // size of control 3 x slide width + width: (width * 3), + // set height to slide height + height: height, + // center control to slide + left: -width + }); + + // show slides + $('.' + option.container, elem).css({ + display: 'block' + }); + + // if autoHeight true, get and set height of first slide + if (option.autoHeight) { + control.children().css({ + height: 'auto' + }); + control.animate({ + height: control.children(':eq('+ start +')').outerHeight() + },option.autoHeightSpeed); + } + + // checks if image is loaded + if (option.preload && control.find('img:eq(' + start + ')').length) { + // adds preload image + $('.' + option.container, elem).css({ + background: 'url(' + option.preloadImage + ') no-repeat 50% 50%' + }); + + // gets image src, with cache buster + var img = control.find('img:eq(' + start + ')').attr('src') + '?' + (new Date()).getTime(); + + // check if the image has a parent + if ($('img', elem).parent().attr('class') != 'slides_control') { + // If image has parent, get tag name + imageParent = control.children(':eq(0)')[0].tagName.toLowerCase(); + } else { + // Image doesn't have parent, use image tag name + imageParent = control.find('img:eq(' + start + ')'); + } + + // checks if image is loaded + control.find('img:eq(' + start + ')').attr('src', img).load(function() { + // once image is fully loaded, fade in + control.find(imageParent + ':eq(' + start + ')').fadeIn(option.fadeSpeed, option.fadeEasing, function(){ + $(this).css({ + zIndex: 5 + }); + // removes preload image + $('.' + option.container, elem).css({ + background: '' + }); + // let the script know everything is loaded + loaded = true; + // call the loaded funciton + option.slidesLoaded(); + }); + }); + } else { + // if no preloader fade in start slide + control.children(':eq(' + start + ')').fadeIn(option.fadeSpeed, option.fadeEasing, function(){ + // let the script know everything is loaded + loaded = true; + // call the loaded funciton + option.slidesLoaded(); + }); + } + + // click slide for next + if (option.bigTarget) { + // set cursor to pointer + control.children().css({ + cursor: 'pointer' + }); + // click handler + control.children().click(function(){ + // animate to next on slide click + animate('next', effect); + return false; + }); + } + + // pause on mouseover + if (option.hoverPause && option.play) { + control.bind('mouseover',function(){ + // on mouse over stop + stop(); + }); + control.bind('mouseleave',function(){ + // on mouse leave start pause timeout + pause(); + }); + } + + // generate next/prev buttons + if (option.generateNextPrev) { + $('.' + option.container, elem).after('<a href="#" class="'+ option.prev +'">Prev</a>'); + $('.' + option.prev, elem).after('<a href="#" class="'+ option.next +'">Next</a>'); + } + + // next button + $('.' + option.next ,elem).click(function(e){ + e.preventDefault(); + if (option.play) { + pause(); + } + animate('next', effect); + }); + + // previous button + $('.' + option.prev, elem).click(function(e){ + e.preventDefault(); + if (option.play) { + pause(); + } + animate('prev', effect); + }); + + // generate pagination + if (option.generatePagination) { + // create unordered list + if (option.prependPagination) { + elem.prepend('<ul class='+ option.paginationClass +'></ul>'); + } else { + elem.append('<ul class='+ option.paginationClass +'></ul>'); + } + // for each slide create a list item and link + control.children().each(function(){ + $('.' + option.paginationClass, elem).append('<li><a href="#'+ number +'">'+ (number+1) +'</a></li>'); + number++; + }); + } else { + // if pagination exists, add href w/ value of item number to links + $('.' + option.paginationClass + ' li a', elem).each(function(){ + $(this).attr('href', '#' + number); + number++; + }); + } + + // add current class to start slide pagination + $('.' + option.paginationClass + ' li:eq('+ start +')', elem).addClass(option.currentClass); + + // click handling + $('.' + option.paginationClass + ' li a', elem ).click(function(){ + // pause slideshow + if (option.play) { + pause(); + } + // get clicked, pass to animate function + clicked = $(this).attr('href').match('[^#/]+$'); + // if current slide equals clicked, don't do anything + if (current != clicked) { + animate('pagination', paginationEffect, clicked); + } + return false; + }); + + // click handling + $('a.link', elem).click(function(){ + // pause slideshow + if (option.play) { + pause(); + } + // get clicked, pass to animate function + clicked = $(this).attr('href').match('[^#/]+$') - 1; + // if current slide equals clicked, don't do anything + if (current != clicked) { + animate('pagination', paginationEffect, clicked); + } + return false; + }); + + if (option.play) { + // set interval + playInterval = setInterval(function() { + animate('next', effect); + }, option.play); + // store interval id + elem.data('interval',playInterval); + } + }); + }; + + // default options + $.fn.slides.option = { + preload: false, // boolean, Set true to preload images in an image based slideshow + preloadImage: '/img/loading.gif', // string, Name and location of loading image for preloader. Default is "/img/loading.gif" + container: 'slides_container', // string, Class name for slides container. Default is "slides_container" + generateNextPrev: false, // boolean, Auto generate next/prev buttons + next: 'next', // string, Class name for next button + prev: 'prev', // string, Class name for previous button + pagination: true, // boolean, If you're not using pagination you can set to false, but don't have to + generatePagination: true, // boolean, Auto generate pagination + prependPagination: false, // boolean, prepend pagination + paginationClass: 'pagination', // string, Class name for pagination + currentClass: 'current', // string, Class name for current class + fadeSpeed: 350, // number, Set the speed of the fading animation in milliseconds + fadeEasing: '', // string, must load jQuery's easing plugin before http://gsgd.co.uk/sandbox/jquery/easing/ + slideSpeed: 350, // number, Set the speed of the sliding animation in milliseconds + slideEasing: '', // string, must load jQuery's easing plugin before http://gsgd.co.uk/sandbox/jquery/easing/ + start: 1, // number, Set the speed of the sliding animation in milliseconds + effect: 'slide', // string, '[next/prev], [pagination]', e.g. 'slide, fade' or simply 'fade' for both + crossfade: false, // boolean, Crossfade images in a image based slideshow + randomize: false, // boolean, Set to true to randomize slides + play: 0, // number, Autoplay slideshow, a positive number will set to true and be the time between slide animation in milliseconds + pause: 0, // number, Pause slideshow on click of next/prev or pagination. A positive number will set to true and be the time of pause in milliseconds + hoverPause: false, // boolean, Set to true and hovering over slideshow will pause it + autoHeight: false, // boolean, Set to true to auto adjust height + autoHeightSpeed: 350, // number, Set auto height animation time in milliseconds + bigTarget: false, // boolean, Set to true and the whole slide will link to next slide on click + animationStart: function(){}, // Function called at the start of animation + animationComplete: function(){}, // Function called at the completion of animation + slidesLoaded: function() {} // Function is called when slides is fully loaded + }; + + // Randomize slide order on load + $.fn.randomize = function(callback) { + function randomizeOrder() { return(Math.round(Math.random())-0.5); } + return($(this).each(function() { + var $this = $(this); + var $children = $this.children(); + var childCount = $children.length; + if (childCount > 1) { + $children.hide(); + var indices = []; + for (i=0;i<childCount;i++) { indices[indices.length] = i; } + indices = indices.sort(randomizeOrder); + $.each(indices,function(j,k) { + var $child = $children.eq(k); + var $clone = $child.clone(true); + $clone.show().appendTo($this); + if (callback !== undefined) { + callback($child, $clone); + } + $child.remove(); + }); + } + })); + }; +})(jQuery);
\ No newline at end of file diff --git a/nikola/data/themes/default/bundles b/nikola/data/themes/default/bundles index 9d77983..ea9fba9 100644 --- a/nikola/data/themes/default/bundles +++ b/nikola/data/themes/default/bundles @@ -1,2 +1,2 @@ -assets/css/all.css=bootstrap.css,bootstrap-responsive.css,rst.css,code.css,colorbox.css,theme.css,custom.css -assets/js/all.js=jquery-1.7.2.min.js,jquery.colorbox-min.js +assets/css/all.css=bootstrap.css,bootstrap-responsive.css,rst.css,code.css,colorbox.css,slides.js,theme.css,custom.css +assets/js/all.js=jquery-1.7.2.min.js,jquery.colorbox-min.js,slides.min.jquery.js diff --git a/nikola/data/themes/default/messages/de.py b/nikola/data/themes/default/messages/de.py deleted file mode 100644 index 6e16a21..0000000 --- a/nikola/data/themes/default/messages/de.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- encoding:utf-8 -*- - -MESSAGES = { - u"LANGUAGE": u"Deutsch", - u"Posts for year %s": u"Einträge aus dem Jahr %s", - u"Archive": u"Archiv", - u"Posts about %s": u"Einträge über %s", - u"Tags": u"Tags", - u"Also available in": u"Auch verfügbar in", - u"More posts about": u"Weitere Einträge über", - u"Posted": u"Veröffentlicht", - u"Original site": u"Original-Seite", - u"Read in English": u"Auf Deutsch lesen", - u"Older posts": u"Ältere Einträge", - u"Newer posts": u"Neuere Einträge", - u"Previous post": u"Vorheriger Eintrag", - u"Next post": u"Nächster Eintrag", - u"Source": u"Source", - u"Read more": u"Weiterlesen", - u"old posts page %d": u'Vorherige Einträge %d' -} diff --git a/nikola/data/themes/default/messages/en.py b/nikola/data/themes/default/messages/en.py deleted file mode 100644 index 95b1210..0000000 --- a/nikola/data/themes/default/messages/en.py +++ /dev/null @@ -1,25 +0,0 @@ -MESSAGES = [ - u"Posts for year %s", - u"Archive", - u"Posts about %s", - u"Tags", - u"Also available in", - u"More posts about", - u"Posted", - u"Original site", - u"Read in English", - u"Newer posts", - u"Older posts", - u"Previous post", - u"Next post", - u"old posts page %d", - u"Read more", - u"Source", -] - -# In english things are not translated -msg_dict = {} -for msg in MESSAGES: - msg_dict[msg] = msg -MESSAGES = msg_dict -MESSAGES[u"LANGUAGE"] = "English" diff --git a/nikola/data/themes/default/messages/es.py b/nikola/data/themes/default/messages/es.py deleted file mode 100644 index 78de676..0000000 --- a/nikola/data/themes/default/messages/es.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- encoding:utf-8 -*- - -MESSAGES = { - u"LANGUAGE": u"Español", - u"Posts for year %s": u"Posts del año %s", - u"Archive": u"Archivo", - u"Posts about %s": u"Posts sobre %s", - u"Tags": u"Tags", - u"Also available in": u"También disponible en", - u"More posts about": u"Más posts sobre", - u"Posted": u"Publicado", - u"Original site": u"Sitio original", - u"Read in English": u"Leer en español", - u"Older posts": u"Posts anteriores", - u"Newer posts": u"Posts posteriores", - u"Previous post": u"Post anterior", - u"Next post": u"Siguiente post", - u"old posts page %d": u"posts antiguos página %d", - u"Read more": u"Leer más", - u"Source": u"Código", -} diff --git a/nikola/data/themes/default/messages/fr.py b/nikola/data/themes/default/messages/fr.py deleted file mode 100644 index 5db1a1f..0000000 --- a/nikola/data/themes/default/messages/fr.py +++ /dev/null @@ -1,17 +0,0 @@ -# -*- encoding:utf-8 -*- - -MESSAGES = { - u"LANGUAGE": u"Français", - u"Posts for year %s": u"Billets de l'année %s", - u"Archive": u"Archives", - u"Posts about %s": u"Billets sur %s", - u"Tags": u"Étiquettes", - u"Also available in": u"Disponible aussi en", - u"More posts about": u"Plus de billets sur", - u"Posted": u"Publié", - u"Original site": u"Site d'origine", - u"Read in English": u"Lire en français", - u"Newer posts": u"Billets récents", - u"Older posts": u"Anciens billets", - u"Source": u"Source", -} diff --git a/nikola/data/themes/default/messages/gr.py b/nikola/data/themes/default/messages/gr.py deleted file mode 100644 index fa6bb32..0000000 --- a/nikola/data/themes/default/messages/gr.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- encoding:utf-8 -*- - -MESSAGES = { - u"LANGUAGE": u"Ελληνικά", - u"Posts for year %s": u"Αναρτήσεις για τη χρονιά %s", - u"Archive": u"Αρχείο", - u"Posts about %s": u"Αναρτήσεις για %s", - u"Tags": u"Ετικέτες", - u"Also available in": u"Διαθέσιμο και στο", - u"More posts about": u"Περισσότερες αναρτήσεις για", - u"Posted": u"Αναρτήθηκε", - u"Original site": u"Ιστοσελίδα αρχικής ανάρτησης", - u"Read in English": u"Διαβάστε στα Ελληνικά", - u"Newer posts": u"Νεότερες αναρτήσεις", - u"Older posts": u"Παλαιότερες αναρτήσεις", - u"Previous post": u"Προηγούμενη ανάρτηση", - u"Next post": u"Επόμενη ανάρτηση", - u"old posts page %d": u"σελίδα παλαιότερων αναρτήσεων %d", - u"Source": u"Source", -} diff --git a/nikola/data/themes/default/messages/it.py b/nikola/data/themes/default/messages/it.py deleted file mode 100644 index 01a97d5..0000000 --- a/nikola/data/themes/default/messages/it.py +++ /dev/null @@ -1,20 +0,0 @@ -MESSAGES = { - u"LANGUAGE": u"Italiano", - u"Posts for year %s": u"Articoli per l'anno %s", - u"Archive": u"Archivio", - u"Posts about %s": u"Articoli su %s", - u"Tags": u"Tags", - u"Also available in": u"Anche disponibile in", - u"More posts about": u"Altri articoli su", - u"Posted": u"Pubblicato", - u"Original site": u"Sito originale", - u"Read in English": u"Leggi in italiano", - u"Newer posts": u"Articoli recenti", - u"Older posts": u"Articoli più vecchi", - u"Older posts": u"Articoli vecchi", - u"Previous post": u"Articolo precedente", - u"Next post": u"Articolo successivo", - u"old posts page %d": u"pagina dei vecchi articoli %d", - u"Read more": u"Espandi", - u"Source": u"Source", -} diff --git a/nikola/data/themes/default/messages/messages_de.py b/nikola/data/themes/default/messages/messages_de.py new file mode 100644 index 0000000..cafbcbb --- /dev/null +++ b/nikola/data/themes/default/messages/messages_de.py @@ -0,0 +1,22 @@ +# -*- encoding:utf-8 -*- +from __future__ import unicode_literals + +MESSAGES = { + "LANGUAGE": "Deutsch", + "Posts for year %s": "Einträge aus dem Jahr %s", + "Archive": "Archiv", + "Posts about %s": "Einträge über %s", + "Tags": "Tags", + "Also available in": "Auch verfügbar in", + "More posts about": "Weitere Einträge über", + "Posted": "Veröffentlicht", + "Original site": "Original-Seite", + "Read in English": "Auf Deutsch lesen", + "Older posts": "Ältere Einträge", + "Newer posts": "Neuere Einträge", + "Previous post": "Vorheriger Eintrag", + "Next post": "Nächster Eintrag", + "Source": "Source", + "Read more": "Weiterlesen", + "old posts page %d": "Vorherige Einträge %d" +} diff --git a/nikola/data/themes/default/messages/messages_en.py b/nikola/data/themes/default/messages/messages_en.py new file mode 100644 index 0000000..6d39047 --- /dev/null +++ b/nikola/data/themes/default/messages/messages_en.py @@ -0,0 +1,27 @@ +from __future__ import unicode_literals + +MESSAGES = [ + "Posts for year %s", + "Archive", + "Posts about %s", + "Tags", + "Also available in", + "More posts about", + "Posted", + "Original site", + "Read in English", + "Newer posts", + "Older posts", + "Previous post", + "Next post", + "old posts page %d", + "Read more", + "Source", +] + +# In english things are not translated +msg_dict = {} +for msg in MESSAGES: + msg_dict[msg] = msg +MESSAGES = msg_dict +MESSAGES["LANGUAGE"] = "English" diff --git a/nikola/data/themes/default/messages/messages_es.py b/nikola/data/themes/default/messages/messages_es.py new file mode 100644 index 0000000..f17f058 --- /dev/null +++ b/nikola/data/themes/default/messages/messages_es.py @@ -0,0 +1,22 @@ +# -*- encoding:utf-8 -*- +from __future__ import unicode_literals + +MESSAGES = { + "LANGUAGE": "Español", + "Posts for year %s": "Posts del año %s", + "Archive": "Archivo", + "Posts about %s": "Posts sobre %s", + "Tags": "Tags", + "Also available in": "También disponible en", + "More posts about": "Más posts sobre", + "Posted": "Publicado", + "Original site": "Sitio original", + "Read in English": "Leer en español", + "Older posts": "Posts anteriores", + "Newer posts": "Posts posteriores", + "Previous post": "Post anterior", + "Next post": "Siguiente post", + "old posts page %d": "posts antiguos página %d", + "Read more": "Leer más", + "Source": "Código", +} diff --git a/nikola/data/themes/default/messages/messages_fr.py b/nikola/data/themes/default/messages/messages_fr.py new file mode 100644 index 0000000..776147b --- /dev/null +++ b/nikola/data/themes/default/messages/messages_fr.py @@ -0,0 +1,18 @@ +# -*- encoding:utf-8 -*- +from __future__ import unicode_literals + +MESSAGES = { + "LANGUAGE": "Français", + "Posts for year %s": "Billets de l'année %s", + "Archive": "Archives", + "Posts about %s": "Billets sur %s", + "Tags": "Étiquettes", + "Also available in": "Disponible aussi en", + "More posts about": "Plus de billets sur", + "Posted": "Publié", + "Original site": "Site d'origine", + "Read in English": "Lire en français", + "Newer posts": "Billets récents", + "Older posts": "Anciens billets", + "Source": "Source", +} diff --git a/nikola/data/themes/default/messages/messages_gr.py b/nikola/data/themes/default/messages/messages_gr.py new file mode 100644 index 0000000..5965bc3 --- /dev/null +++ b/nikola/data/themes/default/messages/messages_gr.py @@ -0,0 +1,21 @@ +# -*- encoding:utf-8 -*- +from __future__ import unicode_literals + +MESSAGES = { + "LANGUAGE": "Ελληνικά", + "Posts for year %s": "Αναρτήσεις για τη χρονιά %s", + "Archive": "Αρχείο", + "Posts about %s": "Αναρτήσεις για %s", + "Tags": "Ετικέτες", + "Also available in": "Διαθέσιμο και στο", + "More posts about": "Περισσότερες αναρτήσεις για", + "Posted": "Αναρτήθηκε", + "Original site": "Ιστοσελίδα αρχικής ανάρτησης", + "Read in English": "Διαβάστε στα Ελληνικά", + "Newer posts": "Νεότερες αναρτήσεις", + "Older posts": "Παλαιότερες αναρτήσεις", + "Previous post": "Προηγούμενη ανάρτηση", + "Next post": "Επόμενη ανάρτηση", + "old posts page %d": "σελίδα παλαιότερων αναρτήσεων %d", + "Source": "Source", +} diff --git a/nikola/data/themes/default/messages/messages_it.py b/nikola/data/themes/default/messages/messages_it.py new file mode 100644 index 0000000..42f4709 --- /dev/null +++ b/nikola/data/themes/default/messages/messages_it.py @@ -0,0 +1,23 @@ +# vim: set fileencoding=utf-8 : +from __future__ import unicode_literals + +MESSAGES = { + "LANGUAGE": "Italiano", + "Posts for year %s": "Articoli per l'anno %s", + "Archive": "Archivio", + "Posts about %s": "Articoli su %s", + "Tags": "Tags", + "Also available in": "Anche disponibile in", + "More posts about": "Altri articoli s", + "Posted": "Pubblicato", + "Original site": "Sito originale", + "Read in English": "Leggi in italiano", + "Newer posts": "Articoli recenti", + "Older posts": "Articoli più vecchi", + "Older posts": "Articoli vecchi", + "Previous post": "Articolo precedente", + "Next post": "Articolo successivo", + "old posts page %d": "pagina dei vecchi articoli %d", + "Read more": "Espandi", + "Source": "Source", +} diff --git a/nikola/data/themes/default/messages/messages_ru.py b/nikola/data/themes/default/messages/messages_ru.py new file mode 100644 index 0000000..8a209ec --- /dev/null +++ b/nikola/data/themes/default/messages/messages_ru.py @@ -0,0 +1,22 @@ +# -*- encoding:utf-8 -*- +from __future__ import unicode_literals + +MESSAGES = { + "LANGUAGE": "Русский", + "Posts for year %s": "Записи за %s год", + "Archive": "Архив", + "Posts about %s": "Записи с тэгом %s:", + "Tags": "Тэги", + "Also available in": "Также доступно в", + "More posts about": "Больше записей о", + "Posted": "Опубликовано", + "Original site": "Оригинальный сайт", + "Read in English": "Прочесть по-русски", + "Older posts": "Старые записи", + "Newer posts": "Новые записи", + "Previous post": "Предыдущая запись", + "Next post": "Следующая запись", + "old posts page %d": "страница со старыми записями %d", + "Read more": "Продолжить чтение", + "Source": "Source", +} diff --git a/nikola/data/themes/default/messages/ru.py b/nikola/data/themes/default/messages/ru.py deleted file mode 100644 index 5d5cb01..0000000 --- a/nikola/data/themes/default/messages/ru.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- encoding:utf-8 -*- - -MESSAGES = { - u"LANGUAGE": u"Русский", - u"Posts for year %s": u"Записи за %s год", - u"Archive": u"Архив", - u"Posts about %s": u"Записи с тэгом %s:", - u"Tags": u"Тэги", - u"Also available in": u"Также доступно в", - u"More posts about": u"Больше записей о", - u"Posted": u"Опубликовано", - u"Original site": u"Оригинальный сайт", - u"Read in English": u"Прочесть по-русски", - u"Older posts": u"Старые записи", - u"Newer posts": u"Новые записи", - u"Previous post": u"Предыдущая запись", - u"Next post": u"Следующая запись", - u"old posts page %d": u"страница со старыми записями %d", - u"Read more": u"Продолжить чтение", - u"Source": u"Source", -} diff --git a/nikola/data/themes/default/templates/base.tmpl b/nikola/data/themes/default/templates/base.tmpl index cb5e0dd..9c134b7 100644 --- a/nikola/data/themes/default/templates/base.tmpl +++ b/nikola/data/themes/default/templates/base.tmpl @@ -1,40 +1,9 @@ ## -*- coding: utf-8 -*- +<%namespace file="base_helper.tmpl" import="*"/> <!DOCTYPE html> <html lang="${lang}"> <head> - <meta charset="utf-8"> - <meta name="title" content="${title} | ${blog_title}" > - <meta name="description" content="${description}" > - <meta name="author" content="${blog_author}"> - <title>${title} | ${blog_title}</title> - <!-- Le styles --> - %if use_bundles: - <link href="/assets/css/all.css" rel="stylesheet" type="text/css"> - <script src="/assets/js/all.js" type="text/javascript"></script> - %else: - <link href="/assets/css/bootstrap.css" rel="stylesheet" type="text/css"> - <link href="/assets/css/bootstrap-responsive.css" rel="stylesheet" type="text/css"> - <link href="/assets/css/rst.css" rel="stylesheet" type="text/css"> - <link href="/assets/css/code.css" rel="stylesheet" type="text/css"> - <link href="/assets/css/colorbox.css" rel="stylesheet" type="text/css"/> - <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"/> - %if exists("files/assets/css/custom.css", not_empty=True): - <link href="/assets/css/custom.css" rel="stylesheet" type="text/css"> - %endif - <script src="/assets/js/jquery-1.7.2.min.js" type="text/javascript"></script> - <script src="/assets/js/jquery.colorbox-min.js" type="text/javascript"></script> - %endif - <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements --> - <!--[if lt IE 9]> - <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script> - <![endif]--> - %if rss_link: - ${rss_link} - %else: - %for language in translations: - <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS (${language})" href="${_link("rss", None, lang)}"> - %endfor - %endif + ${html_head()} <%block name="extra_head"> </%block> </head> @@ -54,18 +23,14 @@ %if len(translations) > 1: <small> ${(messages[lang][u"Also available in"])}: - %for langname in translations.keys(): - %if langname != lang: - <a href="${_link("index", None, langname)}">${messages[langname]["LANGUAGE"]}</a> - %endif - %endfor + ${html_translations()} </small> %endif </%block> <hr> </div> <!-- End of banner-like substance !--> - <div class="row" id="contentrow"> + <div class="row-fluid" id="contentrow"> <div class="span10" id="contentcolumn"> <!--Body content--> <%block name="content"></%block> @@ -77,23 +42,8 @@ <!--Sidebar content--> <ul class="unstyled"> <li>${license} - <!-- social buttons --> - %if add_this_buttons: - <li> - <div id="addthisbox" class="addthis_toolbox addthis_default_style"> - <a class="addthis_button_preferred_1"></a> - <a class="addthis_button_preferred_2"></a> - <a class="addthis_button_preferred_3"></a> - <a class="addthis_button_preferred_4"></a> - <a class="addthis_button_compact"></a> - <a class="addthis_counter addthis_bubble_style"></a> - </div> - <script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script> - <!-- End of social buttons --> - % endif - %for url, text in sidebar_links[lang]: - <li><a href="${url}">${text}</a> - %endfor + ${html_social()} + ${html_sidebar_links()} <li>${search_form} </ul> <!--End of sidebar content--> diff --git a/nikola/data/themes/default/templates/base_helper.tmpl b/nikola/data/themes/default/templates/base_helper.tmpl new file mode 100644 index 0000000..3f27f23 --- /dev/null +++ b/nikola/data/themes/default/templates/base_helper.tmpl @@ -0,0 +1,74 @@ +<%def name="html_head()"> + <meta charset="utf-8"> + <meta name="title" content="${title} | ${blog_title}" > + <meta name="description" content="${description}" > + <meta name="author" content="${blog_author}"> + <title>${title} | ${blog_title}</title> + <!-- Le styles --> + %if use_bundles: + <link href="/assets/css/all.css" rel="stylesheet" type="text/css"> + <script src="/assets/js/all.js" type="text/javascript"></script> + %else: + <link href="/assets/css/bootstrap.css" rel="stylesheet" type="text/css"> + <link href="/assets/css/bootstrap-responsive.css" rel="stylesheet" type="text/css"> + <link href="/assets/css/rst.css" rel="stylesheet" type="text/css"> + <link href="/assets/css/code.css" rel="stylesheet" type="text/css"> + <link href="/assets/css/colorbox.css" rel="stylesheet" type="text/css"/> + <link href="/assets/css/slides.css" rel="stylesheet" type="text/css"/> + <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"/> + %if has_custom_css: + <link href="/assets/css/custom.css" rel="stylesheet" type="text/css"> + %endif + <script src="/assets/js/jquery-1.7.2.min.js" type="text/javascript"></script> + <script src="/assets/js/jquery.colorbox-min.js" type="text/javascript"></script> + <script src="/assets/js/slides.min.jquery.js" type="text/javascript"></script> + %endif + <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements --> + <!--[if lt IE 9]> + <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script> + <![endif]--> + %if rss_link: + ${rss_link} + %else: + %for language in translations: + <link rel="alternate" type="application/rss+xml" title="RSS (${language})" href="${_link('rss', None, lang)}"> + %endfor + %endif +</%def> + + +<%def name="html_social()"> +%if add_this_buttons: + <!-- Social buttons --> + <div id="addthisbox" class="addthis_toolbox addthis_peekaboo_style addthis_default_style addthis_label_style addthis_32x32_style"> + <a class="addthis_button_more">Share</a> + <ul><li><a class="addthis_button_facebook"></a></li> + <li><a class="addthis_button_google_plusone_share"></a></li> + <li><a class="addthis_button_linkedin"></a></li> + <li><a class="addthis_button_twitter"></a></li> + </ul> + </div> + <script type="text/javascript" src="http://s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script> + <!-- End of social buttons --> +%endif +</%def> + + +<%def name="html_sidebar_links()"> + %for url, text in sidebar_links[lang]: + % if rel_link(permalink, url) == "#": + <li class="active"><a href="${url}">${text}</a> + %else: + <li><a href="${url}">${text}</a> + %endif + %endfor +</%def> + + +<%def name="html_translations()"> + %for langname in translations.keys(): + %if langname != lang: + <a href="${_link("index", None, langname)}">${messages[langname]["LANGUAGE"]}</a> + %endif + %endfor +</%def> diff --git a/nikola/data/themes/default/templates/index.tmpl b/nikola/data/themes/default/templates/index.tmpl index 2c7b4be..03dd1f8 100644 --- a/nikola/data/themes/default/templates/index.tmpl +++ b/nikola/data/themes/default/templates/index.tmpl @@ -1,36 +1,18 @@ ## -*- coding: utf-8 -*- +<%namespace name="helper" file="index_helper.tmpl"/> <%inherit file="base.tmpl"/> <%block name="content"> % for post in posts: <div class="postbox"> <h1><a href="${post.permalink(lang)}">${post.title(lang)}</a> <small> - ${messages[lang]["Posted"]}: ${post.date} + ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} </small></h1> <hr> ${post.text(lang, index_teasers)} - <p> - %if disqus_forum: - <a href="${post.permalink()}#disqus_thread">Comments</a> - %endif + ${helper.html_disqus_link(post)} </div> % endfor - <div> -<ul class="pager"> - %if prevlink: - <li class="previous"> - <a href="${prevlink}">← ${messages[lang]["Newer posts"]}</a> - </li> - %endif - %if nextlink: - <li class="next"> - <a href="${nextlink}">${messages[lang]["Older posts"]} →</a> - </li> - %endif -</ul> - - </div> - %if disqus_forum: - <script type="text/javascript">var disqus_shortname="${disqus_forum}";(function(){var a=document.createElement("script");a.async=true;a.type="text/javascript";a.src="http://"+disqus_shortname+".disqus.com/count.js";(document.getElementsByTagName("HEAD")[0]||document.getElementsByTagName("BODY")[0]).appendChild(a)}());</script> - %endif + ${helper.html_pager()} + ${helper.html_disqus_script()} </%block> diff --git a/nikola/data/themes/default/templates/index_helper.tmpl b/nikola/data/themes/default/templates/index_helper.tmpl new file mode 100644 index 0000000..cfecdf3 --- /dev/null +++ b/nikola/data/themes/default/templates/index_helper.tmpl @@ -0,0 +1,31 @@ +<%def name="html_pager()"> +<div> +<ul class="pager"> + %if prevlink: + <li class="previous"> + <a href="${prevlink}">← ${messages[lang]["Newer posts"]}</a> + </li> + %endif + %if nextlink: + <li class="next"> + <a href="${nextlink}">${messages[lang]["Older posts"]} →</a> + </li> + %endif +</ul> +</div> +</%def> + + +<%def name="html_disqus_link(post)"> + <p> + %if disqus_forum: + <a href="${post.permalink()}#disqus_thread">Comments</a> + %endif +</%def> + + +<%def name="html_disqus_script()"> + %if disqus_forum: + <script type="text/javascript">var disqus_shortname="${disqus_forum}";(function(){var a=document.createElement("script");a.async=true;a.type="text/javascript";a.src="http://"+disqus_shortname+".disqus.com/count.js";(document.getElementsByTagName("HEAD")[0]||document.getElementsByTagName("BODY")[0]).appendChild(a)}());</script> + %endif +</%def> diff --git a/nikola/data/themes/default/templates/list_post.tmpl b/nikola/data/themes/default/templates/list_post.tmpl new file mode 100644 index 0000000..1a1cdee --- /dev/null +++ b/nikola/data/themes/default/templates/list_post.tmpl @@ -0,0 +1,14 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> + <!--Body content--> + <div class="postbox"> + <h1>${title}</h1> + <ul class="unstyled"> + % for post in posts: + <li><a href="${post.permalink(lang)}">[${post.date.strftime(date_format)}] ${post.title(lang)}</a> + % endfor + </ul> + </div> + <!--End of body content--> +</%block> diff --git a/nikola/data/themes/default/templates/post.tmpl b/nikola/data/themes/default/templates/post.tmpl index 6bbb460..306192d 100644 --- a/nikola/data/themes/default/templates/post.tmpl +++ b/nikola/data/themes/default/templates/post.tmpl @@ -1,51 +1,20 @@ ## -*- coding: utf-8 -*- +<%namespace name="helper" file="post_helper.tmpl"/> <%inherit file="base.tmpl"/> <%block name="content"> <div class="postbox"> - <h1><a href='${permalink}'>${title}</a></h1> - % if link: - <p><a href='${link}'>${messages[lang]["Original site"]}</a></p> - % endif + ${helper.html_title()} <hr> <small> - ${messages[lang]["Posted"]}: ${post.date} | - - %if len(translations) > 1: - %for langname in translations.keys(): - %if langname != lang: - <a href="${post.permalink(langname)}">${messages[langname][u"Read in English"]}</a> - | - %endif - %endfor - %endif - - <a href="${post.pagenames[lang]+".txt"}">${messages[lang]["Source"]}</a> - %if post.tags: - | ${messages[lang]["More posts about"]} - %for tag in post.tags: - <a href="${_link("tag", tag, lang)}"><span class="badge badge-info">${tag}</span></a> - %endfor - %endif + ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} + ${helper.html_translations(post)} + | + <a href="${post.pagenames[lang]+'.txt'}">${messages[lang]["Source"]}</a> + ${helper.html_tags(post)} </small> <hr> ${post.text(lang)} - <ul class="pager"> - %if post.prev_post: - <li class="previous"> - <a href="${post.prev_post.permalink(lang)}">← ${messages[lang]["Previous post"]}</a> - </li> - %endif - %if post.next_post: - <li class="next"> - <a href="${post.next_post.permalink(lang)}">${messages[lang]["Next post"]} →</a> - </li> - %endif - </ul> - %if disqus_forum: - <div id="disqus_thread"></div> - <script type="text/javascript">var disqus_shortname="${disqus_forum}";var disqus_url="${post.permalink(absolute=True)}";(function(){var a=document.createElement("script");a.type="text/javascript";a.async=true;a.src="http://"+disqus_shortname+".disqus.com/embed.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a)})(); </script> - <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> - <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> - %endif + ${helper.html_pager(post)} + ${helper.html_disqus(post)} </div> </%block> diff --git a/nikola/data/themes/default/templates/post_helper.tmpl b/nikola/data/themes/default/templates/post_helper.tmpl new file mode 100644 index 0000000..3e874e9 --- /dev/null +++ b/nikola/data/themes/default/templates/post_helper.tmpl @@ -0,0 +1,54 @@ +<%def name="html_title()"> + <h1>${title}</h1> + % if link: + <p><a href='${link}'>${messages[lang]["Original site"]}</a></p> + % endif +</%def> + + +<%def name="html_translations(post)"> + %if len(translations) > 1: + %for langname in translations.keys(): + %if langname != lang: + | + <a href="${post.permalink(langname)}">${messages[langname]["Read in English"]}</a> + %endif + %endfor + %endif +</%def> + + +<%def name="html_tags(post)"> + %if post.tags: + | ${messages[lang]["More posts about"]} + %for tag in post.tags: + <a class="tag" href="${_link('tag', tag, lang)}"><span class="badge badge-info">${tag}</span></a> + %endfor + %endif +</%def> + + +<%def name="html_disqus(post)"> + %if disqus_forum: + <div id="disqus_thread"></div> + <script type="text/javascript">var disqus_shortname="${disqus_forum}";var disqus_url="${post.permalink(absolute=True)}";(function(){var a=document.createElement("script");a.type="text/javascript";a.async=true;a.src="http://"+disqus_shortname+".disqus.com/embed.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a)})(); </script> + <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> + <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> + %endif +</%def> + + +<%def name="html_pager(post)"> + <ul class="pager"> + %if post.prev_post: + <li class="previous"> + <a href="${post.prev_post.permalink(lang)}">← ${messages[lang]["Previous post"]}</a> + </li> + %endif + %if post.next_post: + <li class="next"> + <a href="${post.next_post.permalink(lang)}">${messages[lang]["Next post"]} →</a> + </li> + %endif + </ul> +</%def> diff --git a/nikola/data/themes/default/templates/tag.tmpl b/nikola/data/themes/default/templates/tag.tmpl index ac97829..7c89ad1 100644 --- a/nikola/data/themes/default/templates/tag.tmpl +++ b/nikola/data/themes/default/templates/tag.tmpl @@ -1,5 +1,5 @@ ## -*- coding: utf-8 -*- -<%inherit file="list.tmpl"/> +<%inherit file="list_post.tmpl"/> <%block name="extra_head"> %for language in translations: <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for tag ${tag} (${language})" href="${_link("tag_rss", tag, lang)}"> diff --git a/nikola/data/themes/default/templates/tags.tmpl b/nikola/data/themes/default/templates/tags.tmpl index 10040ca..369a3d5 100644 --- a/nikola/data/themes/default/templates/tags.tmpl +++ b/nikola/data/themes/default/templates/tags.tmpl @@ -6,7 +6,7 @@ <h1>${title}</h1> <ul class="unstyled"> % for text, link in items: - <li><a href="${link}"><span class="badge badge-info">${text}</span></a> + <li><a class="tag" href="${link}"><span class="badge badge-info">${text}</span></a> % endfor </ul> <!--End of body content--> diff --git a/nikola/data/themes/jinja-default/README b/nikola/data/themes/jinja-default/README index 3fb7d3f..4b0bf04 100644 --- a/nikola/data/themes/jinja-default/README +++ b/nikola/data/themes/jinja-default/README @@ -1,3 +1,3 @@ This theme is exactly the same as "default" but using Jinja2 templates. -To try it, set TEMPLATE_ENGINE="jinja" and THEME="jinja-default" in your 'conf.py' +To try it, set THEME="jinja-default" in your 'conf.py' diff --git a/nikola/data/themes/jinja-default/templates/base.tmpl b/nikola/data/themes/jinja-default/templates/base.tmpl index 546e1a7..0f394d3 100644 --- a/nikola/data/themes/jinja-default/templates/base.tmpl +++ b/nikola/data/themes/jinja-default/templates/base.tmpl @@ -17,7 +17,7 @@ <link href="/assets/css/code.css" rel="stylesheet" type="text/css"> <link href="/assets/css/colorbox.css" rel="stylesheet" type="text/css"/> <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"/> - {% if exists("files/assets/css/custom.css", not_empty=True) %} + {% if has_custom_css %} <link href="/assets/css/custom.css" rel="stylesheet"> {% endif %} <script src="/assets/js/jquery-1.7.2.min.js" type="text/javascript"></script> @@ -64,7 +64,7 @@ <hr> </div> <!-- End of banner-like substance !--> - <div class="row" id="contentrow"> + <div class="row-fluid" id="contentrow"> <div class="span10" id="contentcolumn"> <!--Body content--> {% block content %}{% endblock %} @@ -76,20 +76,6 @@ <!--Sidebar content--> <ul class="unstyled"> <li>{{license}} - <!-- social buttons --> -` {% if add_this_buttons %} - <li> - <div id="addthisbox" class="addthis_toolbox addthis_default_style"> - <a class="addthis_button_preferred_1"></a> - <a class="addthis_button_preferred_2"></a> - <a class="addthis_button_preferred_3"></a> - <a class="addthis_button_preferred_4"></a> - <a class="addthis_button_compact"></a> - <a class="addthis_counter addthis_bubble_style"></a> - </div> - <script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script> - <!-- End of social buttons --> - {% endif %} {% for url, text in sidebar_links[lang] %} <li><a href="{{url}}">{{text}}</a> {% endfor %} @@ -97,6 +83,19 @@ </ul> <!--End of sidebar content--> </div> + {% if add_this_buttons %} + <!-- social buttons --> + <div id="addthisbox" class="addthis_toolbox addthis_peekaboo_style addthis_default_style addthis_label_style addthis_32x32_style"> + <a class="addthis_button_more">Share</a> + <ul><li><a class="addthis_button_facebook"></a></li> + <li><a class="addthis_button_google_plusone_share"></a></li> + <li><a class="addthis_button_linkedin"></a></li> + <li><a class="addthis_button_twitter"></a></li> + </ul> + </div> + <script type="text/javascript" src="http://s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script> + <!-- End of social buttons --> + {% endif %} {{analytics}} <script type="text/javascript">jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"80%",maxHeight:"80%",scalePhotos:true});</script> </body> diff --git a/nikola/data/themes/jinja-default/templates/index.tmpl b/nikola/data/themes/jinja-default/templates/index.tmpl index 6244e10..c068417 100644 --- a/nikola/data/themes/jinja-default/templates/index.tmpl +++ b/nikola/data/themes/jinja-default/templates/index.tmpl @@ -4,7 +4,7 @@ <div class="postbox"> <h1><a href="{{post.permalink(lang)}}">{{post.title(lang)}}</a> <small> - {{messages[lang]["Posted"]}}: {{post.date}} + {{messages[lang]["Posted"]}}: {{post.date.strftime(date_format)}} </small></h1> <hr> {{post.text(lang, index_teasers)}} diff --git a/nikola/data/themes/jinja-default/templates/list_post.tmpl b/nikola/data/themes/jinja-default/templates/list_post.tmpl new file mode 100644 index 0000000..7723214 --- /dev/null +++ b/nikola/data/themes/jinja-default/templates/list_post.tmpl @@ -0,0 +1,13 @@ +{% extends "base.tmpl" %} +{% block content %} + <!--Body content--> + <div class="postbox"> + <h1>{{title}}</h1> + <ul class="unstyled"> + {% for post in posts %} + <li><a href="{{post.permalink(lang)}}">[{{post.date.strftime(date_format)}}] {{post.title(lang)}}</a> + {% endfor %} + </ul> + </div> + <!--End of body content--> +{% endblock %} diff --git a/nikola/data/themes/jinja-default/templates/post.tmpl b/nikola/data/themes/jinja-default/templates/post.tmpl index 4748959..3ce6abe 100644 --- a/nikola/data/themes/jinja-default/templates/post.tmpl +++ b/nikola/data/themes/jinja-default/templates/post.tmpl @@ -7,7 +7,7 @@ {% endif %} <hr> <small> - {{messages[lang]["Posted"]}}: {{post.date}} | + {{messages[lang]["Posted"]}}: {{post.date.strftime(date_format)}} | {% if translations|length > 1 %} {% for langname in translations.keys() %} diff --git a/nikola/data/themes/jinja-default/templates/tag.tmpl b/nikola/data/themes/jinja-default/templates/tag.tmpl index 59facb4..42720fd 100644 --- a/nikola/data/themes/jinja-default/templates/tag.tmpl +++ b/nikola/data/themes/jinja-default/templates/tag.tmpl @@ -1,4 +1,4 @@ -{% extends "list.tmpl"%} +{% extends "list_post.tmpl"%} {%block extra_head %} {% for language in translations %} <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for tag {{tag}} ({{language}})" href="{{_link("tag_rss", tag, lang)}}"> diff --git a/nikola/data/themes/monospace/assets/css/code.css b/nikola/data/themes/monospace/assets/css/code.css new file mode 100644 index 0000000..b1d7ace --- /dev/null +++ b/nikola/data/themes/monospace/assets/css/code.css @@ -0,0 +1,62 @@ +pre { word-break: pre; white-space: pre; word-wrap: pre; overflow: auto; max-width: 100%;} +td.linenos { vertical-align: top; width: 4em;} +div.code > pre, .code +{ background: #f8f8f8; white-space: pre;} +.code .c { color: #008800; font-style: italic } /* Comment */ +.code .err { border: 1px solid #FF0000 } /* Error */ +.code .k { color: #AA22FF; font-weight: bold } /* Keyword */ +.code .o { color: #666666 } /* Operator */ +.code .cm { color: #008800; font-style: italic } /* Comment.Multiline */ +.code .cp { color: #008800 } /* Comment.Preproc */ +.code .c1 { color: #008800; font-style: italic } /* Comment.Single */ +.code .cs { color: #008800; font-weight: bold } /* Comment.Special */ +.code .gd { color: #A00000 } /* Generic.Deleted */ +.code .ge { font-style: italic } /* Generic.Emph */ +.code .gr { color: #FF0000 } /* Generic.Error */ +.code .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.code .gi { color: #00A000 } /* Generic.Inserted */ +.code .go { color: #808080 } /* Generic.Output */ +.code .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.code .gs { font-weight: bold } /* Generic.Strong */ +.code .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.code .gt { color: #0040D0 } /* Generic.Traceback */ +.code .kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */ +.code .kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */ +.code .kp { color: #AA22FF } /* Keyword.Pseudo */ +.code .kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */ +.code .kt { color: #AA22FF; font-weight: bold } /* Keyword.Type */ +.code .m { color: #666666 } /* Literal.Number */ +.code .s { color: #BB4444 } /* Literal.String */ +.code .na { color: #BB4444 } /* Name.Attribute */ +.code .nb { color: #AA22FF } /* Name.Builtin */ +.code .nc { color: #0000FF } /* Name.Class */ +.code .no { color: #880000 } /* Name.Constant */ +.code .nd { color: #AA22FF } /* Name.Decorator */ +.code .ni { color: #999999; font-weight: bold } /* Name.Entity */ +.code .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.code .nf { color: #00A000 } /* Name.Function */ +.code .nl { color: #A0A000 } /* Name.Label */ +.code .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.code .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.code .nv { color: #B8860B } /* Name.Variable */ +.code .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.code .mf { color: #666666 } /* Literal.Number.Float */ +.code .mh { color: #666666 } /* Literal.Number.Hex */ +.code .mi { color: #666666 } /* Literal.Number.Integer */ +.code .mo { color: #666666 } /* Literal.Number.Oct */ +.code .sb { color: #BB4444 } /* Literal.String.Backtick */ +.code .sc { color: #BB4444 } /* Literal.String.Char */ +.code .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */ +.code .s2 { color: #BB4444 } /* Literal.String.Double */ +.code .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.code .sh { color: #BB4444 } /* Literal.String.Heredoc */ +.code .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.code .sx { color: #008000 } /* Literal.String.Other */ +.code .sr { color: #BB6688 } /* Literal.String.Regex */ +.code .s1 { color: #BB4444 } /* Literal.String.Single */ +.code .ss { color: #B8860B } /* Literal.String.Symbol */ +.code .bp { color: #AA22FF } /* Name.Builtin.Pseudo */ +.code .vc { color: #B8860B } /* Name.Variable.Class */ +.code .vg { color: #B8860B } /* Name.Variable.Global */ +.code .vi { color: #B8860B } /* Name.Variable.Instance */ +.code .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/nikola/data/themes/monospace/assets/css/colorbox.css b/nikola/data/themes/monospace/assets/css/colorbox.css new file mode 100644 index 0000000..f67c346 --- /dev/null +++ b/nikola/data/themes/monospace/assets/css/colorbox.css @@ -0,0 +1,85 @@ +/*
+ ColorBox Core Style:
+ The following CSS is consistent between example themes and should not be altered.
+*/
+#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
+#cboxOverlay{position:fixed; width:100%; height:100%;}
+#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
+#cboxContent{position:relative;}
+#cboxLoadedContent{overflow:auto;}
+#cboxTitle{margin:0;}
+#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;}
+#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
+.cboxPhoto{float:left; margin:auto; border:0; display:block;}
+.cboxIframe{width:100%; height:100%; display:block; border:0;}
+
+/*
+ User Style:
+ Change the following styles to modify the appearance of ColorBox. They are
+ ordered & tabbed in a way that represents the nesting of the generated HTML.
+*/
+#cboxOverlay{background:url(images/overlay.png) repeat 0 0;}
+#colorbox{}
+ #cboxTopLeft{width:21px; height:21px; background:url(images/controls.png) no-repeat -101px 0;}
+ #cboxTopRight{width:21px; height:21px; background:url(images/controls.png) no-repeat -130px 0;}
+ #cboxBottomLeft{width:21px; height:21px; background:url(images/controls.png) no-repeat -101px -29px;}
+ #cboxBottomRight{width:21px; height:21px; background:url(images/controls.png) no-repeat -130px -29px;}
+ #cboxMiddleLeft{width:21px; background:url(images/controls.png) left top repeat-y;}
+ #cboxMiddleRight{width:21px; background:url(images/controls.png) right top repeat-y;}
+ #cboxTopCenter{height:21px; background:url(images/border.png) 0 0 repeat-x;}
+ #cboxBottomCenter{height:21px; background:url(images/border.png) 0 -29px repeat-x;}
+ #cboxContent{background:#fff; overflow:hidden;}
+ .cboxIframe{background:#fff;}
+ #cboxError{padding:50px; border:1px solid #ccc;}
+ #cboxLoadedContent{margin-bottom:28px;}
+ #cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;}
+ #cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;}
+ #cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;}
+ #cboxPrevious{position:absolute; bottom:0; left:0; background:url(images/controls.png) no-repeat -75px 0; width:25px; height:25px; text-indent:-9999px;}
+ #cboxPrevious:hover{background-position:-75px -25px;}
+ #cboxNext{position:absolute; bottom:0; left:27px; background:url(images/controls.png) no-repeat -50px 0; width:25px; height:25px; text-indent:-9999px;}
+ #cboxNext:hover{background-position:-50px -25px;}
+ #cboxLoadingOverlay{background:url(images/loading_background.png) no-repeat center center;}
+ #cboxLoadingGraphic{background:url(images/loading.gif) no-repeat center center;}
+ #cboxClose{position:absolute; bottom:0; right:0; background:url(images/controls.png) no-repeat -25px 0; width:25px; height:25px; text-indent:-9999px;}
+ #cboxClose:hover{background-position:-25px -25px;}
+
+/*
+ The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill
+ when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to or needed in IE9.
+ See: http://jacklmoore.com/notes/ie-transparency-problems/
+*/
+.cboxIE #cboxTopLeft,
+.cboxIE #cboxTopCenter,
+.cboxIE #cboxTopRight,
+.cboxIE #cboxBottomLeft,
+.cboxIE #cboxBottomCenter,
+.cboxIE #cboxBottomRight,
+.cboxIE #cboxMiddleLeft,
+.cboxIE #cboxMiddleRight {
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF);
+}
+
+/*
+ The following provides PNG transparency support for IE6
+ Feel free to remove this and the /ie6/ directory if you have dropped IE6 support.
+*/
+.cboxIE6 #cboxTopLeft{background:url(images/ie6/borderTopLeft.png);}
+.cboxIE6 #cboxTopCenter{background:url(images/ie6/borderTopCenter.png);}
+.cboxIE6 #cboxTopRight{background:url(images/ie6/borderTopRight.png);}
+.cboxIE6 #cboxBottomLeft{background:url(images/ie6/borderBottomLeft.png);}
+.cboxIE6 #cboxBottomCenter{background:url(images/ie6/borderBottomCenter.png);}
+.cboxIE6 #cboxBottomRight{background:url(images/ie6/borderBottomRight.png);}
+.cboxIE6 #cboxMiddleLeft{background:url(images/ie6/borderMiddleLeft.png);}
+.cboxIE6 #cboxMiddleRight{background:url(images/ie6/borderMiddleRight.png);}
+
+.cboxIE6 #cboxTopLeft,
+.cboxIE6 #cboxTopCenter,
+.cboxIE6 #cboxTopRight,
+.cboxIE6 #cboxBottomLeft,
+.cboxIE6 #cboxBottomCenter,
+.cboxIE6 #cboxBottomRight,
+.cboxIE6 #cboxMiddleLeft,
+.cboxIE6 #cboxMiddleRight {
+ _behavior: expression(this.src = this.src ? this.src : this.currentStyle.backgroundImage.split('"')[1], this.style.background = "none", this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + this.src + ", sizingMethod='scale')");
+}
diff --git a/nikola/data/themes/monospace/assets/css/rst.css b/nikola/data/themes/monospace/assets/css/rst.css new file mode 100644 index 0000000..1f0edcb --- /dev/null +++ b/nikola/data/themes/monospace/assets/css/rst.css @@ -0,0 +1,315 @@ +/* +:Author: David Goodger +:Contact: goodger@users.sourceforge.net +:Date: $Date: 2005-12-18 01:56:14 +0100 (Sun, 18 Dec 2005) $ +:Revision: $Revision: 4224 $ +:Copyright: This stylesheet has been placed in the public domain. + +Default cascading style sheet for the HTML output of Docutils. + +See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to +customize this style sheet. +*/ + +/* used to remove borders from tables and images */ +.borderless, table.borderless td, table.borderless th { + border: 0 } + +table.borderless td, table.borderless th { + /* Override padding for "table.docutils td" with "! important". + The right padding separates the table cells. */ + padding: 0 0.5em 0 0 ! important } + +.first { + /* Override more specific margin styles with "! important". */ + margin-top: 0 ! important } + +.last, .with-subtitle { + margin-bottom: 0 ! important } + +.hidden { + display: none } + +a.toc-backref { + text-decoration: none ; + color: black } + +blockquote.epigraph { + margin: 2em 1em ; } + +dl.docutils dd { + margin-bottom: 0.5em } + +/* Uncomment (and remove this text!) to get bold-faced definition list terms +dl.docutils dt { + font-weight: bold } +*/ + +div.abstract { + margin: 2em 5em } + +div.abstract p.topic-title { + font-weight: bold ; + text-align: center } + +div.admonition, div.attention, div.caution, div.danger, div.error, +div.hint, div.important, div.note, div.tip, div.warning { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #d9edf7; + color: #3a87ad; + border: 1px solid #bce8f1; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +div.admonition p.admonition-title, div.hint p.admonition-title, +div.important p.admonition-title, div.note p.admonition-title, +div.tip p.admonition-title { + font-weight: bold ; + font-family: sans-serif } + +div.attention p.admonition-title, div.caution p.admonition-title, +div.danger p.admonition-title, div.error p.admonition-title, +div.warning p.admonition-title { + color: red ; + font-weight: bold ; + font-family: sans-serif } + +/* Uncomment (and remove this text!) to get reduced vertical space in + compound paragraphs. +div.compound .compound-first, div.compound .compound-middle { + margin-bottom: 0.5em } + +div.compound .compound-last, div.compound .compound-middle { + margin-top: 0.5em } +*/ + +div.dedication { + margin: 2em 5em ; + text-align: center ; + font-style: italic } + +div.dedication p.topic-title { + font-weight: bold ; + font-style: normal } + +div.figure { + text-align: center; + margin-left: 2em ; + margin-right: 2em } + +div.footer, div.header { + clear: both; + font-size: smaller } + +div.line-block { + display: block ; + margin-top: 1em ; + margin-bottom: 1em } + +div.line-block div.line-block { + margin-top: 0 ; + margin-bottom: 0 ; + margin-left: 1.5em } + +div.sidebar { + margin-left: 1em ; + border: medium outset ; + padding: 1em ; + background-color: #ffffee ; + width: 40% ; + float: right ; + clear: right } + +div.sidebar p.rubric { + font-family: sans-serif ; + font-size: medium } + +div.system-messages { + margin: 5em } + +div.system-messages h1 { + color: red } + +div.system-message { + padding: 8px 35px 8px 14px; + margin-bottom: 18px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + border: 1px solid #eed3d7; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + padding: 1em; + background-color: #f2dede; + color: #b94a48; + +} + +div.system-message p.system-message-title { + color: inherit ; + font-weight: bold } + +div.topic { + margin: 2em } + +h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, +h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { + margin-top: 0.4em } + +h1.title { + text-align: center } + +h2.subtitle { + text-align: center } + +hr.docutils { + width: 75% } + +img.align-left { + clear: left } + +img.align-right { + clear: right } + +ol.simple, ul.simple { + margin-bottom: 1em } + +ol.arabic { + list-style: decimal } + +ol.loweralpha { + list-style: lower-alpha } + +ol.upperalpha { + list-style: upper-alpha } + +ol.lowerroman { + list-style: lower-roman } + +ol.upperroman { + list-style: upper-roman } + +p.attribution { + text-align: right ; + margin-left: 50% } + +p.caption { + font-style: italic } + +p.credits { + font-style: italic ; + font-size: smaller } + +p.label { + white-space: nowrap } + +p.rubric { + font-weight: bold ; + font-size: larger ; + color: maroon ; + text-align: center } + +p.sidebar-title { + font-family: sans-serif ; + font-weight: bold ; + font-size: larger } + +p.sidebar-subtitle { + font-family: sans-serif ; + font-weight: bold } + +p.topic-title { + font-weight: bold } + +pre.address { + margin-bottom: 0 ; + margin-top: 0 ; + font-family: serif ; + font-size: 100% } + +pre.literal-block, pre.doctest-block { + margin: 0 0 0 0 ; + background-color: #eeeeee; + padding: 1em; + overflow: auto; +/* font-family: "Courier New", Courier, monospace;*/ +} + +span.classifier { + font-family: sans-serif ; + font-style: oblique } + +span.classifier-delimiter { + font-family: sans-serif ; + font-weight: bold } + +span.interpreted { + font-family: sans-serif } + +span.option { + white-space: nowrap } + +span.pre { + white-space: pre } + +span.problematic { + color: red } + +span.section-subtitle { + /* font-size relative to parent (h1..h6 element) */ + font-size: 80% } + +table.citation { + border-left: solid 1px gray; + margin-left: 1px } + +table.docinfo { + margin: 2em 4em } + +table.docutils { + margin-top: 0.5em ; + margin-bottom: 0.5em } + +table.footnote { + border-left: solid 1px black; + margin-left: 1px } + +table.docutils td, table.docutils th, +table.docinfo td, table.docinfo th { + padding-left: 0.5em ; + padding-right: 0.5em ; + vertical-align: top } + +table.docutils th.field-name, table.docinfo th.docinfo-name { + font-weight: bold ; + text-align: left ; + white-space: nowrap ; + padding-left: 0 } + +h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, +h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { + font-size: 100% } + +tt.docutils { + background-color: #eeeeee } + +ul.auto-toc { + list-style-type: none } + +#blog-title { + font-size: 34pt; + /*margin:0 0.3em -14px;*/ + background-color: #FFF; + font-family: "courier"; + text-align: right; + margin-top: 20px; + margin-bottom: 10px; +} + +img { + margin-top: 12px; + margin-bottom: 12px; +} diff --git a/nikola/data/themes/monospace/assets/css/theme.css b/nikola/data/themes/monospace/assets/css/theme.css new file mode 100644 index 0000000..b66d7bd --- /dev/null +++ b/nikola/data/themes/monospace/assets/css/theme.css @@ -0,0 +1,14 @@ +body { margin:0px; padding:20px 0px; text-align:center; font-family:Monospace; color:#585858; } +.post { margin:0px 0px 30px 0px; padding:0px 0px 30px 0px; border-bottom:1px dotted #C8C8C8; } +.meta { margin:10px; padding:15px; background:#EAEAEA; clear:both; } +#footer { text-align:center; clear:both; margin:30px 0px 0px 0px; padding:30px 0px 0px 0px; border-top:1px dotted #C8C8C8; } +#wrap { margin:0px auto; text-align:left; font-size: 13px; line-height: 1.4; } +#container { float:right; } +#sidebar { overflow:hidden; clear:left; text-align:right; width:250px; height:auto; padding:0px 15px 0px 0px; border-right:1px dotted #C8C8C8; } +#sidebar li { list-style-type:none; } +#sidebar > li { margin:20px 0px; } +#sidebar h1 { border-bottom:1px dotted #C8C8C8; } +#sidebar .description { display:block; width:100%; height:auto; margin:0px 0px 10px 0px; } +h1, h2, h3, h4, h5, h6, h7 { margin:0px; text-transform:uppercase; } +h4, h5, h6 { font-size:14px; } +h1 { padding:0px 0px 15px; margin:0px 0px 15px 0px; } diff --git a/nikola/data/themes/monospace/bundles b/nikola/data/themes/monospace/bundles new file mode 100644 index 0000000..aa35d9c --- /dev/null +++ b/nikola/data/themes/monospace/bundles @@ -0,0 +1 @@ +assets/css/all.css=rst.css,code.css,theme.css diff --git a/nikola/data/themes/monospace/messages b/nikola/data/themes/monospace/messages new file mode 120000 index 0000000..3047ea2 --- /dev/null +++ b/nikola/data/themes/monospace/messages @@ -0,0 +1 @@ +../default/messages/
\ No newline at end of file diff --git a/nikola/data/themes/monospace/templates/base.tmpl b/nikola/data/themes/monospace/templates/base.tmpl new file mode 100644 index 0000000..7758ded --- /dev/null +++ b/nikola/data/themes/monospace/templates/base.tmpl @@ -0,0 +1,44 @@ +## -*- coding: utf-8 -*- +<%namespace file="base_helper.tmpl" import="*"/> +<!DOCTYPE html> +<html lang="${lang}"> +<head> + ${html_head()} + <%block name="extra_head"> + </%block> +</head> +<body class="home blog"> + %if add_this_buttons: + <script type="text/javascript">var addthis_config={"ui_language":"${lang}"};</script> + % endif + <div id="wrap" style="width:850px"> + <div id="container" style="width:560px"> + <%block name="content"></%block> + </div> + <div id="sidebar"> + <!--Sidebar content--> + <h1 id="blog-title"> + <a href="${abs_link('/')}" title="${blog_title}">${blog_title}</a> + </h1> + <%block name="belowtitle"> + %if len(translations) > 1: + <small> + ${(messages[lang][u"Also available in"])}: + ${html_translations()} + </small> + %endif + </%block> + <ul class="unstyled"> + <li>${license} + ${html_social()} + ${html_sidebar_links()} + <li>${search_form} + </ul> + </div> + <div id="footer"> + ${content_footer} + </div> + </div> + ${analytics} + <script type="text/javascript">jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"80%",maxHeight:"80%",scalePhotos:true});</script> +</body> diff --git a/nikola/data/themes/monospace/templates/base_helper.tmpl b/nikola/data/themes/monospace/templates/base_helper.tmpl new file mode 100644 index 0000000..f5fe80c --- /dev/null +++ b/nikola/data/themes/monospace/templates/base_helper.tmpl @@ -0,0 +1,64 @@ +<%def name="html_head()"> + <meta charset="utf-8"> + <meta name="title" content="${title} | ${blog_title}" > + <meta name="description" content="${description}" > + <meta name="author" content="${blog_author}"> + <title>${title} | ${blog_title}</title> + %if use_bundles: +<!-- CSS and JS Bundles here --> + <link href="/assets/css/all.css" rel="stylesheet" type="text/css"> + %else: +<!-- CSS and JS here --> + <link href="/assets/css/rst.css" rel="stylesheet" type="text/css"> + <link href="/assets/css/code.css" rel="stylesheet" type="text/css"> + <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"/> + %if has_custom_css: +<!-- Custom CSS here --> + <link href="/assets/css/custom.css" rel="stylesheet" type="text/css"> + %endif + %endif + %if rss_link: + ${rss_link} + %else: + %for language in translations: + <link rel="alternate" type="application/rss+xml" title="RSS (${language})" href="${_link('rss', None, lang)}"> + %endfor + %endif +</%def> + + +<%def name="html_social()"> +%if add_this_buttons: + <!-- Social buttons --> + <div id="addthisbox" class="addthis_toolbox addthis_peekaboo_style addthis_default_style addthis_label_style addthis_32x32_style"> + <a class="addthis_button_more">Share</a> + <ul><li><a class="addthis_button_facebook"></a></li> + <li><a class="addthis_button_google_plusone_share"></a></li> + <li><a class="addthis_button_linkedin"></a></li> + <li><a class="addthis_button_twitter"></a></li> + </ul> + </div> + <script type="text/javascript" src="http://s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script> + <!-- End of social buttons --> +%endif +</%def> + + +<%def name="html_sidebar_links()"> + %for url, text in sidebar_links[lang]: + % if rel_link(permalink, url) == "#": + <li class="active"><a href="${url}">${text}</a> + %else: + <li><a href="${url}">${text}</a> + %endif + %endfor +</%def> + + +<%def name="html_translations()"> + %for langname in translations.keys(): + %if langname != lang: + <a href="${_link("index", None, langname)}">${messages[langname]["LANGUAGE"]}</a> + %endif + %endfor +</%def> diff --git a/nikola/data/themes/monospace/templates/gallery.tmpl b/nikola/data/themes/monospace/templates/gallery.tmpl new file mode 100644 index 0000000..37d749f --- /dev/null +++ b/nikola/data/themes/monospace/templates/gallery.tmpl @@ -0,0 +1,27 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="sourcelink"></%block> + +<%block name="content"> + <ul class="breadcrumb"> + % for link, crumb in crumbs: + <li><a href="${link}">/ ${crumb}</a></li> + % endfor + </ul> + %if text: + <p> + ${text} + </p> + %endif + <ul> + % for folder in folders: + <li><a href="${folder}"><i class="icon-folder-open"></i> ${folder}</a></li> + % endfor + </ul> + <ul class="thumbnails"> + %for image in images: + <li><a href="${image[0]}" class="thumbnail image-reference" ${image[2]}> + <img src="${image[1]}" /></a></li> + %endfor + </ul> +</%block> diff --git a/nikola/data/themes/monospace/templates/index.tmpl b/nikola/data/themes/monospace/templates/index.tmpl new file mode 100644 index 0000000..bbf5529 --- /dev/null +++ b/nikola/data/themes/monospace/templates/index.tmpl @@ -0,0 +1,27 @@ +## -*- coding: utf-8 -*- +<%namespace name="helper" file="index_helper.tmpl"/> +<%inherit file="base.tmpl"/> +<%block name="content"> + % for post in posts: + <div class="postbox"> + <h1><a href="${post.permalink(lang)}">${post.title(lang)}</a></h1> + <div class="meta" style="background-color: rgb(234, 234, 234); "> + <span class="authordate"> + ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} + </span> + <br> + <span class="tags">Tags: + %if post.tags: + %for tag in post.tags: + <a class="tag" href="${_link('tag', tag, lang)}"><span class="badge badge-info">${tag}</span></a> + %endfor + %endif + </span> + </div> + ${post.text(lang, index_teasers)} + ${helper.html_disqus_link(post)} + </div> + % endfor + ${helper.html_pager()} + ${helper.html_disqus_script()} +</%block> diff --git a/nikola/data/themes/monospace/templates/index_helper.tmpl b/nikola/data/themes/monospace/templates/index_helper.tmpl new file mode 100644 index 0000000..cfecdf3 --- /dev/null +++ b/nikola/data/themes/monospace/templates/index_helper.tmpl @@ -0,0 +1,31 @@ +<%def name="html_pager()"> +<div> +<ul class="pager"> + %if prevlink: + <li class="previous"> + <a href="${prevlink}">← ${messages[lang]["Newer posts"]}</a> + </li> + %endif + %if nextlink: + <li class="next"> + <a href="${nextlink}">${messages[lang]["Older posts"]} →</a> + </li> + %endif +</ul> +</div> +</%def> + + +<%def name="html_disqus_link(post)"> + <p> + %if disqus_forum: + <a href="${post.permalink()}#disqus_thread">Comments</a> + %endif +</%def> + + +<%def name="html_disqus_script()"> + %if disqus_forum: + <script type="text/javascript">var disqus_shortname="${disqus_forum}";(function(){var a=document.createElement("script");a.async=true;a.type="text/javascript";a.src="http://"+disqus_shortname+".disqus.com/count.js";(document.getElementsByTagName("HEAD")[0]||document.getElementsByTagName("BODY")[0]).appendChild(a)}());</script> + %endif +</%def> diff --git a/nikola/data/themes/monospace/templates/list.tmpl b/nikola/data/themes/monospace/templates/list.tmpl new file mode 100644 index 0000000..a60b508 --- /dev/null +++ b/nikola/data/themes/monospace/templates/list.tmpl @@ -0,0 +1,14 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> + <!--Body content--> + <div class="postbox"> + <h1>${title}</h1> + <ul class="unstyled"> + % for text, link in items: + <li><a href="${link}">${text}</a> + % endfor + </ul> + </div> + <!--End of body content--> +</%block> diff --git a/nikola/data/themes/monospace/templates/list_post.tmpl b/nikola/data/themes/monospace/templates/list_post.tmpl new file mode 100644 index 0000000..1a1cdee --- /dev/null +++ b/nikola/data/themes/monospace/templates/list_post.tmpl @@ -0,0 +1,14 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> + <!--Body content--> + <div class="postbox"> + <h1>${title}</h1> + <ul class="unstyled"> + % for post in posts: + <li><a href="${post.permalink(lang)}">[${post.date.strftime(date_format)}] ${post.title(lang)}</a> + % endfor + </ul> + </div> + <!--End of body content--> +</%block> diff --git a/nikola/data/themes/monospace/templates/listing.tmpl b/nikola/data/themes/monospace/templates/listing.tmpl new file mode 100644 index 0000000..596a704 --- /dev/null +++ b/nikola/data/themes/monospace/templates/listing.tmpl @@ -0,0 +1,10 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> +<ul class="breadcrumb"> + % for link, crumb in crumbs: + <li><a href="${link}">/ ${crumb}</a></li> + % endfor +</ul> +${code} +</%block> diff --git a/nikola/data/themes/monospace/templates/post.tmpl b/nikola/data/themes/monospace/templates/post.tmpl new file mode 100644 index 0000000..94a74f8 --- /dev/null +++ b/nikola/data/themes/monospace/templates/post.tmpl @@ -0,0 +1,28 @@ +## -*- coding: utf-8 -*- +<%namespace name="helper" file="post_helper.tmpl"/> +<%inherit file="base.tmpl"/> +<%block name="content"> + <div class="post"> + ${helper.html_title()} + <div class="meta" style="background-color: rgb(234, 234, 234); "> + <span class="authordate"> + ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} [<a href="${post.pagenames[lang]+'.txt'}">${messages[lang]["Source"]}</a>] + </span> + <br> + %if post.tags: + <span class="tags">${messages[lang]["Tags"]}: + %for tag in post.tags: + <a class="tag" href="${_link('tag', tag, lang)}"><span class="badge badge-info">${tag}</span></a> + %endfor + </span> + <br> + %endif + <span class="authordate"> + ${helper.html_translations(post)} + </span> + </div> + ${post.text(lang)} + ${helper.html_pager(post)} + ${helper.html_disqus(post)} + </div> +</%block> diff --git a/nikola/data/themes/monospace/templates/post_helper.tmpl b/nikola/data/themes/monospace/templates/post_helper.tmpl new file mode 100644 index 0000000..3e874e9 --- /dev/null +++ b/nikola/data/themes/monospace/templates/post_helper.tmpl @@ -0,0 +1,54 @@ +<%def name="html_title()"> + <h1>${title}</h1> + % if link: + <p><a href='${link}'>${messages[lang]["Original site"]}</a></p> + % endif +</%def> + + +<%def name="html_translations(post)"> + %if len(translations) > 1: + %for langname in translations.keys(): + %if langname != lang: + | + <a href="${post.permalink(langname)}">${messages[langname]["Read in English"]}</a> + %endif + %endfor + %endif +</%def> + + +<%def name="html_tags(post)"> + %if post.tags: + | ${messages[lang]["More posts about"]} + %for tag in post.tags: + <a class="tag" href="${_link('tag', tag, lang)}"><span class="badge badge-info">${tag}</span></a> + %endfor + %endif +</%def> + + +<%def name="html_disqus(post)"> + %if disqus_forum: + <div id="disqus_thread"></div> + <script type="text/javascript">var disqus_shortname="${disqus_forum}";var disqus_url="${post.permalink(absolute=True)}";(function(){var a=document.createElement("script");a.type="text/javascript";a.async=true;a.src="http://"+disqus_shortname+".disqus.com/embed.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a)})(); </script> + <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> + <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> + %endif +</%def> + + +<%def name="html_pager(post)"> + <ul class="pager"> + %if post.prev_post: + <li class="previous"> + <a href="${post.prev_post.permalink(lang)}">← ${messages[lang]["Previous post"]}</a> + </li> + %endif + %if post.next_post: + <li class="next"> + <a href="${post.next_post.permalink(lang)}">${messages[lang]["Next post"]} →</a> + </li> + %endif + </ul> +</%def> diff --git a/nikola/data/themes/monospace/templates/story.tmpl b/nikola/data/themes/monospace/templates/story.tmpl new file mode 100644 index 0000000..deb0a46 --- /dev/null +++ b/nikola/data/themes/monospace/templates/story.tmpl @@ -0,0 +1,8 @@ +## -*- coding: utf-8 -*- +<%inherit file="post.tmpl"/> +<%block name="content"> +%if title: + <h1>${title}</h1> +%endif + ${post.text(lang)} +</%block> diff --git a/nikola/data/themes/monospace/templates/tag.tmpl b/nikola/data/themes/monospace/templates/tag.tmpl new file mode 100644 index 0000000..7c89ad1 --- /dev/null +++ b/nikola/data/themes/monospace/templates/tag.tmpl @@ -0,0 +1,7 @@ +## -*- coding: utf-8 -*- +<%inherit file="list_post.tmpl"/> +<%block name="extra_head"> + %for language in translations: + <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for tag ${tag} (${language})" href="${_link("tag_rss", tag, lang)}"> + %endfor +</%block> diff --git a/nikola/data/themes/monospace/templates/tags.tmpl b/nikola/data/themes/monospace/templates/tags.tmpl new file mode 100644 index 0000000..369a3d5 --- /dev/null +++ b/nikola/data/themes/monospace/templates/tags.tmpl @@ -0,0 +1,14 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> + <div class="postbox"> + <!--Body content--> + <h1>${title}</h1> + <ul class="unstyled"> + % for text, link in items: + <li><a class="tag" href="${link}"><span class="badge badge-info">${text}</span></a> + % endfor + </ul> + <!--End of body content--> + </div> +</%block> diff --git a/nikola/data/themes/orphan/assets/css/code.css b/nikola/data/themes/orphan/assets/css/code.css new file mode 120000 index 0000000..6b2b872 --- /dev/null +++ b/nikola/data/themes/orphan/assets/css/code.css @@ -0,0 +1 @@ +../../../default/assets/css/code.css
\ No newline at end of file diff --git a/nikola/data/themes/orphan/assets/css/colorbox.css b/nikola/data/themes/orphan/assets/css/colorbox.css new file mode 120000 index 0000000..2c48dd8 --- /dev/null +++ b/nikola/data/themes/orphan/assets/css/colorbox.css @@ -0,0 +1 @@ +../../../default/assets/css/colorbox.css
\ No newline at end of file diff --git a/nikola/data/themes/orphan/assets/css/rst.css b/nikola/data/themes/orphan/assets/css/rst.css new file mode 120000 index 0000000..2e56146 --- /dev/null +++ b/nikola/data/themes/orphan/assets/css/rst.css @@ -0,0 +1 @@ +../../../default/assets/css/rst.css
\ No newline at end of file diff --git a/nikola/data/themes/orphan/assets/css/theme.css b/nikola/data/themes/orphan/assets/css/theme.css new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/nikola/data/themes/orphan/assets/css/theme.css diff --git a/nikola/data/themes/orphan/bundles b/nikola/data/themes/orphan/bundles new file mode 100644 index 0000000..aa35d9c --- /dev/null +++ b/nikola/data/themes/orphan/bundles @@ -0,0 +1 @@ +assets/css/all.css=rst.css,code.css,theme.css diff --git a/nikola/data/themes/orphan/messages b/nikola/data/themes/orphan/messages new file mode 120000 index 0000000..3047ea2 --- /dev/null +++ b/nikola/data/themes/orphan/messages @@ -0,0 +1 @@ +../default/messages/
\ No newline at end of file diff --git a/nikola/data/themes/orphan/templates/base.tmpl b/nikola/data/themes/orphan/templates/base.tmpl new file mode 100644 index 0000000..f280d08 --- /dev/null +++ b/nikola/data/themes/orphan/templates/base.tmpl @@ -0,0 +1,36 @@ +## -*- coding: utf-8 -*- +<%namespace file="base_helper.tmpl" import="*"/> +<!DOCTYPE html> +<html lang="${lang}"> +<head> + ${html_head()} + <%block name="extra_head"> + </%block> +</head> +<body> + %if add_this_buttons: + <script type="text/javascript">var addthis_config={"ui_language":"${lang}"};</script> + % endif + <h1 id="blog-title"> + <a href="${abs_link('/')}" title="${blog_title}">${blog_title}</a> + </h1> + <%block name="belowtitle"> + %if len(translations) > 1: + <small> + ${(messages[lang][u"Also available in"])}: + ${html_translations()} + </small> + %endif + </%block> + <%block name="content"></%block> + <small>${content_footer}</small> + <!--Sidebar content--> + <ul class="unstyled"> + <li>${license} + ${html_social()} + ${html_sidebar_links()} + <li>${search_form} + </ul> + ${analytics} + <script type="text/javascript">jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"80%",maxHeight:"80%",scalePhotos:true});</script> +</body> diff --git a/nikola/data/themes/orphan/templates/base_helper.tmpl b/nikola/data/themes/orphan/templates/base_helper.tmpl new file mode 100644 index 0000000..f5fe80c --- /dev/null +++ b/nikola/data/themes/orphan/templates/base_helper.tmpl @@ -0,0 +1,64 @@ +<%def name="html_head()"> + <meta charset="utf-8"> + <meta name="title" content="${title} | ${blog_title}" > + <meta name="description" content="${description}" > + <meta name="author" content="${blog_author}"> + <title>${title} | ${blog_title}</title> + %if use_bundles: +<!-- CSS and JS Bundles here --> + <link href="/assets/css/all.css" rel="stylesheet" type="text/css"> + %else: +<!-- CSS and JS here --> + <link href="/assets/css/rst.css" rel="stylesheet" type="text/css"> + <link href="/assets/css/code.css" rel="stylesheet" type="text/css"> + <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"/> + %if has_custom_css: +<!-- Custom CSS here --> + <link href="/assets/css/custom.css" rel="stylesheet" type="text/css"> + %endif + %endif + %if rss_link: + ${rss_link} + %else: + %for language in translations: + <link rel="alternate" type="application/rss+xml" title="RSS (${language})" href="${_link('rss', None, lang)}"> + %endfor + %endif +</%def> + + +<%def name="html_social()"> +%if add_this_buttons: + <!-- Social buttons --> + <div id="addthisbox" class="addthis_toolbox addthis_peekaboo_style addthis_default_style addthis_label_style addthis_32x32_style"> + <a class="addthis_button_more">Share</a> + <ul><li><a class="addthis_button_facebook"></a></li> + <li><a class="addthis_button_google_plusone_share"></a></li> + <li><a class="addthis_button_linkedin"></a></li> + <li><a class="addthis_button_twitter"></a></li> + </ul> + </div> + <script type="text/javascript" src="http://s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script> + <!-- End of social buttons --> +%endif +</%def> + + +<%def name="html_sidebar_links()"> + %for url, text in sidebar_links[lang]: + % if rel_link(permalink, url) == "#": + <li class="active"><a href="${url}">${text}</a> + %else: + <li><a href="${url}">${text}</a> + %endif + %endfor +</%def> + + +<%def name="html_translations()"> + %for langname in translations.keys(): + %if langname != lang: + <a href="${_link("index", None, langname)}">${messages[langname]["LANGUAGE"]}</a> + %endif + %endfor +</%def> diff --git a/nikola/data/themes/orphan/templates/gallery.tmpl b/nikola/data/themes/orphan/templates/gallery.tmpl new file mode 100644 index 0000000..37d749f --- /dev/null +++ b/nikola/data/themes/orphan/templates/gallery.tmpl @@ -0,0 +1,27 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="sourcelink"></%block> + +<%block name="content"> + <ul class="breadcrumb"> + % for link, crumb in crumbs: + <li><a href="${link}">/ ${crumb}</a></li> + % endfor + </ul> + %if text: + <p> + ${text} + </p> + %endif + <ul> + % for folder in folders: + <li><a href="${folder}"><i class="icon-folder-open"></i> ${folder}</a></li> + % endfor + </ul> + <ul class="thumbnails"> + %for image in images: + <li><a href="${image[0]}" class="thumbnail image-reference" ${image[2]}> + <img src="${image[1]}" /></a></li> + %endfor + </ul> +</%block> diff --git a/nikola/data/themes/orphan/templates/index.tmpl b/nikola/data/themes/orphan/templates/index.tmpl new file mode 100644 index 0000000..03dd1f8 --- /dev/null +++ b/nikola/data/themes/orphan/templates/index.tmpl @@ -0,0 +1,18 @@ +## -*- coding: utf-8 -*- +<%namespace name="helper" file="index_helper.tmpl"/> +<%inherit file="base.tmpl"/> +<%block name="content"> + % for post in posts: + <div class="postbox"> + <h1><a href="${post.permalink(lang)}">${post.title(lang)}</a> + <small> + ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} + </small></h1> + <hr> + ${post.text(lang, index_teasers)} + ${helper.html_disqus_link(post)} + </div> + % endfor + ${helper.html_pager()} + ${helper.html_disqus_script()} +</%block> diff --git a/nikola/data/themes/orphan/templates/index_helper.tmpl b/nikola/data/themes/orphan/templates/index_helper.tmpl new file mode 100644 index 0000000..cfecdf3 --- /dev/null +++ b/nikola/data/themes/orphan/templates/index_helper.tmpl @@ -0,0 +1,31 @@ +<%def name="html_pager()"> +<div> +<ul class="pager"> + %if prevlink: + <li class="previous"> + <a href="${prevlink}">← ${messages[lang]["Newer posts"]}</a> + </li> + %endif + %if nextlink: + <li class="next"> + <a href="${nextlink}">${messages[lang]["Older posts"]} →</a> + </li> + %endif +</ul> +</div> +</%def> + + +<%def name="html_disqus_link(post)"> + <p> + %if disqus_forum: + <a href="${post.permalink()}#disqus_thread">Comments</a> + %endif +</%def> + + +<%def name="html_disqus_script()"> + %if disqus_forum: + <script type="text/javascript">var disqus_shortname="${disqus_forum}";(function(){var a=document.createElement("script");a.async=true;a.type="text/javascript";a.src="http://"+disqus_shortname+".disqus.com/count.js";(document.getElementsByTagName("HEAD")[0]||document.getElementsByTagName("BODY")[0]).appendChild(a)}());</script> + %endif +</%def> diff --git a/nikola/data/themes/orphan/templates/list.tmpl b/nikola/data/themes/orphan/templates/list.tmpl new file mode 100644 index 0000000..a60b508 --- /dev/null +++ b/nikola/data/themes/orphan/templates/list.tmpl @@ -0,0 +1,14 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> + <!--Body content--> + <div class="postbox"> + <h1>${title}</h1> + <ul class="unstyled"> + % for text, link in items: + <li><a href="${link}">${text}</a> + % endfor + </ul> + </div> + <!--End of body content--> +</%block> diff --git a/nikola/data/themes/orphan/templates/list_post.tmpl b/nikola/data/themes/orphan/templates/list_post.tmpl new file mode 100644 index 0000000..1a1cdee --- /dev/null +++ b/nikola/data/themes/orphan/templates/list_post.tmpl @@ -0,0 +1,14 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> + <!--Body content--> + <div class="postbox"> + <h1>${title}</h1> + <ul class="unstyled"> + % for post in posts: + <li><a href="${post.permalink(lang)}">[${post.date.strftime(date_format)}] ${post.title(lang)}</a> + % endfor + </ul> + </div> + <!--End of body content--> +</%block> diff --git a/nikola/data/themes/orphan/templates/listing.tmpl b/nikola/data/themes/orphan/templates/listing.tmpl new file mode 100644 index 0000000..596a704 --- /dev/null +++ b/nikola/data/themes/orphan/templates/listing.tmpl @@ -0,0 +1,10 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> +<ul class="breadcrumb"> + % for link, crumb in crumbs: + <li><a href="${link}">/ ${crumb}</a></li> + % endfor +</ul> +${code} +</%block> diff --git a/nikola/data/themes/orphan/templates/post.tmpl b/nikola/data/themes/orphan/templates/post.tmpl new file mode 100644 index 0000000..306192d --- /dev/null +++ b/nikola/data/themes/orphan/templates/post.tmpl @@ -0,0 +1,20 @@ +## -*- coding: utf-8 -*- +<%namespace name="helper" file="post_helper.tmpl"/> +<%inherit file="base.tmpl"/> +<%block name="content"> + <div class="postbox"> + ${helper.html_title()} + <hr> + <small> + ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} + ${helper.html_translations(post)} + | + <a href="${post.pagenames[lang]+'.txt'}">${messages[lang]["Source"]}</a> + ${helper.html_tags(post)} + </small> + <hr> + ${post.text(lang)} + ${helper.html_pager(post)} + ${helper.html_disqus(post)} + </div> +</%block> diff --git a/nikola/data/themes/orphan/templates/post_helper.tmpl b/nikola/data/themes/orphan/templates/post_helper.tmpl new file mode 100644 index 0000000..3e874e9 --- /dev/null +++ b/nikola/data/themes/orphan/templates/post_helper.tmpl @@ -0,0 +1,54 @@ +<%def name="html_title()"> + <h1>${title}</h1> + % if link: + <p><a href='${link}'>${messages[lang]["Original site"]}</a></p> + % endif +</%def> + + +<%def name="html_translations(post)"> + %if len(translations) > 1: + %for langname in translations.keys(): + %if langname != lang: + | + <a href="${post.permalink(langname)}">${messages[langname]["Read in English"]}</a> + %endif + %endfor + %endif +</%def> + + +<%def name="html_tags(post)"> + %if post.tags: + | ${messages[lang]["More posts about"]} + %for tag in post.tags: + <a class="tag" href="${_link('tag', tag, lang)}"><span class="badge badge-info">${tag}</span></a> + %endfor + %endif +</%def> + + +<%def name="html_disqus(post)"> + %if disqus_forum: + <div id="disqus_thread"></div> + <script type="text/javascript">var disqus_shortname="${disqus_forum}";var disqus_url="${post.permalink(absolute=True)}";(function(){var a=document.createElement("script");a.type="text/javascript";a.async=true;a.src="http://"+disqus_shortname+".disqus.com/embed.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a)})(); </script> + <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> + <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> + %endif +</%def> + + +<%def name="html_pager(post)"> + <ul class="pager"> + %if post.prev_post: + <li class="previous"> + <a href="${post.prev_post.permalink(lang)}">← ${messages[lang]["Previous post"]}</a> + </li> + %endif + %if post.next_post: + <li class="next"> + <a href="${post.next_post.permalink(lang)}">${messages[lang]["Next post"]} →</a> + </li> + %endif + </ul> +</%def> diff --git a/nikola/data/themes/orphan/templates/story.tmpl b/nikola/data/themes/orphan/templates/story.tmpl new file mode 100644 index 0000000..deb0a46 --- /dev/null +++ b/nikola/data/themes/orphan/templates/story.tmpl @@ -0,0 +1,8 @@ +## -*- coding: utf-8 -*- +<%inherit file="post.tmpl"/> +<%block name="content"> +%if title: + <h1>${title}</h1> +%endif + ${post.text(lang)} +</%block> diff --git a/nikola/data/themes/orphan/templates/tag.tmpl b/nikola/data/themes/orphan/templates/tag.tmpl new file mode 100644 index 0000000..7c89ad1 --- /dev/null +++ b/nikola/data/themes/orphan/templates/tag.tmpl @@ -0,0 +1,7 @@ +## -*- coding: utf-8 -*- +<%inherit file="list_post.tmpl"/> +<%block name="extra_head"> + %for language in translations: + <link rel="alternate" type="application/rss+xml" type="application/rss+xml" title="RSS for tag ${tag} (${language})" href="${_link("tag_rss", tag, lang)}"> + %endfor +</%block> diff --git a/nikola/data/themes/orphan/templates/tags.tmpl b/nikola/data/themes/orphan/templates/tags.tmpl new file mode 100644 index 0000000..369a3d5 --- /dev/null +++ b/nikola/data/themes/orphan/templates/tags.tmpl @@ -0,0 +1,14 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> + <div class="postbox"> + <!--Body content--> + <h1>${title}</h1> + <ul class="unstyled"> + % for text, link in items: + <li><a class="tag" href="${link}"><span class="badge badge-info">${text}</span></a> + % endfor + </ul> + <!--End of body content--> + </div> +</%block> diff --git a/nikola/data/themes/site/assets/css/theme.css b/nikola/data/themes/site/assets/css/theme.css index 6b21e2e..32c9f24 100644 --- a/nikola/data/themes/site/assets/css/theme.css +++ b/nikola/data/themes/site/assets/css/theme.css @@ -1,5 +1,11 @@ -body { margin-top: 50px;} - +body { + padding-top: 60px; +} +@media (max-width: 979px) { + body { + padding-top: 0px; + } +} #container { width: 960px; margin: 50 auto; @@ -23,5 +29,3 @@ img { .footerbox {padding: 15px; text-align: center; margin-bottom: 15px;} -#addthisbox {top: 180px; left:10px;} - diff --git a/nikola/data/themes/site/templates/base.tmpl b/nikola/data/themes/site/templates/base.tmpl index 46e9b39..784f29a 100644 --- a/nikola/data/themes/site/templates/base.tmpl +++ b/nikola/data/themes/site/templates/base.tmpl @@ -1,40 +1,9 @@ ## -*- coding: utf-8 -*- +<%namespace file="base_helper.tmpl" import="*"/> <!DOCTYPE html> <html lang="${lang}"> <head> - <meta charset="utf-8"> - <meta name="title" content="${title} | ${blog_title}" > - <meta name="description" content="${description}" > - <meta name="author" content="${blog_author}"> - <title>${title} | ${blog_title}</title> - <!-- Le styles --> - %if use_bundles: - <link href="/assets/css/all.css" rel="stylesheet" type="text/css"> - <script src="/assets/js/all.js" type="text/javascript"></script> - %else: - <link href="/assets/css/bootstrap.css" rel="stylesheet" type="text/css"> - <link href="/assets/css/bootstrap-responsive.css" rel="stylesheet" type="text/css"> - <link href="/assets/css/rst.css" rel="stylesheet" type="text/css"> - <link href="/assets/css/code.css" rel="stylesheet" type="text/css"> - <link href="/assets/css/colorbox.css" rel="stylesheet" type="text/css"/> - <link href="/assets/css/theme.css" rel="stylesheet" type="text/css"/> - %if exists("files/assets/css/custom.css", not_empty=True): - <link href="/assets/css/custom.css" rel="stylesheet" type="text/css"> - %endif - <script src="/assets/js/jquery-1.7.2.min.js" type="text/javascript"></script> - <script src="/assets/js/jquery.colorbox-min.js" type="text/javascript"></script> - %endif - <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements --> - <!--[if lt IE 9]> - <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> - <![endif]--> - %if rss_link: - ${rss_link} - %else: - %for language in translations: - <link rel="alternate" type="application/rss+xml" title="RSS (${language})" href="${_link("rss", None, lang)}"> - %endfor - %endif + ${html_head()} <%block name="extra_head"> </%block> </head> @@ -47,13 +16,7 @@ ${blog_title} </a> <ul class="nav"> - %for url, text in sidebar_links[lang]: - % if rel_link(permalink, url) == "#": - <li class="active"><a href="${url}">${text}</a> - %else: - <li><a href="${url}">${text}</a> - %endif - %endfor + ${html_sidebar_links()} </ul> %if search_form: ${search_form} @@ -61,13 +24,7 @@ <ul class="nav pull-right"> <%block name="belowtitle"> %if len(translations) > 1: - <li> - %for langname in translations.keys(): - %if langname != lang: - <a href="${_link("index", None, langname)}">${messages[langname]["LANGUAGE"]}</a> - %endif - %endfor - </li> + <li>${html_translations()}</li> %endif </%block> <%block name="sourcelink"> </%block> @@ -76,7 +33,6 @@ </div> </div> <!-- End of Menubar --> - <div class="container" id="container"> <!--Body content--> <%block name="content"></%block> @@ -85,20 +41,7 @@ ${content_footer} </div> </div> - %if add_this_buttons: - <!-- addthis --> - <div id="addthisbox" class="addthis_bar addthis_bar_vertical addthis_bar_small"> - <div class="addthis_toolbox addthis_default_style"> - <span><a class="addthis_button_preferred_1"></a></span> - <span><a class="addthis_button_preferred_2"></a></span> - <span><a class="addthis_button_preferred_3"></a></span> - <span><a class="addthis_button_preferred_4"></a></span> - <span><a class="addthis_button_compact"></a></span> - </div> - </div> - <script type="text/javascript" src="http://s7.addthis.com/js/300/addthis_widget.js#pubid=ra-4f7088a56bb93798"></script> - <!-- End of addthis --> - %endif +${html_social()} ${analytics} <script type="text/javascript">jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"80%",maxHeight:"80%",scalePhotos:true});</script> </body> diff --git a/nikola/data/themes/site/templates/post.tmpl b/nikola/data/themes/site/templates/post.tmpl index f777366..06ca10f 100644 --- a/nikola/data/themes/site/templates/post.tmpl +++ b/nikola/data/themes/site/templates/post.tmpl @@ -1,50 +1,19 @@ ## -*- coding: utf-8 -*- +<%namespace name="helper" file="post_helper.tmpl"/> <%inherit file="base.tmpl"/> <%block name="content"> <div class="postbox"> - <h1>${title}</h1> - % if link: - <p><a href='${link}'>${messages[lang]["Original site"]}</a></p> - % endif + ${helper.html_title()} <hr> <small> - ${messages[lang]["Posted"]}: ${post.date} - - %if len(translations) > 1: - %for langname in translations.keys(): - %if langname != lang: - | - <a href="${post.permalink(langname)}">${messages[langname][u"Read in English"]}</a> - %endif - %endfor - %endif - %if post.tags: - | ${messages[lang]["More posts about"]} - %for tag in post.tags: - <a href="${_link("tag", tag, lang)}"><span class="badge badge-info">${tag}</span></a> - %endfor - %endif + ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} + ${helper.html_translations(post)} + ${helper.html_tags(post)} </small> <hr> ${post.text(lang)} - <ul class="pager"> - %if post.prev_post: - <li class="previous"> - <a href="${post.prev_post.permalink(lang)}">← ${messages[lang]["Previous post"]}</a> - </li> - %endif - %if post.next_post: - <li class="next"> - <a href="${post.next_post.permalink(lang)}">${messages[lang]["Next post"]} →</a> - </li> - %endif - </ul> - %if disqus_forum: - <div id="disqus_thread"></div> - <script type="text/javascript">var disqus_shortname="${disqus_forum}";var disqus_url="${post.permalink(absolute=True)}";(function(){var a=document.createElement("script");a.type="text/javascript";a.async=true;a.src="http://"+disqus_shortname+".disqus.com/embed.js";(document.getElementsByTagName("head")[0]||document.getElementsByTagName("body")[0]).appendChild(a)})();</script> - <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript> - <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a> - %endif + ${helper.html_pager(post)} + ${helper.html_disqus(post)} </div> </%block> diff --git a/nikola/filters.py b/nikola/filters.py index f450d10..15696f1 100644 --- a/nikola/filters.py +++ b/nikola/filters.py @@ -1,6 +1,31 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """Utility functions to help you run filters on files.""" import os +import re import shutil import subprocess import tempfile @@ -23,11 +48,53 @@ def runinplace(command, infile): tmpdir = tempfile.mkdtemp() tmpfname = os.path.join(tmpdir, os.path.basename(infile)) - command = command.replace('%1', infile) - command = command.replace('%2', tmpfname) + command = command.replace('%1', "'%s'" % infile) + + needs_tmp = "%2" in command + command = command.replace('%2', "'%s'"% tmpfname) + subprocess.check_call(command, shell=True) - shutil.move(tmpfname, infile) + + if needs_tmp: + shutil.move(tmpfname, infile) def yui_compressor(infile): - return runinplace(r'yui-compressor %1 -o %2', infile) + return runinplace(r'yui-compressor --nomunge %1 -o %2', infile) + +def optipng(infile): + return runinplace(r"optipng -preserve -o2 -quiet %1", infile) + +def jpegoptim(infile): + return runinplace(r"jpegoptim -p --strip-all -q %1",infile) + +def tidy(inplace): + # Goggle site verifcation files are no HTML + if re.match(r"google[a-f0-9]+.html", os.path.basename(inplace)) \ + and open(inplace).readline().startswith("google-site-verification:"): + return + + # Tidy will give error exits, that we will ignore. + output = subprocess.check_output( "tidy -m -w 90 --indent no --quote-marks no --keep-time yes --tidy-mark no '%s'; exit 0" % inplace, stderr = subprocess.STDOUT, shell = True ) + + for line in output.split( "\n" ): + if "Warning:" in line: + if '<meta> proprietary attribute "charset"' in line: + # We want to set it though. + continue + elif '<meta> lacks "content" attribute' in line: + # False alarm to me. + continue + elif '<div> anchor' in line and 'already defined' in line: + # Some seeming problem with JavaScript terminators. + continue + elif '<img> lacks "alt" attribute' in line: + # Happens in gallery code, probably can be tolerated. + continue + elif '<table> lacks "summary" attribute' in line: + # Happens for tables, TODO: Check this is normal. + continue + else: + assert False, (inplace,line) + elif "Error:" in line: + assert False, line diff --git a/nikola/nikola.py b/nikola/nikola.py index 8b69d02..4ce6f61 100644 --- a/nikola/nikola.py +++ b/nikola/nikola.py @@ -1,11 +1,38 @@ # -*- coding: utf-8 -*- - +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function, unicode_literals from collections import defaultdict from copy import copy import glob import os import sys -import urlparse +try: + from urlparse import urlparse, urlsplit, urljoin +except ImportError: + from urllib.parse import urlparse, urlsplit, urljoin import lxml.html from yapsy.PluginManager import PluginManager @@ -17,9 +44,9 @@ else: import logging logging.basicConfig(level=logging.ERROR) -from post import Post -import utils -from plugin_categories import ( +from .post import Post +from . import utils +from .plugin_categories import ( Command, LateTask, PageCompiler, @@ -56,6 +83,7 @@ class Nikola(object): 'ARCHIVE_FILENAME': "archive.html", 'DEFAULT_LANG': "en", 'OUTPUT_FOLDER': 'output', + 'CACHE_FOLDER': 'cache', 'FILES_FOLDERS': {'files': ''}, 'LISTINGS_FOLDER': 'listings', 'ADD_THIS_BUTTONS': True, @@ -94,8 +122,8 @@ class Nikola(object): }) self.plugin_manager.setPluginInfoExtension('plugin') self.plugin_manager.setPluginPlaces([ - os.path.join(os.path.dirname(__file__), 'plugins'), - os.path.join(os.getcwd(), 'plugins'), + str(os.path.join(os.path.dirname(__file__), 'plugins')), + str(os.path.join(os.getcwd(), 'plugins')), ]) self.plugin_manager.collectPlugins() @@ -128,6 +156,17 @@ class Nikola(object): self.GLOBAL_CONTEXT['index_display_post_count'] = self.config[ 'INDEX_DISPLAY_POST_COUNT'] self.GLOBAL_CONTEXT['use_bundles'] = self.config['USE_BUNDLES'] + if 'date_format' not in self.GLOBAL_CONTEXT: + self.GLOBAL_CONTEXT['date_format'] = '%Y-%m-%d %H:%M' + + # check if custom css exist and is not empty + for files_path in list(self.config['FILES_FOLDERS'].keys()): + custom_css_path = os.path.join(files_path, 'assets/css/custom.css') + if self.file_exists(custom_css_path, not_empty=True): + self.GLOBAL_CONTEXT['has_custom_css'] = True + break + else: + self.GLOBAL_CONTEXT['has_custom_css'] = False # Load template plugin template_sys_name = utils.get_template_engine(self.THEMES) @@ -138,9 +177,10 @@ class Nikola(object): % template_sys_name) sys.exit(1) self.template_system = pi.plugin_object - self.template_system.set_directories( - [os.path.join(utils.get_theme_path(name), "templates") - for name in self.THEMES]) + lookup_dirs = [os.path.join(utils.get_theme_path(name), "templates") + for name in self.THEMES] + self.template_system.set_directories(lookup_dirs, + self.config['CACHE_FOLDER']) # Load compiler plugins self.compilers = {} @@ -165,7 +205,7 @@ class Nikola(object): except KeyError: # Find the correct compiler for this files extension langs = [lang for lang, exts in - self.config['post_compilers'].items() + list(self.config['post_compilers'].items()) if ext in exts] if len(langs) != 1: if len(set(langs)) > 1: @@ -199,14 +239,14 @@ class Nikola(object): # This is to support windows paths url_part = "/".join(url_part.split(os.sep)) - src = urlparse.urljoin(self.config["BLOG_URL"], url_part) + src = urljoin(self.config["BLOG_URL"], url_part) - parsed_src = urlparse.urlsplit(src) + parsed_src = urlsplit(src) src_elems = parsed_src.path.split('/')[1:] def replacer(dst): # Refuse to replace links that are full URLs. - dst_url = urlparse.urlparse(dst) + dst_url = urlparse(dst) if dst_url.netloc: if dst_url.scheme == 'link': # Magic link dst = self.link(dst_url.netloc, dst_url.path.lstrip('/'), @@ -215,12 +255,12 @@ class Nikola(object): return dst # Normalize - dst = urlparse.urljoin(src, dst) + dst = urljoin(src, dst) # Avoid empty links. if src == dst: return "#" # Check that link can be made relative, otherwise return dest - parsed_dst = urlparse.urlsplit(dst) + parsed_dst = urlsplit(dst) if parsed_src[:2] != parsed_dst[:2]: return dst @@ -252,8 +292,8 @@ class Nikola(object): pass doc = lxml.html.document_fromstring(data) doc.rewrite_links(replacer) - data = '<!DOCTYPE html>' + lxml.html.tostring(doc, encoding='utf8') - with open(output_name, "w+") as post_file: + data = b'<!DOCTYPE html>' + lxml.html.tostring(doc, encoding='utf8') + with open(output_name, "wb+") as post_file: post_file.write(data) def path(self, kind, name, lang, is_link=False): @@ -283,41 +323,39 @@ class Nikola(object): path = [] if kind == "tag_index": - path = filter(None, [self.config['TRANSLATIONS'][lang], - self.config['TAG_PATH'], 'index.html']) + path = [_f for _f in [self.config['TRANSLATIONS'][lang], + self.config['TAG_PATH'], 'index.html'] if _f] elif kind == "tag": if self.config['SLUG_TAG_PATH']: name = utils.slugify(name) - path = filter(None, [self.config['TRANSLATIONS'][lang], - self.config['TAG_PATH'], name + ".html"]) + path = [_f for _f in [self.config['TRANSLATIONS'][lang], + self.config['TAG_PATH'], name + ".html"] if _f] elif kind == "tag_rss": if self.config['SLUG_TAG_PATH']: name = utils.slugify(name) - path = filter(None, [self.config['TRANSLATIONS'][lang], - self.config['TAG_PATH'], name + ".xml"]) + path = [_f for _f in [self.config['TRANSLATIONS'][lang], + self.config['TAG_PATH'], name + ".xml"] if _f] elif kind == "index": if name > 0: - path = filter(None, [self.config['TRANSLATIONS'][lang], - self.config['INDEX_PATH'], 'index-%s.html' % name]) + path = [_f for _f in [self.config['TRANSLATIONS'][lang], + self.config['INDEX_PATH'], 'index-%s.html' % name] if _f] else: - path = filter(None, [self.config['TRANSLATIONS'][lang], - self.config['INDEX_PATH'], 'index.html']) + path = [_f for _f in [self.config['TRANSLATIONS'][lang], + self.config['INDEX_PATH'], 'index.html'] if _f] elif kind == "rss": - path = filter(None, [self.config['TRANSLATIONS'][lang], - self.config['RSS_PATH'], 'rss.xml']) + path = [_f for _f in [self.config['TRANSLATIONS'][lang], + self.config['RSS_PATH'], 'rss.xml'] if _f] elif kind == "archive": if name: - path = filter(None, [self.config['TRANSLATIONS'][lang], - self.config['ARCHIVE_PATH'], name, 'index.html']) + path = [_f for _f in [self.config['TRANSLATIONS'][lang], + self.config['ARCHIVE_PATH'], name, 'index.html'] if _f] else: - path = filter(None, [self.config['TRANSLATIONS'][lang], - self.config['ARCHIVE_PATH'], self.config['ARCHIVE_FILENAME']]) + path = [_f for _f in [self.config['TRANSLATIONS'][lang], + self.config['ARCHIVE_PATH'], self.config['ARCHIVE_FILENAME']] if _f] elif kind == "gallery": - path = filter(None, - [self.config['GALLERY_PATH'], name, 'index.html']) + path = [_f for _f in [self.config['GALLERY_PATH'], name, 'index.html'] if _f] elif kind == "listing": - path = filter(None, - [self.config['LISTINGS_FOLDER'], name + '.html']) + path = [_f for _f in [self.config['LISTINGS_FOLDER'], name + '.html'] if _f] if is_link: return '/' + ('/'.join(path)) else: @@ -328,20 +366,20 @@ class Nikola(object): def abs_link(self, dst): # Normalize - dst = urlparse.urljoin(self.config['BLOG_URL'], dst) + dst = urljoin(self.config['BLOG_URL'], dst) - return urlparse.urlparse(dst).path + return urlparse(dst).path def rel_link(self, src, dst): # Normalize - src = urlparse.urljoin(self.config['BLOG_URL'], src) - dst = urlparse.urljoin(src, dst) + src = urljoin(self.config['BLOG_URL'], src) + dst = urljoin(src, dst) # Avoid empty links. if src == dst: return "#" # Check that link can be made relative, otherwise return dest - parsed_src = urlparse.urlsplit(src) - parsed_dst = urlparse.urlsplit(dst) + parsed_src = urlsplit(src) + parsed_dst = urlsplit(dst) if parsed_src[:2] != parsed_dst[:2]: return dst # Now both paths are on the same site and absolute @@ -379,7 +417,7 @@ class Nikola(object): task_dep.append(pluginInfo.plugin_object.name) yield { - 'name': 'all', + 'name': b'all', 'actions': None, 'clean': True, 'task_dep': task_dep @@ -388,18 +426,22 @@ class Nikola(object): def scan_posts(self): """Scan all the posts.""" if not self._scanned: - print "Scanning posts ", + print("Scanning posts ") targets = set([]) for wildcard, destination, _, use_in_feeds in \ self.config['post_pages']: - print ".", + print (".") for base_path in glob.glob(wildcard): - post = Post(base_path, destination, use_in_feeds, + post = Post( + base_path, + self.config['CACHE_FOLDER'], + destination, + use_in_feeds, self.config['TRANSLATIONS'], self.config['DEFAULT_LANG'], self.config['BLOG_URL'], self.MESSAGES) - for lang, langpath in self.config['TRANSLATIONS'].items(): + for lang, langpath in list(self.config['TRANSLATIONS'].items()): dest = (destination, langpath, post.pagenames[lang]) if dest in targets: raise Exception( @@ -414,9 +456,9 @@ class Nikola(object): self.posts_per_tag[tag].append(post.post_name) else: self.pages.append(post) - for name, post in self.global_data.items(): + for name, post in list(self.global_data.items()): self.timeline.append(post) - self.timeline.sort(cmp=lambda a, b: cmp(a.date, b.date)) + self.timeline.sort(key=lambda p: p.date) self.timeline.reverse() post_timeline = [p for p in self.timeline if p.use_in_feeds] for i, p in enumerate(post_timeline[1:]): @@ -424,7 +466,7 @@ class Nikola(object): for i, p in enumerate(post_timeline[:-1]): p.prev_post = post_timeline[i + 1] self._scanned = True - print "done!" + print("done!") def generic_page_renderer(self, lang, wildcard, template_name, destination, filters): @@ -497,4 +539,4 @@ class Nikola(object): 'uptodate': [config_changed(deps_context)] } - yield utils.apply_filters(task, filters) + return utils.apply_filters(task, filters) diff --git a/nikola/plugin_categories.py b/nikola/plugin_categories.py index cc59b24..bf810e3 100644 --- a/nikola/plugin_categories.py +++ b/nikola/plugin_categories.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + __all__ = [ 'Command', 'LateTask', @@ -58,8 +82,8 @@ class TemplateSystem(object): name = "dummy templates" - def set_directories(self, directories): - """Sets the list of folders where templates are located.""" + def set_directories(self, directories, cache_folder): + """Sets the list of folders where templates are located and cache.""" raise Exception("Implement Me First") def template_deps(self, template_name): diff --git a/nikola/plugins/__init__.py b/nikola/plugins/__init__.py new file mode 100644 index 0000000..ec6c8f5 --- /dev/null +++ b/nikola/plugins/__init__.py @@ -0,0 +1,4 @@ +from __future__ import absolute_import + +from . import command_import_wordpress + diff --git a/nikola/plugins/command_bootswatch_theme.py b/nikola/plugins/command_bootswatch_theme.py index f077eb1..185717f 100644 --- a/nikola/plugins/command_bootswatch_theme.py +++ b/nikola/plugins/command_bootswatch_theme.py @@ -1,6 +1,35 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function from optparse import OptionParser import os -import urllib2 + +try: + import requests +except ImportError: + requests = None from nikola.plugin_categories import Command @@ -12,7 +41,9 @@ class CommandBootswatchTheme(Command): def run(self, *args): """Given a swatch name and a parent theme, creates a custom theme.""" - + if requests is None: + print('To use the install_theme command, you need to install the "requests" package.') + return parser = OptionParser(usage="nikola %s [options]" % self.name) parser.add_option("-n", "--name", dest="name", help="New theme name (default: custom)", default='custom') @@ -27,21 +58,21 @@ class CommandBootswatchTheme(Command): swatch = options.swatch parent = options.parent - print "Creating '%s' theme from '%s' and '%s'" % ( - name, swatch, parent) + print("Creating '%s' theme from '%s' and '%s'" % ( + name, swatch, parent)) try: os.makedirs(os.path.join('themes', name, 'assets', 'css')) except: pass for fname in ('bootstrap.min.css', 'bootstrap.css'): url = 'http://bootswatch.com/%s/%s' % (swatch, fname) - print "Downloading: ", url - data = urllib2.urlopen(url).read() + print("Downloading: ", url) + data = requests.get(url).text with open(os.path.join( 'themes', name, 'assets', 'css', fname), 'wb+') as output: output.write(data) with open(os.path.join('themes', name, 'parent'), 'wb+') as output: output.write(parent) - print 'Theme created. Change the THEME setting to "%s" to use it.'\ - % name + print('Theme created. Change the THEME setting to "%s" to use it.' + % name) diff --git a/nikola/plugins/command_build.py b/nikola/plugins/command_build.py index cface15..867cbf9 100644 --- a/nikola/plugins/command_build.py +++ b/nikola/plugins/command_build.py @@ -1,3 +1,28 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import unicode_literals import os import tempfile @@ -14,7 +39,7 @@ class CommandBuild(Command): # FIXME: this is crap, do it right with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as dodo: - dodo.write(''' + dodo.write(b''' from doit.reporter import ExecutedOnlyReporter DOIT_CONFIG = { 'reporter': ExecutedOnlyReporter, @@ -29,4 +54,11 @@ def task_render_site(): return SITE.gen_tasks() ''') dodo.flush() - os.system('doit -f %s -d . %s' % (dodo.name, ' '.join(args))) + first = args[0] if args else None + if first in ('auto', 'clean', 'forget', 'ignore', 'list', 'run'): + cmd = first + args = args[1:] + else: + cmd = 'run' + os.system('doit %s -f %s -d . %s' % (cmd, dodo.name, ' '.join(args))) + diff --git a/nikola/plugins/command_check.py b/nikola/plugins/command_check.py index ce1e2e3..5fc8bfe 100644 --- a/nikola/plugins/command_check.py +++ b/nikola/plugins/command_check.py @@ -1,8 +1,36 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function from optparse import OptionParser import os import sys -import urllib -from urlparse import urlparse +try: + from urllib import unquote + from urlparse import urlparse +except ImportError: + from urllib.parse import unquote, urlparse import lxml.html @@ -48,24 +76,24 @@ def analize(task): target = target.split('#')[0] target_filename = os.path.abspath( os.path.join(os.path.dirname(filename), - urllib.unquote(target))) + unquote(target))) if target_filename not in existing_targets: if os.path.exists(target_filename): existing_targets.add(target_filename) else: - print "In %s broken link: " % filename, target + print("In %s broken link: " % filename, target) if '--find-sources' in sys.argv: - print "Possible sources:" - print os.popen( - 'nikola build list --deps %s' % task, 'r').read() - print "===============================\n" + print("Possible sources:") + print(os.popen( + 'nikola build list --deps %s' % task, 'r').read()) + print("===============================\n") except Exception as exc: - print "Error with:", filename, exc + print("Error with:", filename, exc) def scan_links(): - print "Checking Links:\n===============\n" + print("Checking Links:\n===============\n") for task in os.popen('nikola build list --all', 'r').readlines(): task = task.strip() if task.split(':')[0] in ( @@ -79,7 +107,7 @@ def scan_links(): def scan_files(): - print "Checking Files:\n===============\n" + print("Checking Files:\n===============\n") task_fnames = set([]) real_fnames = set([]) # First check that all targets are generated in the right places @@ -97,13 +125,13 @@ def scan_files(): only_on_output = list(real_fnames - task_fnames) if only_on_output: only_on_output.sort() - print "\nFiles from unknown origins:\n" + print("\nFiles from unknown origins:\n") for f in only_on_output: - print f + print(f) only_on_input = list(task_fnames - real_fnames) if only_on_input: only_on_input.sort() - print "\nFiles not generated:\n" + print("\nFiles not generated:\n") for f in only_on_input: - print f + print(f) diff --git a/nikola/plugins/command_console.plugin b/nikola/plugins/command_console.plugin new file mode 100644 index 0000000..003b994 --- /dev/null +++ b/nikola/plugins/command_console.plugin @@ -0,0 +1,9 @@ +[Core] +Name = console +Module = command_console + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://nikola.ralsina.com.ar +Description = Start a debugging python console diff --git a/nikola/plugins/command_console.py b/nikola/plugins/command_console.py new file mode 100644 index 0000000..ea517a0 --- /dev/null +++ b/nikola/plugins/command_console.py @@ -0,0 +1,35 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import os + +from nikola.plugin_categories import Command + + +class Deploy(Command): + """Start debugging console.""" + name = "console" + + def run(self, *args): + os.system('python -i -c "from nikola.console import *"') diff --git a/nikola/plugins/command_deploy.py b/nikola/plugins/command_deploy.py index cb2eb41..48d6e91 100644 --- a/nikola/plugins/command_deploy.py +++ b/nikola/plugins/command_deploy.py @@ -1,3 +1,28 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function from optparse import OptionParser import os @@ -12,5 +37,5 @@ class Deploy(Command): parser = OptionParser(usage="nikola %s [options]" % self.name) (options, args) = parser.parse_args(list(args)) for command in self.site.config['DEPLOY_COMMANDS']: - print "==>", command + print("==>", command) os.system(command) diff --git a/nikola/plugins/command_import_wordpress.py b/nikola/plugins/command_import_wordpress.py index e75d022..1552da4 100644 --- a/nikola/plugins/command_import_wordpress.py +++ b/nikola/plugins/command_import_wordpress.py @@ -1,11 +1,45 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import unicode_literals, print_function import codecs +import csv import os -from urlparse import urlparse -from urllib import urlopen +import re +try: + from urlparse import urlparse +except ImportError: + from urllib.parse import urlparse -from lxml import etree, html +from lxml import etree, html, builder from mako.template import Template +try: + import requests +except ImportError: + requests = None + from nikola.plugin_categories import Command from nikola import utils @@ -17,38 +51,67 @@ class CommandImportWordpress(Command): name = "import_wordpress" - def run(self, fname=None): - # Parse the data - if fname is None: - print "Usage: nikola import_wordpress wordpress_dump.xml" - return - context = {} - with open(fname) as fd: - xml = [] + @staticmethod + def read_xml_file(filename): + xml = [] + + with open(filename, 'rb') as fd: for line in fd: # These explode etree and are useless - if '<atom:link rel=' in line: + if b'<atom:link rel=' in line: continue xml.append(line) - xml = '\n'.join(xml) + xml = b'\n'.join(xml) - tree = etree.fromstring(xml) + return xml + + @classmethod + def get_channel_from_file(cls, filename): + tree = etree.fromstring(cls.read_xml_file(filename)) channel = tree.find('channel') + return channel + + @staticmethod + def configure_redirections(url_map): + redirections = [] + for k, v in url_map.items(): + # remove the initial "/" because src is a relative file path + src = (urlparse(k).path + 'index.html')[1:] + dst = (urlparse(v).path) + if src == 'index.html': + print("Can't do a redirect for: %r" % k) + else: + redirections.append((src, dst)) + + return redirections + @staticmethod + def generate_base_site(context): + os.system('nikola init new_site') + conf_template = Template(filename=os.path.join( + os.path.dirname(utils.__file__), 'conf.py.in')) + + return conf_template + + @staticmethod + def populate_context(channel): + wordpress_namespace = channel.nsmap['wp'] + + context = {} context['DEFAULT_LANG'] = get_text_tag(channel, 'language', 'en')[:2] - context['BLOG_TITLE'] = get_text_tag( - channel, 'title', 'PUT TITLE HERE') + context['BLOG_TITLE'] = get_text_tag(channel, 'title', + 'PUT TITLE HERE') context['BLOG_DESCRIPTION'] = get_text_tag( channel, 'description', 'PUT DESCRIPTION HERE') context['BLOG_URL'] = get_text_tag(channel, 'link', '#') - author = channel.find('{http://wordpress.org/export/1.2/}author') + author = channel.find('{%s}author' % wordpress_namespace) context['BLOG_EMAIL'] = get_text_tag( author, - '{http://wordpress.org/export/1.2/}author_email', + '{%s}author_email' % wordpress_namespace, "joe@example.com") context['BLOG_AUTHOR'] = get_text_tag( author, - '{http://wordpress.org/export/1.2/}author_display_name', + '{%s}author_display_name' % wordpress_namespace, "Joe Example") context['POST_PAGES'] = '''( ("posts/*.wp", "posts", "post.tmpl", True), @@ -61,19 +124,149 @@ class CommandImportWordpress(Command): } ''' - # Generate base site - os.system('nikola init new_site') - conf_template = Template(filename=os.path.join( - os.path.dirname(utils.__file__), 'data', 'samplesite', 'conf.py.in')) - with codecs.open(os.path.join('new_site', 'conf.py'), - 'w+', 'utf8') as fd: - fd.write(conf_template.render(**context)) + return context - # Import posts - for item in channel.findall('item'): - import_attachment(item) + @staticmethod + def download_url_content_to_file(url, dst_path): + with open(dst_path, 'wb+') as fd: + fd.write(requests.get(url).content) + + def import_attachment(self, item, wordpress_namespace): + url = get_text_tag(item, '{%s}attachment_url' % wordpress_namespace, 'foo') + link = get_text_tag(item, '{%s}link' % wordpress_namespace, 'foo') + path = urlparse(url).path + dst_path = os.path.join(*(['new_site', 'files'] + + list(path.split('/')))) + dst_dir = os.path.dirname(dst_path) + if not os.path.isdir(dst_dir): + os.makedirs(dst_dir) + print("Downloading %s => %s" % (url, dst_path)) + self.download_url_content_to_file(url, dst_path) + dst_url = '/'.join(dst_path.split(os.sep)[2:]) + links[link] = '/' + dst_url + links[url] = '/' + dst_url + + @staticmethod + def write_content(filename, content): + with open(filename, "wb+") as fd: + if content.strip(): + # Handle sourcecode pseudo-tags + content = re.sub('\[sourcecode language="([^"]+)"\]', + "\n~~~~~~~~~~~~{.\\1}\n", content) + content = content.replace('[/sourcecode]', "\n~~~~~~~~~~~~\n") + doc = html.document_fromstring(content) + doc.rewrite_links(replacer) + # Replace H1 elements with H2 elements + for tag in doc.findall('.//h1'): + if not tag.text: + print("Failed to fix bad title: %r" % + html.tostring(tag)) + else: + tag.getparent().replace(tag, builder.E.h2(tag.text)) + fd.write(html.tostring(doc, encoding='utf8')) + + @staticmethod + def write_metadata(filename, title, slug, post_date, description, tags): + with codecs.open(filename, "w+", "utf8") as fd: + fd.write('%s\n' % title) + fd.write('%s\n' % slug) + fd.write('%s\n' % post_date) + fd.write('%s\n' % ','.join(tags)) + fd.write('\n') + fd.write('%s\n' % description) + + def import_item(self, item, wordpress_namespace, out_folder=None): + """Takes an item from the feed and creates a post file.""" + if out_folder is None: + out_folder = 'posts' + + title = get_text_tag(item, 'title', 'NO TITLE') + # link is something like http://foo.com/2012/09/01/hello-world/ + # So, take the path, utils.slugify it, and that's our slug + link = get_text_tag(item, 'link', None) + slug = utils.slugify(urlparse(link).path) + if not slug: # it happens if the post has no "nice" URL + slug = get_text_tag(item, '{%s}post_name' % wordpress_namespace, None) + if not slug: # it *may* happen + slug = get_text_tag(item, '{%s}post_id' % wordpress_namespace, None) + if not slug: # should never happen + print("Error converting post:", title) + return + + description = get_text_tag(item, 'description', '') + post_date = get_text_tag(item, '{%s}post_date' % wordpress_namespace, None) + status = get_text_tag(item, '{%s}status' % wordpress_namespace, 'publish') + content = get_text_tag( + item, '{http://purl.org/rss/1.0/modules/content/}encoded', '') + + tags = [] + if status != 'publish': + tags.append('draft') + for tag in item.findall('category'): + text = tag.text + if text == 'Uncategorized': + continue + tags.append(text) + + self.url_map[link] = self.context['BLOG_URL'] + '/' + \ + out_folder + '/' + slug + '.html' + + self.write_metadata(os.path.join('new_site', out_folder, + slug + '.meta'), + title, slug, post_date, description, tags) + self.write_content( + os.path.join('new_site', out_folder, slug + '.wp'), content) + + def process_item(self, item): + # The namespace usually is something like: + # http://wordpress.org/export/1.2/ + wordpress_namespace = item.nsmap['wp'] + post_type = get_text_tag(item, '{%s}post_type' % wordpress_namespace, 'post') + + if post_type == 'attachment': + self.import_attachment(item, wordpress_namespace) + elif post_type == 'post': + self.import_item(item, wordpress_namespace, 'posts') + else: + self.import_item(item, wordpress_namespace, 'stories') + + def import_posts(self, channel): for item in channel.findall('item'): - import_item(item) + self.process_item(item) + + @staticmethod + def write_urlmap_csv(output_file, url_map): + with codecs.open(output_file, 'w+', 'utf8') as fd: + csv_writer = csv.writer(fd) + for item in url_map.items(): + csv_writer.writerow(item) + + @staticmethod + def write_configuration(filename, rendered_template): + with codecs.open(filename, 'w+', 'utf8') as fd: + fd.write(rendered_template) + + def run(self, fname=None): + # Parse the data + if requests is None: + print('To use the import_wordpress command, you have to install the "requests" package.') + return + if fname is None: + print("Usage: nikola import_wordpress wordpress_dump.xml") + return + + self.url_map = {} + channel = self.get_channel_from_file(fname) + self.context = self.populate_context(channel) + conf_template = self.generate_base_site(self.context) + self.context['REDIRECTIONS'] = self.configure_redirections( + self.url_map) + + self.import_posts(channel) + self.write_urlmap_csv( + os.path.join('new_site', 'url_map.csv'), self.url_map) + self.write_configuration(os.path.join( + 'new_site', 'conf.py'), conf_template.render(**self.context)) def replacer(dst): @@ -81,83 +274,10 @@ def replacer(dst): def get_text_tag(tag, name, default): + if tag is None: + return default t = tag.find(name) if t is not None: return t.text else: return default - - -def import_attachment(item): - post_type = get_text_tag(item, - '{http://wordpress.org/export/1.2/}post_type', 'post') - if post_type == 'attachment': - url = get_text_tag(item, - '{http://wordpress.org/export/1.2/}attachment_url', 'foo') - link = get_text_tag(item, - '{http://wordpress.org/export/1.2/}link', 'foo') - path = urlparse(url).path - dst_path = os.path.join(*(['new_site', 'files'] - + list(path.split('/')))) - dst_dir = os.path.dirname(dst_path) - if not os.path.isdir(dst_dir): - os.makedirs(dst_dir) - print "Downloading %s => %s" % (url, dst_path) - with open(dst_path, 'wb+') as fd: - fd.write(urlopen(url).read()) - dst_url = '/'.join(dst_path.split(os.sep)[2:]) - links[link] = '/' + dst_url - links[url] = '/' + dst_url - return - - -def import_item(item): - """Takes an item from the feed and creates a post file.""" - title = get_text_tag(item, 'title', 'NO TITLE') - # link is something like http://foo.com/2012/09/01/hello-world/ - # So, take the path, utils.slugify it, and that's our slug - slug = utils.slugify(urlparse(get_text_tag(item, 'link', None)).path) - description = get_text_tag(item, 'description', '') - post_date = get_text_tag(item, - '{http://wordpress.org/export/1.2/}post_date', None) - post_type = get_text_tag(item, - '{http://wordpress.org/export/1.2/}post_type', 'post') - status = get_text_tag(item, - '{http://wordpress.org/export/1.2/}status', 'publish') - content = get_text_tag(item, - '{http://purl.org/rss/1.0/modules/content/}encoded', '') - - tags = [] - if status != 'publish': - tags.append('draft') - for tag in item.findall('category'): - text = tag.text - if text == 'Uncategorized': - continue - tags.append(text) - - if post_type == 'attachment': - return - elif post_type == 'post': - out_folder = 'posts' - else: - out_folder = 'stories' - # Write metadata - with codecs.open(os.path.join('new_site', out_folder, slug + '.meta'), - "w+", "utf8") as fd: - fd.write(u'%s\n' % title) - fd.write(u'%s\n' % slug) - fd.write(u'%s\n' % post_date) - fd.write(u'%s\n' % ','.join(tags)) - fd.write(u'\n') - fd.write(u'%s\n' % description) - with open(os.path.join( - 'new_site', out_folder, slug + '.wp'), "wb+") as fd: - if content.strip(): - try: - doc = html.document_fromstring(content) - doc.rewrite_links(replacer) - fd.write(html.tostring(doc, encoding='utf8')) - except: - import pdb - pdb.set_trace() diff --git a/nikola/plugins/command_init.py b/nikola/plugins/command_init.py index a032370..0b56482 100644 --- a/nikola/plugins/command_init.py +++ b/nikola/plugins/command_init.py @@ -1,6 +1,34 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function from optparse import OptionParser import os import shutil +import codecs + +from mako.template import Template import nikola from nikola.plugin_categories import Command @@ -17,18 +45,50 @@ That will create a sample site in the specified folder. The destination folder must not exist. """ + SAMPLE_CONF = { + 'BLOG_AUTHOR': "Your Name", + 'BLOG_TITLE': "Demo Site", + 'BLOG_URL': "http://nikola.ralsina.com.ar", + 'BLOG_EMAIL': "joe@demo.site", + 'BLOG_DESCRIPTION': "This is a demo site for Nikola.", + 'DEFAULT_LANG': "en", + + 'POST_PAGES': """( + ("posts/*.txt", "posts", "post.tmpl", True), + ("stories/*.txt", "stories", "story.tmpl", False), +)""", + + 'POST_COMPILERS': """{ + "rest": ('.txt', '.rst'), + "markdown": ('.md', '.mdown', '.markdown'), + "html": ('.html', '.htm') + }""", + 'REDIRECTIONS': '[]', + } + def run(self, *args): """Create a new site.""" parser = OptionParser(usage=self.usage) (options, args) = parser.parse_args(list(args)) + if not args: + print("Usage: nikola init folder [options]") + return target = args[0] if target is None: - print self.usage + print(self.usage) else: - src = os.path.join(os.path.dirname(nikola.__file__), - 'data', 'samplesite') + # copy sample data + lib_path = os.path.dirname(nikola.__file__) + src = os.path.join(lib_path, 'data', 'samplesite') shutil.copytree(src, target) - print "A new site with some sample data has been created at %s."\ - % target - print "See README.txt in that folder for more information." + # create conf.py + template_path = os.path.join(lib_path, 'conf.py.in') + conf_template = Template(filename=template_path) + conf_path = os.path.join(target, 'conf.py') + with codecs.open(conf_path, 'w+', 'utf8') as fd: + fd.write(conf_template.render(**self.SAMPLE_CONF)) + + print("A new site with some sample data has been created at %s." + % target) + print("See README.txt in that folder for more information.") diff --git a/nikola/plugins/command_install_theme.py b/nikola/plugins/command_install_theme.py index 293ce97..b9ca634 100644 --- a/nikola/plugins/command_install_theme.py +++ b/nikola/plugins/command_install_theme.py @@ -1,9 +1,38 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function from optparse import OptionParser import os -import urllib2 import json from io import StringIO +try: + import requests +except ImportError: + requests = None + from nikola.plugin_categories import Command from nikola import utils @@ -15,7 +44,9 @@ class CommandInstallTheme(Command): def run(self, *args): """Install theme into current site.""" - + if requests is None: + print('To use the install_theme command, you need to install the "requests" package.') + return parser = OptionParser(usage="nikola %s [options]" % self.name) parser.add_option("-l", "--list", dest="list", action="store_true", @@ -33,15 +64,15 @@ class CommandInstallTheme(Command): url = options.url if name is None and not listing: - print "This command needs either the -n or the -l option." + print("This command needs either the -n or the -l option.") return False - data = urllib2.urlopen(url).read() + data = requests.get(url).text data = json.loads(data) if listing: - print "Themes:" - print "-------" + print("Themes:") + print("-------") for theme in sorted(data.keys()): - print theme + print(theme) return True else: if name in data: @@ -52,11 +83,11 @@ class CommandInstallTheme(Command): os.makedirs("themes") except: raise OSError("mkdir 'theme' error!") - print 'Downloading: %s' % data[name] + print('Downloading: %s' % data[name]) zip_file = StringIO() - zip_file.write(urllib2.urlopen(data[name]).read()) - print 'Extracting: %s into themes' % name + zip_file.write(requests.get(data[name]).content) + print('Extracting: %s into themes' % name) utils.extract_all(zip_file) else: - print "Can't find theme %s" % name + print("Can't find theme %s" % name) return False diff --git a/nikola/plugins/command_new_post.py b/nikola/plugins/command_new_post.py index 574df5f..36026be 100644 --- a/nikola/plugins/command_new_post.py +++ b/nikola/plugins/command_new_post.py @@ -1,3 +1,28 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import unicode_literals, print_function import codecs import datetime from optparse import OptionParser @@ -47,12 +72,13 @@ class CommandNewPost(Command): else: path = self.site.config['post_pages'][0][0] - print "Creating New Post" - print "-----------------\n" + print("Creating New Post") + print("-----------------\n") if title is None: - title = raw_input("Enter title: ").decode(sys.stdin.encoding) + print("Enter title: ") + title = sys.stdin.readline().decode(sys.stdin.encoding).strip() else: - print "Title: ", title + print("Title: ", title) slug = utils.slugify(title) date = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S') data = [ @@ -72,12 +98,12 @@ class CommandNewPost(Command): if (not onefile and os.path.isfile(meta_path)) or \ os.path.isfile(txt_path): - print "The title already exists!" + print("The title already exists!") exit() if onefile: if post_format not in ('rest', 'markdown'): - print "ERROR: Unknown post format %s" % post_format + print("ERROR: Unknown post format %s" % post_format) return with codecs.open(txt_path, "wb+", "utf8") as fd: if post_format == 'markdown': @@ -90,11 +116,11 @@ class CommandNewPost(Command): fd.write('.. description: \n') if post_format == 'markdown': fd.write('-->\n') - fd.write(u"Write your post here.") + fd.write("\nWrite your post here.") else: with codecs.open(meta_path, "wb+", "utf8") as fd: fd.write(data) with codecs.open(txt_path, "wb+", "utf8") as fd: - fd.write(u"Write your post here.") - print "Your post's metadata is at: ", meta_path - print "Your post's text is at: ", txt_path + fd.write("Write your post here.") + print("Your post's metadata is at: ", meta_path) + print("Your post's text is at: ", txt_path) diff --git a/nikola/plugins/command_serve.py b/nikola/plugins/command_serve.py index 626b117..628bba0 100644 --- a/nikola/plugins/command_serve.py +++ b/nikola/plugins/command_serve.py @@ -1,7 +1,36 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function from optparse import OptionParser import os -from BaseHTTPServer import HTTPServer -from SimpleHTTPServer import SimpleHTTPRequestHandler +try: + from BaseHTTPServer import HTTPServer + from SimpleHTTPServer import SimpleHTTPRequestHandler +except ImportError: + from http.server import HTTPServer + from http.server import SimpleHTTPRequestHandler from nikola.plugin_categories import Command @@ -25,13 +54,13 @@ class CommandBuild(Command): out_dir = self.site.config['OUTPUT_FOLDER'] if not os.path.isdir(out_dir): - print "Error: Missing '%s' folder?" % out_dir + print("Error: Missing '%s' folder?" % out_dir) else: os.chdir(out_dir) httpd = HTTPServer((options.address, options.port), OurHTTPRequestHandler) sa = httpd.socket.getsockname() - print "Serving HTTP on", sa[0], "port", sa[1], "..." + print("Serving HTTP on", sa[0], "port", sa[1], "...") httpd.serve_forever() diff --git a/nikola/plugins/compile_html.py b/nikola/plugins/compile_html.py index 8241030..24e01fb 100644 --- a/nikola/plugins/compile_html.py +++ b/nikola/plugins/compile_html.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """Implementation of compile_html based on markdown.""" import os diff --git a/nikola/plugins/compile_markdown/__init__.py b/nikola/plugins/compile_markdown/__init__.py index 958cfa3..1a58a98 100644 --- a/nikola/plugins/compile_markdown/__init__.py +++ b/nikola/plugins/compile_markdown/__init__.py @@ -1,20 +1,49 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """Implementation of compile_html based on markdown.""" import codecs import os import re -from markdown import markdown +try: + from markdown import markdown +except ImportError: + markdown = None from nikola.plugin_categories import PageCompiler class CompileMarkdown(PageCompiler): - """Compile reSt into HTML.""" + """Compile markdown into HTML.""" name = "markdown" def compile_html(self, source, dest): + if markdown is None: + raise Exception('To build this site, you need to install the "markdown" package.') try: os.makedirs(os.path.dirname(dest)) except: diff --git a/nikola/plugins/compile_rest/__init__.py b/nikola/plugins/compile_rest/__init__.py index 0a25a06..0e677e1 100644 --- a/nikola/plugins/compile_rest/__init__.py +++ b/nikola/plugins/compile_rest/__init__.py @@ -1,3 +1,28 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import unicode_literals import codecs import os @@ -5,17 +30,16 @@ import docutils.core import docutils.io from docutils.parsers.rst import directives -from pygments_code_block_directive import ( +from .pygments_code_block_directive import ( code_block_directive, listings_directive) directives.register_directive('code-block', code_block_directive) directives.register_directive('listing', listings_directive) -import pygments_code_block_directive -# Below is to make pyflakes happy (sigh) -pygments_code_block_directive -from youtube import youtube +from .youtube import youtube directives.register_directive('youtube', youtube) +from .slides import slides +directives.register_directive('slides', slides) from nikola.plugin_categories import PageCompiler diff --git a/nikola/plugins/compile_rest/pygments_code_block_directive.py b/nikola/plugins/compile_rest/pygments_code_block_directive.py index ac91f3c..a83098f 100644 --- a/nikola/plugins/compile_rest/pygments_code_block_directive.py +++ b/nikola/plugins/compile_rest/pygments_code_block_directive.py @@ -26,6 +26,7 @@ """Define and register a code-block directive using pygments"""
+from __future__ import unicode_literals
# Requirements
# ------------
@@ -34,7 +35,10 @@ import codecs
from copy import copy
import os
-import urlparse
+try:
+ from urlparse import urlparse, urlunsplit
+except ImportError:
+ from urllib.parse import urlparse, urlunsplit
from docutils import nodes, core
from docutils.parsers.rst import directives
@@ -90,7 +94,7 @@ class DocutilsInterface(object): def lex(self):
"""Get lexer for language (use text as fallback)"""
try:
- if self.language and unicode(self.language).lower() != 'none':
+ if self.language and str(self.language).lower() != 'none':
lexer = get_lexer_by_name(self.language.lower(),
**self.custom_args
)
@@ -105,7 +109,7 @@ class DocutilsInterface(object): """join subsequent tokens of same token-type
"""
tokens = iter(tokens)
- (lasttype, lastval) = tokens.next()
+ (lasttype, lastval) = next(tokens)
for ttype, value in tokens:
if ttype is lasttype:
lastval += value
@@ -143,7 +147,7 @@ def code_block_directive(name, arguments, options, content, lineno, content = codecs.open(
options['include'], 'r', encoding).read().rstrip()
except (IOError, UnicodeError): # no file or problem reading it
- content = u''
+ content = ''
line_offset = 0
if content:
# here we define the start-at and end-at options
@@ -163,8 +167,22 @@ def code_block_directive(name, arguments, options, content, lineno, if after_index < 0:
raise state_machine.reporter.severe(
'Problem with "start-at" option of "%s" '
- 'code-block directive:\nText not found.' %
- options['start-at'])
+ 'code-block directive:\nText not found.'
+ % options['start-at'])
+ # patch mmueller start
+ # Move the after_index to the beginning of the line with the
+ # match.
+ for char in content[after_index:0:-1]:
+ # codecs always opens binary. This works with '\n',
+ # '\r' and '\r\n'. We are going backwards, so
+ # '\n' is found first in '\r\n'.
+ # Going with .splitlines() seems more appropriate
+ # but needs a few more changes.
+ if char == '\n' or char == '\r':
+ break
+ after_index -= 1
+ # patch mmueller end
+
content = content[after_index:]
line_offset = len(content[:after_index].splitlines())
@@ -208,7 +226,7 @@ def code_block_directive(name, arguments, options, content, lineno, content = content[:before_index]
else:
- content = u'\n'.join(content)
+ content = '\n'.join(content)
if 'tabsize' in options:
tabw = options['tabsize']
@@ -240,7 +258,7 @@ def code_block_directive(name, arguments, options, content, lineno, else:
# The [:-1] is because pygments adds a trailing \n which looks bad
l = list(DocutilsInterface(content, language, options))
- if l[-1] == ('', u'\n'):
+ if l[-1] == ('', '\n'):
l = l[:-1]
for cls, value in l:
if withln and "\n" in value:
@@ -249,7 +267,7 @@ def code_block_directive(name, arguments, options, content, lineno, # The first piece, pass as-is
code_block += nodes.Text(values[0], values[0])
# On the second and later pieces, insert \n and linenos
- linenos = range(lineno, lineno + len(values))
+ linenos = list(range(lineno, lineno + len(values)))
for chunk, ln in zip(values, linenos)[1:]:
if ln <= total_lines:
code_block += nodes.inline(fstr % ln, fstr % ln,
@@ -319,7 +337,7 @@ def listings_directive(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine):
fname = arguments[0]
options['include'] = os.path.join('listings', fname)
- target = urlparse.urlunsplit(("link", 'listing', fname, '', ''))
+ target = urlunsplit(("link", 'listing', fname, '', ''))
generated_nodes = [core.publish_doctree('`%s <%s>`_' % (fname, target))[0]]
generated_nodes += code_block_directive(name, [arguments[1]],
options, content, lineno, content_offset, block_text,
diff --git a/nikola/plugins/compile_rest/slides.py b/nikola/plugins/compile_rest/slides.py new file mode 100644 index 0000000..942a7d4 --- /dev/null +++ b/nikola/plugins/compile_rest/slides.py @@ -0,0 +1,89 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +import json + +from docutils import nodes +from docutils.parsers.rst import Directive, directives + +class slides(Directive): + + """ Restructured text extension for inserting slideshows.""" + + has_content = True + option_spec = { + "preload": directives.flag, + "preloadImage": directives.uri, + "container": directives.unchanged, + "generateNextPrev": directives.flag, + "next": directives.unchanged, + "prev": directives.unchanged, + "pagination": directives.flag, + "generatePagination": directives.flag, + "paginationClass": directives.unchanged, + "currentClass": directives.unchanged, + "fadeSpeed": directives.positive_int, + "fadeEasing": directives.unchanged, + "slideSpeed": directives.positive_int, + "slideEasing": directives.unchanged, + "start": directives.positive_int, + "effect": directives.unchanged, + "crossfade": directives.flag, + "randomize": directives.flag, + "play": directives.positive_int, + "pause": directives.positive_int, + "hoverPause": directives.flag, + "autoHeight": directives.flag, + "autoHeightSpeed": directives.positive_int, + "bigTarget": directives.flag, + "animationStart": directives.unchanged, + "animationComplete": directives.unchanged, + } + + def run(self): + if len(self.content) == 0: + return + for opt in ("preload", "generateNextPrev", "pagination", "generatePagination", + "crossfade", "randomize", "hoverPause", "autoHeight", "bigTarget"): + if opt in self.options: + self.options[opt] = True + options = { + "autoHeight": True, + "bigTarget": True, + "paginationClass": "pager", + "currentClass": "slide-current" + } + options.update(self.options) + options = json.dumps(options) + output = [] + output.append("""<script> $(function(){ $("#slides").slides(%s); }); </script>""" % options) + output.append("""<div id="slides" class="slides"><div class="slides_container">""") + for image in self.content: + output.append("""<div><img src="%s"></div>""" % image) + output.append("""</div></div>""") + + return [nodes.raw('', '\n'.join(output), format='html')] + + +directives.register_directive('slides', slides) diff --git a/nikola/plugins/compile_rest/youtube.py b/nikola/plugins/compile_rest/youtube.py index 584160b..0765158 100644 --- a/nikola/plugins/compile_rest/youtube.py +++ b/nikola/plugins/compile_rest/youtube.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + from docutils import nodes from docutils.parsers.rst import directives diff --git a/nikola/plugins/task_archive.py b/nikola/plugins/task_archive.py index 4c97101..cafb7e3 100644 --- a/nikola/plugins/task_archive.py +++ b/nikola/plugins/task_archive.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import os from nikola.plugin_categories import Task @@ -18,39 +42,36 @@ class Archive(Task): } self.site.scan_posts() # TODO add next/prev links for years - template_name = "list.tmpl" + template_name = "list_post.tmpl" # TODO: posts_per_year is global, kill it - for year, posts in self.site.posts_per_year.items(): + for year, posts in list(self.site.posts_per_year.items()): for lang in kw["translations"]: output_name = os.path.join( kw['output_folder'], self.site.path("archive", year, lang)) post_list = [self.site.global_data[post] for post in posts] - post_list.sort(cmp=lambda a, b: cmp(a.date, b.date)) + post_list.sort(key=lambda a: a.date) post_list.reverse() context = {} context["lang"] = lang - context["items"] = [("[%s] %s" % - (post.date, post.title(lang)), post.permalink(lang)) - for post in post_list] + context["posts"] = post_list context["permalink"] = self.site.link("archive", year, lang) context["title"] = kw["messages"][lang]["Posts for year %s"]\ % year - for task in self.site.generic_post_list_renderer( + task = self.site.generic_post_list_renderer( lang, post_list, output_name, template_name, kw['filters'], context, - ): - task['uptodate'] = [config_changed({ - 1: task['uptodate'][0].config, - 2: kw})] - task['basename'] = self.name - yield task + ) + task_cfg = {1: task['uptodate'][0].config, 2: kw} + task['uptodate'] = [config_changed(task_cfg)] + task['basename'] = self.name + yield task # And global "all your years" page - years = self.site.posts_per_year.keys() + years = list(self.site.posts_per_year.keys()) years.sort(reverse=True) template_name = "list.tmpl" kw['years'] = years @@ -62,16 +83,15 @@ class Archive(Task): context["items"] = [(year, self.site.link("archive", year, lang)) for year in years] context["permalink"] = self.site.link("archive", None, lang) - for task in self.site.generic_post_list_renderer( + task = self.site.generic_post_list_renderer( lang, [], output_name, template_name, kw['filters'], context, - ): - task['uptodate'] = [config_changed({ - 1: task['uptodate'][0].config, - 2: kw})] - task['basename'] = self.name - yield task + ) + task_cfg = {1: task['uptodate'][0].config, 2: kw} + task['uptodate'] = [config_changed(task_cfg)] + task['basename'] = self.name + yield task diff --git a/nikola/plugins/task_copy_assets.py b/nikola/plugins/task_copy_assets.py index ac31fd7..6b9c6a5 100644 --- a/nikola/plugins/task_copy_assets.py +++ b/nikola/plugins/task_copy_assets.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import os from nikola.plugin_categories import Task @@ -21,7 +45,7 @@ class CopyAssets(Task): "output_folder": self.site.config['OUTPUT_FOLDER'], "filters": self.site.config['FILTERS'], } - + flag = True tasks = {} for theme_name in kw['themes']: src = os.path.join(utils.get_theme_path(theme_name), 'assets') @@ -32,4 +56,13 @@ class CopyAssets(Task): tasks[task['name']] = task task['uptodate'] = [utils.config_changed(kw)] task['basename'] = self.name + flag = False yield utils.apply_filters(task, kw['filters']) + + if flag: + yield { + 'basename': self.name, + 'name': 'None', + 'uptodate': [True], + 'actions': [], + } diff --git a/nikola/plugins/task_copy_files.py b/nikola/plugins/task_copy_files.py index a053905..f8d761d 100644 --- a/nikola/plugins/task_copy_files.py +++ b/nikola/plugins/task_copy_files.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import os from nikola.plugin_categories import Task diff --git a/nikola/plugins/task_create_bundles.py b/nikola/plugins/task_create_bundles.py index ebca0b7..4903699 100644 --- a/nikola/plugins/task_create_bundles.py +++ b/nikola/plugins/task_create_bundles.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import os try: @@ -25,6 +49,7 @@ class BuildBundles(LateTask): kw = { 'filters': self.site.config['FILTERS'], 'output_folder': self.site.config['OUTPUT_FOLDER'], + 'cache_folder': self.site.config['CACHE_FOLDER'], 'theme_bundles': get_theme_bundles(self.site.THEMES), } @@ -32,7 +57,7 @@ class BuildBundles(LateTask): out_dir = os.path.join(kw['output_folder'], os.path.dirname(output)) inputs = [i for i in inputs if os.path.isfile( os.path.join(out_dir, i))] - cache_dir = os.path.join('cache', 'webassets') + cache_dir = os.path.join(kw['cache_folder'], 'webassets') if not os.path.isdir(cache_dir): os.makedirs(cache_dir) env = webassets.Environment(out_dir, os.path.dirname(output), diff --git a/nikola/plugins/task_indexes.py b/nikola/plugins/task_indexes.py index 2311ef3..6f54145 100644 --- a/nikola/plugins/task_indexes.py +++ b/nikola/plugins/task_indexes.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import os from nikola.plugin_categories import Task @@ -66,16 +90,15 @@ class Indexes(Task): context["permalink"] = self.site.link("index", i, lang) output_name = os.path.join( kw['output_folder'], self.site.path("index", i, lang)) - for task in self.site.generic_post_list_renderer( + task = self.site.generic_post_list_renderer( lang, post_list, output_name, template_name, kw['filters'], context, - ): - task['uptodate'] = [config_changed({ - 1: task['uptodate'][0].config, - 2: kw})] - task['basename'] = 'render_indexes' - yield task + ) + task_cfg = {1: task['uptodate'][0].config, 2: kw} + task['uptodate'] = [config_changed(task_cfg)] + task['basename'] = 'render_indexes' + yield task diff --git a/nikola/plugins/task_redirect.py b/nikola/plugins/task_redirect.py index 7c2ccb1..d7117ec 100644 --- a/nikola/plugins/task_redirect.py +++ b/nikola/plugins/task_redirect.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import codecs import os @@ -33,7 +57,7 @@ class Redirect(Task): src_path = os.path.join(kw["output_folder"], src) yield { 'basename': self.name, - 'name': src_path, + 'name': src_path.encode('utf8'), 'targets': [src_path], 'actions': [(create_redirect, (src_path, dst))], 'clean': True, @@ -42,6 +66,10 @@ class Redirect(Task): def create_redirect(src, dst): + try: + os.makedirs(os.path.dirname(src)) + except: + pass with codecs.open(src, "wb+", "utf8") as fd: fd.write(('<head>' + '<meta HTTP-EQUIV="REFRESH" content="0; url=%s">' + diff --git a/nikola/plugins/task_render_galleries.py b/nikola/plugins/task_render_galleries.py index 27e13ea..72d0581 100644 --- a/nikola/plugins/task_render_galleries.py +++ b/nikola/plugins/task_render_galleries.py @@ -1,3 +1,28 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import unicode_literals import codecs import datetime import glob @@ -23,7 +48,7 @@ from nikola import utils class Galleries(Task): """Copy theme assets into output.""" - name = "render_galleries" + name = str("render_galleries") dates = {} def gen_tasks(self): @@ -33,6 +58,7 @@ class Galleries(Task): 'thumbnail_size': self.site.config['THUMBNAIL_SIZE'], 'max_image_size': self.site.config['MAX_IMAGE_SIZE'], 'output_folder': self.site.config['OUTPUT_FOLDER'], + 'cache_folder': self.site.config['CACHE_FOLDER'], 'default_lang': self.site.config['DEFAULT_LANG'], 'blog_description': self.site.config['BLOG_DESCRIPTION'], 'use_filename_as_title': self.site.config['USE_FILENAME_AS_TITLE'], @@ -48,7 +74,7 @@ class Galleries(Task): gallery_list.append(root) if not gallery_list: yield { - 'basename': 'render_galleries', + 'basename': str('render_galleries'), 'actions': [], } return @@ -66,8 +92,8 @@ class Galleries(Task): self.site.path("gallery", gallery_name, None))) if not os.path.isdir(output_gallery): yield { - 'basename': 'render_galleries', - 'name': output_gallery, + 'basename': str('render_galleries'), + 'name': str(output_gallery), 'actions': [(os.makedirs, (output_gallery,))], 'targets': [output_gallery], 'clean': True, @@ -91,8 +117,8 @@ class Galleries(Task): except IOError: excluded_image_name_list = [] - excluded_image_list = map(add_gallery_path, - excluded_image_name_list) + excluded_image_list = list(map(add_gallery_path, + excluded_image_name_list)) image_set = set(image_list) - set(excluded_image_list) image_list = list(image_set) except IOError: @@ -107,17 +133,16 @@ class Galleries(Task): # TODO: write this in human paths = ['/'.join(['..'] * (len(crumbs) - 1 - i)) for i in range(len(crumbs[:-1]))] + ['#'] - crumbs = zip(paths, crumbs) + crumbs = list(zip(paths, crumbs)) image_list = [x for x in image_list if "thumbnail" not in x] # Sort by date - image_list.sort(cmp=lambda a, b: cmp( - self.image_date(a), self.image_date(b))) + image_list.sort(key=lambda a: self.image_date(a)) image_name_list = [os.path.basename(x) for x in image_list] thumbs = [] # Do thumbnails and copy originals - for img, img_name in zip(image_list, image_name_list): + for img, img_name in list(zip(image_list, image_name_list)): # img is "galleries/name/image_name.jpg" # img_name is "image_name.jpg" # fname, ext are "image_name", ".jpg" @@ -130,8 +155,8 @@ class Galleries(Task): orig_dest_path = os.path.join(output_gallery, img_name) thumbs.append(os.path.basename(thumb_path)) yield { - 'basename': 'render_galleries', - 'name': thumb_path, + 'basename': str('render_galleries'), + 'name': thumb_path.encode('utf8'), 'file_dep': [img], 'targets': [thumb_path], 'actions': [ @@ -142,8 +167,8 @@ class Galleries(Task): 'uptodate': [utils.config_changed(kw)], } yield { - 'basename': 'render_galleries', - 'name': orig_dest_path, + 'basename': str('render_galleries'), + 'name': orig_dest_path.encode('utf8'), 'file_dep': [img], 'targets': [orig_dest_path], 'actions': [ @@ -165,8 +190,8 @@ class Galleries(Task): fname + ".thumbnail" + ext) excluded_dest_path = os.path.join(output_gallery, img_name) yield { - 'basename': 'render_galleries', - 'name': excluded_thumb_dest_path, + 'basename': str('render_galleries'), + 'name': excluded_thumb_dest_path.encode('utf8'), 'file_dep': [exclude_path], #'targets': [excluded_thumb_dest_path], 'actions': [ @@ -176,8 +201,8 @@ class Galleries(Task): 'uptodate': [utils.config_changed(kw)], } yield { - 'basename': 'render_galleries', - 'name': excluded_dest_path, + 'basename': str('render_galleries'), + 'name': excluded_dest_path.encode('utf8'), 'file_dep': [exclude_path], #'targets': [excluded_dest_path], 'actions': [ @@ -193,11 +218,11 @@ class Galleries(Task): context["title"] = os.path.basename(gallery_path) context["description"] = kw["blog_description"] if kw['use_filename_as_title']: - img_titles = ['title="%s"' % utils.unslugify(fn[:-4]) + img_titles = ['id="%s" alt="%s" title="%s"' % (fn[:-4], fn[:-4], utils.unslugify(fn[:-4])) for fn in image_name_list] else: img_titles = [''] * len(image_name_list) - context["images"] = zip(image_name_list, thumbs, img_titles) + context["images"] = list(zip(image_name_list, thumbs, img_titles)) context["folders"] = folder_list context["crumbs"] = crumbs context["permalink"] = self.site.link( @@ -206,14 +231,14 @@ class Galleries(Task): # Use galleries/name/index.txt to generate a blurb for # the gallery, if it exists index_path = os.path.join(gallery_path, "index.txt") - cache_dir = os.path.join('cache', 'galleries') + cache_dir = os.path.join(kw["cache_folder"], 'galleries') if not os.path.isdir(cache_dir): os.makedirs(cache_dir) - index_dst_path = os.path.join(cache_dir, unicode(uuid.uuid1())+'.html') + index_dst_path = os.path.join(cache_dir, str(uuid.uuid1())+'.html') if os.path.exists(index_path): compile_html = self.site.get_compiler(index_path) yield { - 'basename': 'render_galleries', + 'basename': str('render_galleries'), 'name': index_dst_path.encode('utf-8'), 'file_dep': [index_path], 'targets': [index_dst_path], @@ -236,8 +261,8 @@ class Galleries(Task): self.site.render_template(template_name, output_name, context) yield { - 'basename': 'render_galleries', - 'name': output_name, + 'basename': str('render_galleries'), + 'name': output_name.encode('utf8'), 'file_dep': file_dep, 'targets': [output_name], 'actions': [(render_gallery, @@ -262,7 +287,7 @@ class Galleries(Task): except Exception: exif = None if exif is not None: - for tag, value in exif.items(): + for tag, value in list(exif.items()): decoded = ExifTags.TAGS.get(tag, tag) if decoded == 'Orientation': @@ -284,13 +309,13 @@ class Galleries(Task): def image_date(self, src): """Try to figure out the date of the image.""" if src not in self.dates: - im = Image.open(src) try: + im = Image.open(src) exif = im._getexif() except Exception: exif = None if exif is not None: - for tag, value in exif.items(): + for tag, value in list(exif.items()): decoded = ExifTags.TAGS.get(tag, tag) if decoded == 'DateTimeOriginal': try: diff --git a/nikola/plugins/task_render_listings.py b/nikola/plugins/task_render_listings.py index 7ec6e42..e3334c2 100644 --- a/nikola/plugins/task_render_listings.py +++ b/nikola/plugins/task_render_listings.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import os from pygments import highlight diff --git a/nikola/plugins/task_render_pages.py b/nikola/plugins/task_render_pages.py index 954dc47..1892c13 100644 --- a/nikola/plugins/task_render_pages.py +++ b/nikola/plugins/task_render_pages.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + from nikola.plugin_categories import Task from nikola.utils import config_changed diff --git a/nikola/plugins/task_render_posts.py b/nikola/plugins/task_render_posts.py index 44888f2..48a0384 100644 --- a/nikola/plugins/task_render_posts.py +++ b/nikola/plugins/task_render_posts.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + from copy import copy import os diff --git a/nikola/plugins/task_render_rss.py b/nikola/plugins/task_render_rss.py index bee1192..54b66bf 100644 --- a/nikola/plugins/task_render_rss.py +++ b/nikola/plugins/task_render_rss.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import os from nikola import utils @@ -30,7 +54,7 @@ class RenderRSS(Task): deps += post.deps(lang) yield { 'basename': 'render_rss', - 'name': output_name, + 'name': output_name.encode('utf8'), 'file_dep': deps, 'targets': [output_name], 'actions': [(utils.generic_rss_renderer, diff --git a/nikola/plugins/task_render_sources.py b/nikola/plugins/task_render_sources.py index ae5ce23..3a05b96 100644 --- a/nikola/plugins/task_render_sources.py +++ b/nikola/plugins/task_render_sources.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import os from nikola.plugin_categories import Task diff --git a/nikola/plugins/task_render_tags.py b/nikola/plugins/task_render_tags.py index 61629ec..026ba75 100644 --- a/nikola/plugins/task_render_tags.py +++ b/nikola/plugins/task_render_tags.py @@ -1,3 +1,29 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#from __future__ import unicode_literals +import json import os from nikola.plugin_categories import Task @@ -30,151 +56,187 @@ class RenderTags(Task): if not self.site.posts_per_tag: yield { - 'basename': self.name, + 'basename': str(self.name), 'actions': [], } return - def page_name(tagname, i, lang): - """Given tag, n, returns a page name.""" - name = self.site.path("tag", tag, lang) - if i: - name = name.replace('.html', '-%s.html' % i) - return name - - for tag, posts in self.site.posts_per_tag.items(): + for tag, posts in list(self.site.posts_per_tag.items()): post_list = [self.site.global_data[post] for post in posts] - post_list.sort(cmp=lambda a, b: cmp(a.date, b.date)) + post_list.sort(key=lambda a: a.date) post_list.reverse() for lang in kw["translations"]: - #Render RSS - output_name = os.path.join(kw['output_folder'], - self.site.path("tag_rss", tag, lang)) - deps = [] - post_list = [self.site.global_data[post] for post in posts - if self.site.global_data[post].use_in_feeds] - post_list.sort(cmp=lambda a, b: cmp(a.date, b.date)) - post_list.reverse() - for post in post_list: - deps += post.deps(lang) - yield { - 'name': output_name.encode('utf8'), - 'file_dep': deps, - 'targets': [output_name], - 'actions': [(utils.generic_rss_renderer, - (lang, "%s (%s)" % (kw["blog_title"], tag), - kw["blog_url"], kw["blog_description"], - post_list, output_name))], - 'clean': True, - 'uptodate': [utils.config_changed(kw)], - 'basename': self.name - } + yield self.tag_rss(tag, lang, posts, kw) # Render HTML if kw['tag_pages_are_indexes']: - # We render a sort of index page collection using only - # this tag's posts. - - # FIXME: deduplicate this with render_indexes - template_name = "index.tmpl" - # Split in smaller lists - lists = [] - while post_list: - lists.append(post_list[ - :kw["index_display_post_count"]]) - post_list = post_list[ - kw["index_display_post_count"]:] - num_pages = len(lists) - for i, post_list in enumerate(lists): - context = {} - # On a tag page, the feeds include the tag's feeds - rss_link = \ - """<link rel="alternate" type="application/rss+xml" """\ - """type="application/rss+xml" title="RSS for tag """\ - """%s (%s)" href="%s">""" % \ - (tag, lang, self.site.link("tag_rss", tag, lang)) - context['rss_link'] = rss_link - output_name = os.path.join(kw['output_folder'], - page_name(tag, i, lang)) - context["title"] = kw["messages"][lang][ - u"Posts about %s"] % tag - context["prevlink"] = None - context["nextlink"] = None - context['index_teasers'] = kw['index_teasers'] - if i > 1: - context["prevlink"] = os.path.basename( - page_name(tag, i - 1, lang)) - if i == 1: - context["prevlink"] = os.path.basename( - page_name(tag, 0, lang)) - if i < num_pages - 1: - context["nextlink"] = os.path.basename( - page_name(tag, i + 1, lang)) - context["permalink"] = self.site.link("tag", tag, lang) - context["tag"] = tag - for task in self.site.generic_post_list_renderer( - lang, - post_list, - output_name, - template_name, - kw['filters'], - context, - ): - task['uptodate'] = [utils.config_changed({ - 1: task['uptodate'][0].config, - 2: kw})] - task['basename'] = self.name - yield task + yield self.tag_page_as_index(tag, lang, post_list, kw) else: - # We render a single flat link list with this tag's posts - template_name = "tag.tmpl" - output_name = os.path.join(kw['output_folder'], - self.site.path("tag", tag, lang)) - context = {} - context["lang"] = lang - context["title"] = kw["messages"][lang][ - u"Posts about %s"] % tag - context["items"] = [("[%s] %s" % (post.date, - post.title(lang)), - post.permalink(lang)) for post in post_list] - context["permalink"] = self.site.link("tag", tag, lang) - context["tag"] = tag - for task in self.site.generic_post_list_renderer( - lang, - post_list, - output_name, - template_name, - kw['filters'], - context, - ): - task['uptodate'] = [utils.config_changed({ - 1: task['uptodate'][0].config, - 2: kw})] - task['basename'] = self.name - yield task - - # And global "all your tags" page - tags = self.site.posts_per_tag.keys() + yield self.tag_page_as_list(tag, lang, post_list, kw) + + yield self.list_tags_page(kw) + + # Tag cloud json file + tag_cloud_data = {} + for tag, posts in self.site.posts_per_tag.items(): + tag_cloud_data[tag] = [len(posts), self.site.link( + 'tag', tag, self.site.config['DEFAULT_LANG'])] + output_name = os.path.join(kw['output_folder'], + 'assets','js','tag_cloud_data.json') + + def write_tag_data(data): + try: + os.makedirs(os.path.dirname(output_name)) + except: + pass + with open(output_name, 'wb+') as fd: + fd.write(json.dumps(data)) + + task = { + 'basename': str(self.name), + 'name': str(output_name) + } + task['uptodate'] = [utils.config_changed(tag_cloud_data)] + task['targets'] = [output_name] + task['actions'] = [(write_tag_data,[tag_cloud_data])] + yield task + + def list_tags_page(self, kw): + """a global "all your tags" page for each language""" + tags = list(self.site.posts_per_tag.keys()) tags.sort() template_name = "tags.tmpl" kw['tags'] = tags for lang in kw["translations"]: output_name = os.path.join( kw['output_folder'], self.site.path('tag_index', None, lang)) + output_name = output_name.encode('utf8') context = {} - context["title"] = kw["messages"][lang][u"Tags"] + context["title"] = kw["messages"][lang]["Tags"] context["items"] = [(tag, self.site.link("tag", tag, lang)) for tag in tags] context["permalink"] = self.site.link("tag_index", None, lang) - for task in self.site.generic_post_list_renderer( + task = self.site.generic_post_list_renderer( lang, [], output_name, template_name, kw['filters'], context, - ): - task['uptodate'] = [utils.config_changed({ - 1: task['uptodate'][0].config, - 2: kw})] - yield task + ) + task_cfg = {1: task['uptodate'][0].config, 2: kw} + task['uptodate'] = [utils.config_changed(task_cfg)] + yield task + + + def tag_page_as_index(self, tag, lang, post_list, kw): + """render a sort of index page collection using only this tag's posts.""" + + def page_name(tagname, i, lang): + """Given tag, n, returns a page name.""" + name = self.site.path("tag", tag, lang) + if i: + name = name.replace('.html', '-%s.html' % i) + return name + + # FIXME: deduplicate this with render_indexes + template_name = "index.tmpl" + # Split in smaller lists + lists = [] + while post_list: + lists.append(post_list[:kw["index_display_post_count"]]) + post_list = post_list[kw["index_display_post_count"]:] + num_pages = len(lists) + for i, post_list in enumerate(lists): + context = {} + # On a tag page, the feeds include the tag's feeds + rss_link = \ + """<link rel="alternate" type="application/rss+xml" """\ + """type="application/rss+xml" title="RSS for tag """\ + """%s (%s)" href="%s">""" % \ + (tag, lang, self.site.link("tag_rss", tag, lang)) + context['rss_link'] = rss_link + output_name = os.path.join(kw['output_folder'], + page_name(tag, i, lang)) + output_name = output_name.encode('utf8') + context["title"] = kw["messages"][lang][ + "Posts about %s"] % tag + context["prevlink"] = None + context["nextlink"] = None + context['index_teasers'] = kw['index_teasers'] + if i > 1: + context["prevlink"] = os.path.basename( + page_name(tag, i - 1, lang)) + if i == 1: + context["prevlink"] = os.path.basename( + page_name(tag, 0, lang)) + if i < num_pages - 1: + context["nextlink"] = os.path.basename( + page_name(tag, i + 1, lang)) + context["permalink"] = self.site.link("tag", tag, lang) + context["tag"] = tag + task = self.site.generic_post_list_renderer( + lang, + post_list, + output_name, + template_name, + kw['filters'], + context, + ) + task_cfg = {1: task['uptodate'][0].config, 2: kw} + task['uptodate'] = [utils.config_changed(task_cfg)] + task['basename'] = str(self.name) + yield task + + + def tag_page_as_list(self, tag, lang, post_list, kw): + """We render a single flat link list with this tag's posts""" + template_name = "tag.tmpl" + output_name = os.path.join(kw['output_folder'], + self.site.path("tag", tag, lang)) + output_name = output_name.encode('utf8') + context = {} + context["lang"] = lang + context["title"] = kw["messages"][lang]["Posts about %s"] % tag + context["posts"] = post_list + context["permalink"] = self.site.link("tag", tag, lang) + context["tag"] = tag + task = self.site.generic_post_list_renderer( + lang, + post_list, + output_name, + template_name, + kw['filters'], + context, + ) + task_cfg = {1: task['uptodate'][0].config, 2: kw} + task['uptodate'] = [utils.config_changed(task_cfg)] + task['basename'] = str(self.name) + yield task + + + def tag_rss(self, tag, lang, posts, kw): + """RSS for a single tag / language""" + #Render RSS + output_name = os.path.join(kw['output_folder'], + self.site.path("tag_rss", tag, lang)) + output_name = output_name.encode('utf8') + deps = [] + post_list = [self.site.global_data[post] for post in posts + if self.site.global_data[post].use_in_feeds] + post_list.sort(key=lambda a: a.date) + post_list.reverse() + for post in post_list: + deps += post.deps(lang) + return { + 'basename': str(self.name), + 'name': output_name, + 'file_dep': deps, + 'targets': [output_name], + 'actions': [(utils.generic_rss_renderer, + (lang, "%s (%s)" % (kw["blog_title"], tag), + kw["blog_url"], kw["blog_description"], + post_list, output_name))], + 'clean': True, + 'uptodate': [utils.config_changed(kw)], + } diff --git a/nikola/plugins/task_sitemap/__init__.py b/nikola/plugins/task_sitemap/__init__.py index 87b72bf..1ed6c21 100644 --- a/nikola/plugins/task_sitemap/__init__.py +++ b/nikola/plugins/task_sitemap/__init__.py @@ -1,10 +1,34 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + import os import tempfile from nikola.plugin_categories import LateTask from nikola.utils import config_changed -import sitemap_gen as smap +import sitemap_gen class Sitemap(LateTask): @@ -42,15 +66,15 @@ class Sitemap(LateTask): config_file.close() # Generate sitemap - sitemap = smap.CreateSitemapFromFile(config_file.name, True) + sitemap = sitemap_gen.CreateSitemapFromFile(config_file.name, True) if not sitemap: - smap.output.Log('Configuration file errors -- exiting.', 0) + sitemap_gen.output.Log('Configuration file errors -- exiting.', 0) else: sitemap.Generate() - smap.output.Log('Number of errors: %d' % - smap.output.num_errors, 1) - smap.output.Log('Number of warnings: %d' % - smap.output.num_warns, 1) + sitemap_gen.output.Log('Number of errors: %d' % + sitemap_gen.output.num_errors, 1) + sitemap_gen.output.Log('Number of warnings: %d' % + sitemap_gen.output.num_warns, 1) os.unlink(config_file.name) yield { diff --git a/nikola/plugins/task_sitemap/sitemap_gen.py b/nikola/plugins/task_sitemap/sitemap_gen.py index 43e7c32..eef2b0b 100755 --- a/nikola/plugins/task_sitemap/sitemap_gen.py +++ b/nikola/plugins/task_sitemap/sitemap_gen.py @@ -40,6 +40,7 @@ # # http://www.opensource.org/licenses/bsd-license.php # +from __future__ import print_function __usage__ = \ """A simple script to automatically produce sitemaps for a webserver, @@ -56,8 +57,8 @@ Usage: python sitemap_gen.py --config=config.xml [--help] [--testing] # entire file has been parsed. import sys if sys.hexversion < 0x02020000: - print 'This script requires Python 2.2 or later.' - print 'Currently run with version: %s' % sys.version + print('This script requires Python 2.2 or later.') + print('Currently run with version: %s' % sys.version) sys.exit(1) import fnmatch @@ -70,16 +71,12 @@ import stat import time import types import urllib -import urlparse import xml.sax -# True and False were introduced in Python2.2.2 try: - testTrue=True - del testTrue -except NameError: - True=1 - False=0 + from urlparse import urlparse, urlsplit, urlunsplit +except ImportError: + from urllib.parse import urlparse, urlsplit, urlunsplit # Text encodings ENC_ASCII = 'ASCII' @@ -383,7 +380,7 @@ class Output: if text: text = encoder.NarrowText(text, None) if self._verbose >= level: - print text + print(text) #end def Log def Warn(self, text): @@ -393,7 +390,7 @@ class Output: hash = hashlib.md5(text).digest() if not self._warns_shown.has_key(hash): self._warns_shown[hash] = 1 - print '[WARNING] ' + text + print('[WARNING] ' + text) else: self.Log('(suppressed) [WARNING] ' + text, 3) self.num_warns = self.num_warns + 1 @@ -406,7 +403,7 @@ class Output: hash = hashlib.md5(text).digest() if not self._errors_shown.has_key(hash): self._errors_shown[hash] = 1 - print '[ERROR] ' + text + print('[ERROR] ' + text) else: self.Log('(suppressed) [ERROR] ' + text, 3) self.num_errors = self.num_errors + 1 @@ -416,9 +413,9 @@ class Output: """ Output an error and terminate the program. """ if text: text = encoder.NarrowText(text, None) - print '[FATAL] ' + text + print('[FATAL] ' + text) else: - print 'Fatal error.' + print('Fatal error.') sys.exit(1) #end def Fatal @@ -475,7 +472,7 @@ class URL(object): if not loc: return False narrow = encoder.NarrowText(loc, None) - (scheme, netloc, path, query, frag) = urlparse.urlsplit(narrow) + (scheme, netloc, path, query, frag) = urlsplit(narrow) if (not scheme) or (not netloc): return False return True @@ -491,7 +488,7 @@ class URL(object): narrow = encoder.NarrowText(loc, None) # Escape components individually - (scheme, netloc, path, query, frag) = urlparse.urlsplit(narrow) + (scheme, netloc, path, query, frag) = urlsplit(narrow) unr = '-._~' sub = '!$&\'()*+,;=' netloc = urllib.quote(netloc, unr + sub + '%:@/[]') @@ -501,7 +498,7 @@ class URL(object): # Try built-in IDNA encoding on the netloc try: - (ignore, widenetloc, ignore, ignore, ignore) = urlparse.urlsplit(loc) + (ignore, widenetloc, ignore, ignore, ignore) = urlsplit(loc) for c in widenetloc: if c >= unichr(128): netloc = widenetloc.encode(ENC_IDNA) @@ -522,7 +519,7 @@ class URL(object): bad_netloc = True # Put it all back together - narrow = urlparse.urlunsplit((scheme, netloc, path, query, frag)) + narrow = urlunsplit((scheme, netloc, path, query, frag)) # I let '%' through. Fix any that aren't pre-existing escapes. HEXDIG = '0123456789abcdefABCDEF' @@ -1459,7 +1456,7 @@ class InputSitemap(xml.sax.handler.ContentHandler): % path) except IOError: output.Error('Cannot read from file "%s"' % path) - except xml.sax._exceptions.SAXParseException, e: + except xml.sax._exceptions.SAXParseException as e: output.Error('XML error in the file "%s" (line %d, column %d): %s' % (path, e._linenum, e._colnum, e.getMessage())) @@ -1488,7 +1485,7 @@ class InputSitemap(xml.sax.handler.ContentHandler): for url in urllist: url = URL.Canonicalize(url) output.Log('Index points to Sitemap file at: %s' % url, 2) - (scheme, netloc, path, query, frag) = urlparse.urlsplit(url) + (scheme, netloc, path, query, frag) = urlsplit(url) file = os.path.basename(path) file = urllib.unquote(file) if wide: @@ -1679,7 +1676,7 @@ class PerURLStatistics: def Consume(self, url): """ Log some stats for the URL. At the moment, that means extension. """ if url and url.loc: - (scheme, netloc, path, query, frag) = urlparse.urlsplit(url.loc) + (scheme, netloc, path, query, frag) = urlsplit(url.loc) if not path: return @@ -1930,7 +1927,7 @@ class Sitemap(xml.sax.handler.ContentHandler): file = None except IOError: output.Fatal('Couldn\'t write out to file: %s' % filename) - os.chmod(filename, 0644) + os.chmod(filename, 0o0644) # Flush self._set = [] @@ -1965,7 +1962,7 @@ class Sitemap(xml.sax.handler.ContentHandler): fd = None except IOError: output.Fatal('Couldn\'t write out to file: %s' % filename) - os.chmod(filename, 0644) + os.chmod(filename, 0o0644) #end def WriteIndex def NotifySearch(self): @@ -2011,7 +2008,7 @@ class Sitemap(xml.sax.handler.ContentHandler): query_attr = ping[5] query_map[query_attr] = url query = urllib.urlencode(query_map) - notify = urlparse.urlunsplit((ping[0], ping[1], ping[2], query, ping[4])) + notify = urlunsplit((ping[0], ping[1], ping[2], query, ping[4])) # Send the notification output.Log('Notifying: %s' % ping[1], 1) @@ -2183,7 +2180,7 @@ def CreateSitemapFromFile(configpath, suppress_notify): xml.sax.parse(configpath, sitemap) except IOError: output.Error('Cannot read configuration file: %s' % configpath) - except xml.sax._exceptions.SAXParseException, e: + except xml.sax._exceptions.SAXParseException as e: output.Error('XML error in the config file (line %d, column %d): %s' % (e._linenum, e._colnum, e.getMessage())) except xml.sax._exceptions.SAXReaderNotAvailable: diff --git a/nikola/plugins/template_jinja.py b/nikola/plugins/template_jinja.py index 0893cf7..f88b2c0 100644 --- a/nikola/plugins/template_jinja.py +++ b/nikola/plugins/template_jinja.py @@ -1,7 +1,34 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """Jinja template handlers""" import os -import jinja2 +try: + import jinja2 +except ImportError: + jinja2 = None from nikola.plugin_categories import TemplateSystem @@ -12,8 +39,10 @@ class JinjaTemplates(TemplateSystem): name = "jinja" lookup = None - def set_directories(self, directories): + def set_directories(self, directories, cache_folder): """Createa template lookup.""" + if jinja2 is None: + raise Exception('To use this theme you need to install the "Jinja2" package.') self.lookup = jinja2.Environment(loader=jinja2.FileSystemLoader( directories, encoding='utf-8', @@ -21,7 +50,8 @@ class JinjaTemplates(TemplateSystem): def render_template(self, template_name, output_name, context): """Render the template into output_name using context.""" - + if jinja2 is None: + raise Exception('To use this theme you need to install the "Jinja2" package.') template = self.lookup.get_template(template_name) output = template.render(**context) if output_name is not None: diff --git a/nikola/plugins/template_mako.py b/nikola/plugins/template_mako.py index 7ab5c43..2f8d52c 100644 --- a/nikola/plugins/template_mako.py +++ b/nikola/plugins/template_mako.py @@ -1,3 +1,27 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """Mako template handlers""" import os @@ -29,9 +53,9 @@ class MakoTemplates(TemplateSystem): # TODO: include tags are not handled return deps - def set_directories(self, directories): + def set_directories(self, directories, cache_folder): """Createa template lookup.""" - cache_dir = os.path.join('cache', '.mako.tmp') + cache_dir = os.path.join(cache_folder, '.mako.tmp') if os.path.exists(cache_dir): shutil.rmtree(cache_dir) self.lookup = TemplateLookup( diff --git a/nikola/post.py b/nikola/post.py index f4b0a0e..d5b98f6 100644 --- a/nikola/post.py +++ b/nikola/post.py @@ -1,11 +1,34 @@ # -*- coding: utf-8 -*- +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. import codecs import os import lxml.html -import utils +from . import utils __all__ = ['Post'] @@ -14,7 +37,7 @@ class Post(object): """Represents a blog post or web page.""" - def __init__(self, source_path, destination, use_in_feeds, + def __init__(self, source_path, cache_folder, destination, use_in_feeds, translations, default_lang, blog_url, messages): """Initialize post. @@ -32,7 +55,7 @@ class Post(object): self.source_path = source_path # posts/blah.txt self.post_name = os.path.splitext(source_path)[0] # posts/blah # cache/posts/blah.html - self.base_path = os.path.join('cache', self.post_name + ".html") + self.base_path = os.path.join(cache_folder, self.post_name + ".html") self.metadata_path = self.post_name + ".meta" # posts/blah.meta self.folder = destination self.translations = translations @@ -56,7 +79,7 @@ class Post(object): self.date = utils.to_datetime(self.date) self.tags = [x.strip() for x in self.tags.split(',')] - self.tags = filter(None, self.tags) + self.tags = [_f for _f in self.tags if _f] # While draft comes from the tags, it's not really a tag self.use_in_feeds = use_in_feeds and "draft" not in self.tags @@ -123,7 +146,7 @@ class Post(object): if os.path.isfile(self.metadata_path): deps.append(self.metadata_path) if lang != self.default_lang: - lang_deps = filter(os.path.exists, [x + "." + lang for x in deps]) + lang_deps = list(filter(os.path.exists, [x + "." + lang for x in deps])) deps += lang_deps return deps @@ -166,7 +189,7 @@ class Post(object): pieces = list(os.path.split(self.translations[lang])) pieces += list(os.path.split(self.folder)) pieces += [self.pagenames[lang] + extension] - pieces = filter(None, pieces) + pieces = [_f for _f in pieces if _f] if absolute: pieces = [self.blog_url] + pieces else: diff --git a/nikola/utils.py b/nikola/utils.py index e319a6d..18b4646 100644 --- a/nikola/utils.py +++ b/nikola/utils.py @@ -1,6 +1,31 @@ +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + """Utility functions.""" -from collections import defaultdict +from __future__ import print_function +from collections import defaultdict, Callable import datetime import hashlib import os @@ -12,11 +37,15 @@ import string import subprocess import sys from zipfile import ZipFile as zip +try: + from imp import reload +except ImportError: + pass from doit import tools from unidecode import unidecode -import PyRSS2Gen as rss +from . import PyRSS2Gen as rss __all__ = ['get_theme_path', 'get_theme_chain', 'load_messages', 'copy_tree', 'generic_rss_renderer', @@ -37,11 +66,11 @@ class config_changed(tools.config_changed): """ A copy of doit's but using pickle instead of serializing manually.""" def _calc_digest(self): - if isinstance(self.config, basestring): + if isinstance(self.config, str): return self.config elif isinstance(self.config, dict): data = json.dumps(self.config, cls=CustomEncoder) - if isinstance(data, unicode): # pragma: no cover # python3 + if isinstance(data, str): # pragma: no cover # python3 byte_data = data.encode("utf-8") else: byte_data = data @@ -68,7 +97,7 @@ def get_theme_path(theme): 'data', 'themes', theme) if os.path.isdir(dir_name): return dir_name - raise Exception(u"Can't find theme '%s'" % theme) + raise Exception("Can't find theme '%s'" % theme) def re_meta(line, match): @@ -158,25 +187,25 @@ def load_messages(themes, translations): """ messages = defaultdict(dict) warned = [] + oldpath = sys.path[:] for theme_name in themes[::-1]: msg_folder = os.path.join(get_theme_path(theme_name), 'messages') - oldpath = sys.path sys.path.insert(0, msg_folder) - english = __import__('en') - for lang in translations.keys(): + english = __import__('messages_en') + for lang in list(translations.keys()): # If we don't do the reload, the module is cached - translation = __import__(lang) + translation = __import__('messages_'+lang) reload(translation) if sorted(translation.MESSAGES.keys()) !=\ sorted(english.MESSAGES.keys()) and \ lang not in warned: # FIXME: get real logging in place - print "Warning: Incomplete translation for language '%s'." % lang + print("Warning: Incomplete translation for language '%s'." % lang) warned.append(lang) messages[lang].update(english.MESSAGES) messages[lang].update(translation.MESSAGES) del(translation) - sys.path = oldpath + sys.path = oldpath return messages @@ -210,7 +239,7 @@ def copy_tree(src, dst, link_cutoff=None): dst_file = os.path.join(dst_dir, src_name) src_file = os.path.join(root, src_name) yield { - 'name': dst_file, + 'name': str(dst_file), 'file_dep': [src_file], 'targets': [dst_file], 'actions': [(copy_file, (src_file, dst_file, link_cutoff))], @@ -225,9 +254,9 @@ def generic_rss_renderer(lang, title, link, description, for post in timeline[:10]: args = { 'title': post.title(lang), - 'link': post.permalink(lang), + 'link': post.permalink(lang, absolute=True), 'description': post.text(lang, teaser_only=True), - 'guid': post.permalink(lang), + 'guid': post.permalink(lang, absolute=True), 'pubDate': post.date, } items.append(rss.RSSItem(**args)) @@ -288,7 +317,9 @@ def slugify(value): From Django's "django/template/defaultfilters.py". """ value = unidecode(value) - value = unicode(_slugify_strip_re.sub('', value).strip().lower()) + # WARNING: this may not be python2/3 equivalent + #value = unicode(_slugify_strip_re.sub('', value).strip().lower()) + value = str(_slugify_strip_re.sub('', value).strip().lower()) return _slugify_hyphenate_re.sub('-', value) @@ -312,7 +343,7 @@ class UnsafeZipException(Exception): def extract_all(zipfile): pwd = os.getcwd() os.chdir('themes') - z = zip(zipfile) + z = list(zip(zipfile)) namelist = z.namelist() for f in namelist: if f.endswith('/') and '..' in f: @@ -364,11 +395,11 @@ def apply_filters(task, filters): """ def filter_matches(ext): - for key, value in filters.items(): + for key, value in list(filters.items()): if isinstance(key, (tuple, list)): if ext in key: return value - elif isinstance(key, (str, unicode)): + elif isinstance(key, (str, bytes)): if ext == key: return value else: @@ -381,7 +412,7 @@ def apply_filters(task, filters): for action in filter_: def unlessLink(action, target): if not os.path.islink(target): - if callable(action): + if isinstance(action, Callable): action(target) else: subprocess.check_call(action % target, shell=True) |
