diff options
| author | 2013-02-27 09:13:31 -0300 | |
|---|---|---|
| committer | 2013-02-27 09:13:31 -0300 | |
| commit | cb2680529d9447d94546c8c0960f0c4e299af18c (patch) | |
| tree | 335ce0e66c214a120aa51ac78e25afe6585c1a13 | |
| parent | 6e0996d54cad4586645fdc59164708e4b4b9dcec (diff) | |
| parent | 878ba1152ebc64a4a2609d23c9e400a6111db642 (diff) | |
Merge tag 'upstream/5.3'
Upstream version 5.3
46 files changed, 1237 insertions, 390 deletions
diff --git a/.travis.yml b/.travis.yml index 035fa4c..b0f9231 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,5 +10,5 @@ install: - "pip install . --use-mirrors" # We run tests and afterwards nikola to see if the command is executable. script: - - nosetests + - nosetests --with-doctest - nikola diff --git a/CHANGES.txt b/CHANGES.txt index 0b285a9..fe55892 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,31 @@ +New in 5.3 +========== + +Features +-------- + +* Bootstrap 2.3.0 +* Optionally use content distribution networks for jquery and twitter-bootstrap (USE_CDN option) +* Improve progressive rendering by moving javascript to the bottom of pages +* New Brazilian portuguese translation. +* New planetoid experimental extra_plugin + +Bugfixes +-------- + +* Make really sure we import the right conf.py +* Make SLUG_TAG_PATH a config dep for most pages +* Removed meta title tag for better HTML validation +* Removed #999 background from footnote backlink. +* Made footnote references be superscripted. +* Centered figure's image and caption. +* Removed outset border from admonitions. +* Use default theme as last resource for messages/translations +* DATE_FORMAT option was being ignored +* Remove trailing "\" on windows gallery links (Issue #298) +* Inconsistent breadcrumbs in gallery pages (Issue #303) +* Use source files as bundle dependencies instead of outputs (Issue #294) + New in 5.2 ========== @@ -52,6 +80,7 @@ Bugfixes * Get title from filename if not available in metadata. * Don't copy sources if they end in ".html" * Don't link to unexisting translations. +* Sort tags case insensitive. New in v5.1 =========== diff --git a/docs/manual.txt b/docs/manual.txt index 49a474d..caf9780 100644 --- a/docs/manual.txt +++ b/docs/manual.txt @@ -1,7 +1,7 @@ The Nikola Handbook =================== -:Version: 5.2 +:Version: 5.3 :Author: Roberto Alsina <ralsina@netmanagers.com.ar> .. class:: alert alert-info pull-right @@ -14,9 +14,13 @@ All You Need to Know After you have Nikola installed: -Create a site: +Create a empty site: ``nikola init mysite`` +You can create a site with demo files in it with ``nikola init mysite --demo`` + +The rest of these commands have to be executed inside the new ``mysite`` folder. + Create a post: ``nikola new_post`` @@ -216,6 +220,18 @@ After that, run ``nikola init --demo sitename`` and that will create a folder ca Nikola is packaged for some Linux distributions, you may get that instead. +*NOTE*: If you get a ``ERROR: /bin/sh: 1: xslt-config: not found`` or ``fatal error: +libxml/xmlversion.h: No such file or directory`` when running ``pip install -r requirements.txt``, install *libxml* and *libxslt* libraries, like so: + +Debian systems: + + sudo apt-get install libxml2-dev + sudo apt-get install libxslt1-dev + +RHEL systems: + + yum install libxslt-devel libxml2-devel + Getting Started --------------- @@ -772,6 +788,9 @@ different ones, or about other webservers, please share! #. Through the filters feature, you can run your files through arbitrary commands, so that images are recompressed, Javascript is minimized, etc. +#. The USE_CDN option offloads standard Javascript and CSS files to a CDN so they are not + downloaded from your server. + Restructured Text Extensions ---------------------------- diff --git a/extra_plugins/README.txt b/extra_plugins/README.txt new file mode 100644 index 0000000..2a04614 --- /dev/null +++ b/extra_plugins/README.txt @@ -0,0 +1,62 @@ +Extra Plugins +============= + +These are plugins that may not be widely used or that are a bit too radical or +experimental for the general public. + +To enable them for you, create a ``plugins/`` folder in your site, and copy +both the ``.plugin`` file and the matching ``.py`` file or folder. + +Planetoid +--------- + +This plugin converts Nikola into the equivalent of `Planet <http://www.planetplanet.org/>`_ +a feed aggregator. It requires `PeeWee <https://github.com/coleifer/peewee>`_ and +`Feedparser <http://code.google.com/p/feedparser/>`_ to work. + +It has a configuration option: PLANETOID_REFRESH which is the number of minutes +before retrying a feed (defaults to 60). + +You need to create a ``feeds`` file containing the data of which feeds you want to +aggregate. The format is very simple:: + + # Roberto Alsina + http://feeds2.feedburner.com/PostsInLateralOpinionAboutPython + Roberto Alsina + +#. Lines that start with ``#`` are comments and ignored. +#. Lines that start with http are feed URLs. +#. URL lines have to be followed by the "real name" of the feed. + +FIXME: explain the planetoid theme stuff + +After all that is in place, just run ``nikola build`` and you'll get +a planet. + +Local Search +------------ + +If you don't want to depend on google or duckduckgo to implement search for you, +or just want it to wok even if you are offline, enable this plugin and the +search will be performed client side. + +This plugin implements a Tipue-based local search for your site. + +To use it, copy task_localsearch.plugin and task_localsearch +into a plugins/ folder in your nikola site. + +After you build your site, you will have several new files in assets/css and assets/js +and a search.html that you can use as a basis for using this in your site. + +For more information about how to customize it and use it, please refer to the tipue +docs at http://www.tipue.com/search/ + +Tipue is under an MIT license (see MIT-LICENSE.txt) + + +Mustache +-------- + +This task gives you a ``mustache.html`` file which lets you access your whole +blog without reloading the page, using client-side templates. Makes it much +faster and modern ;-) diff --git a/extra_plugins/command_planetoid.plugin b/extra_plugins/command_planetoid.plugin new file mode 100644 index 0000000..8636d49 --- /dev/null +++ b/extra_plugins/command_planetoid.plugin @@ -0,0 +1,9 @@ +[Core] +Name = planetoid +Module = command_planetoid + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://nikola.ralsina.com.ar +Description = Maintain a planet-like site diff --git a/extra_plugins/command_planetoid/__init__.py b/extra_plugins/command_planetoid/__init__.py new file mode 100644 index 0000000..7ccb19e --- /dev/null +++ b/extra_plugins/command_planetoid/__init__.py @@ -0,0 +1,248 @@ +# -*- 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 +import codecs +import datetime +import hashlib +from optparse import OptionParser +import os + +from doit.tools import timeout +import feedparser +import peewee + +from nikola.plugin_categories import Command, Task +from nikola.utils import config_changed + + +class Feed(peewee.Model): + name = peewee.CharField() + url = peewee.CharField(max_length=200) + last_status = peewee.CharField(null=True) + etag = peewee.CharField(max_length=200) + last_modified = peewee.DateTimeField() + + +class Entry(peewee.Model): + date = peewee.DateTimeField() + feed = peewee.ForeignKeyField(Feed) + content = peewee.TextField(max_length=20000) + link = peewee.CharField(max_length=200) + title = peewee.CharField(max_length=200) + guid = peewee.CharField(max_length=200) + + +class Planetoid(Command, Task): + """Maintain a planet-like thing.""" + name = "planetoid" + + def init_db(self): + # setup database + Feed.create_table(fail_silently=True) + Entry.create_table(fail_silently=True) + + def gen_tasks(self): + self.init_db() + for task in self.task_load_feeds(): + yield task + for task in self.task_update_feeds(): + yield task + for task in self.task_generate_posts(): + yield task + + def run(self, *args): + self.init_db() + parser = OptionParser(usage="nikola %s [options]" % self.name) + (options, args) = parser.parse_args(list(args)) + + def task_load_feeds(self): + "Read the feeds file, add it to the database." + feeds = [] + feed = name = None + for line in codecs.open('feeds', 'r', 'utf-8'): + line = line.strip() + if line.startswith("#"): + continue + elif line.startswith(u'http'): + feed = line + elif line: + name = line + if feed and name: + feeds.append([feed, name]) + feed = name = None + + def add_feed(name, url): + f = Feed.create( + name=name, + url=url, + etag='foo', + last_modified=datetime.datetime(1970, 1, 1), + ) + f.save() + + def update_feed_url(feed, url): + feed.url = url + feed.save() + + for feed, name in feeds: + f = Feed.select().where(Feed.name == name) + if not list(f): + yield { + 'basename': self.name, + 'name': name.encode('utf8'), + 'actions': ((add_feed, (name, feed)), ), + 'file_dep': ['feeds'], + } + elif list(f)[0].url != feed: + yield { + 'basename': self.name, + 'name': (u'updating_' + name).encode('utf8'), + 'actions': ((update_feed_url, (list(f)[0], feed)), ), + } + + def task_update_feeds(self): + """Download feed contents, add entries to the database.""" + def update_feed(feed): + modified = feed.last_modified.timetuple() + etag = feed.etag + try: + parsed = feedparser.parse( + feed.url, + etag=etag, + modified=modified + ) + feed.last_status = str(parsed.status) + except: # Probably a timeout + # TODO: log failure + return + if parsed.feed.get('title'): + print(parsed.feed.title) + else: + print(feed.url) + feed.etag = parsed.get('etag', 'foo') + modified = tuple(parsed.get('date_parsed', (1970, 1, 1)))[:6] + print("==========>", modified) + modified = datetime.datetime(*modified) + feed.last_modified = modified + feed.save() + # No point in adding items from missinfg feeds + if parsed.status > 400: + # TODO log failure + return + for entry_data in parsed.entries: + print("=========================================") + date = entry_data.get('published_parsed', None) + if date is None: + date = entry_data.get('updated_parsed', None) + if date is None: + print("Can't parse date from:") + print(entry_data) + return False + print("DATE:===>", date) + date = datetime.datetime(*(date[:6])) + title = "%s: %s" % (feed.name, entry_data.get('title', 'Sin título')) + content = entry_data.get('content', None) + if content: + content = content[0].value + if not content: + content = entry_data.get('description', None) + if not content: + content = entry_data.get('summary', 'Sin contenido') + guid = str(entry_data.get('guid', entry_data.link)) + link = entry_data.link + print(repr([date, title])) + e = list(Entry.select().where(Entry.guid == guid)) + print( + repr(dict( + date=date, + title=title, + content=content, + guid=guid, + feed=feed, + link=link, + )) + ) + if not e: + entry = Entry.create( + date=date, + title=title, + content=content, + guid=guid, + feed=feed, + link=link, + ) + else: + entry = e[0] + entry.date = date + entry.title = title + entry.content = content + entry.link = link + entry.save() + for feed in Feed.select(): + task = { + 'basename': self.name, + 'name': str(feed.url), + 'actions': [(update_feed, (feed, ))], + 'uptodate': [timeout(datetime.timedelta(minutes= + self.site.config.get('PLANETOID_REFRESH', 60)))], + } + yield task + + def task_generate_posts(self): + """Generate post files for the blog entries.""" + def gen_id(entry): + h = hashlib.md5() + h.update(entry.feed.name.encode('utf8')) + h.update(entry.guid) + return h.hexdigest() + + def generate_post(entry): + unique_id = gen_id(entry) + meta_path = os.path.join('posts', unique_id + '.meta') + post_path = os.path.join('posts', unique_id + '.txt') + with codecs.open(meta_path, 'wb+', 'utf8') as fd: + fd.write(u'%s\n' % entry.title.replace('\n', ' ')) + fd.write(u'%s\n' % unique_id) + fd.write(u'%s\n' % entry.date.strftime('%Y/%m/%d %H:%M')) + fd.write(u'\n') + fd.write(u'%s\n' % entry.link) + with codecs.open(post_path, 'wb+', 'utf8') as fd: + fd.write(u'.. raw:: html\n\n') + content = entry.content + if not content: + content = u'Sin contenido' + for line in content.splitlines(): + fd.write(u' %s\n' % line) + + for entry in Entry.select().order_by(Entry.date.desc()): + entry_id = gen_id(entry) + yield { + 'basename': self.name, + 'targets': [os.path.join('posts', entry_id + '.meta'), os.path.join('posts', entry_id + '.txt')], + 'name': entry_id, + 'actions': [(generate_post, (entry,))], + 'uptodate': [config_changed({1: entry})] + } diff --git a/extra_plugins/command_planetoid/index.tmpl b/extra_plugins/command_planetoid/index.tmpl new file mode 100644 index 0000000..da9ff5d --- /dev/null +++ b/extra_plugins/command_planetoid/index.tmpl @@ -0,0 +1,26 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> + % for post in posts: + <div style="border: 2px solid darkgrey; margin-bottom: 12px; border-radius: 4px; padding:12px; overflow: auto;"> + <a href="${post.link}"><h1>${post.title(lang)}</a> + <small> + Publicado: ${post.date} + </small></h1> + ${post.text(lang)} + </div> + % endfor + <div> +<ul class="pager"> + %if prevlink: + <li class="previous"> + <a href="${prevlink}">← Posts posteriores</a> + </li> + %endif + %if nextlink: + <li class="next"> + <a href="${nextlink}">Posts anteriores →</a> + </li> + %endif +</ul> +</%block> diff --git a/extra_plugins/command_planetoid/post.tmpl b/extra_plugins/command_planetoid/post.tmpl new file mode 100644 index 0000000..2c4c220 --- /dev/null +++ b/extra_plugins/command_planetoid/post.tmpl @@ -0,0 +1,10 @@ +## -*- coding: utf-8 -*- +<html> +<body> +<script type="text/javascript"> +<!-- +window.location = "${post.link}" +//--> +</script> +Redirecting you to <a href="${post.link}">the original location.</a> +</body>
\ No newline at end of file diff --git a/extra_plugins/task_localsearch/README.txt b/extra_plugins/task_localsearch/README.txt deleted file mode 100644 index f6f2d64..0000000 --- a/extra_plugins/task_localsearch/README.txt +++ /dev/null @@ -1,12 +0,0 @@ -This plugin implements a Tipue-based local search for your site. - -To use it, copy task_localsearch.plugin and task_localsearch -into a plugins/ folder in your nikola site. - -After you build your site, you will have several new files in assets/css and assets/js -and a search.html that you can use as a basis for using this in your site. - -For more information about how to customize it and use it, please refer to the tipue -docs at http://www.tipue.com/search/ - -Tipue is under an MIT license (see MIT-LICENSE.txt) diff --git a/extra_plugins/task_mustache/__init__.py b/extra_plugins/task_mustache/__init__.py index 98e52d1..0d0e87d 100644 --- a/extra_plugins/task_mustache/__init__.py +++ b/extra_plugins/task_mustache/__init__.py @@ -126,8 +126,7 @@ class Mustache(Task): if langname == lang: continue translations.append({'name': - kw["messages"][langname]["Read in" - "English"], + kw["messages"][langname]["Read in English"], 'link': "javascript:load_data('%s');" % post.permalink(langname).replace( ".html", ".json")}) diff --git a/nikola/conf.py.in b/nikola/conf.py.in index b723744..40e1996 100644 --- a/nikola/conf.py.in +++ b/nikola/conf.py.in @@ -283,6 +283,13 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL, # # Also, there is a local search plugin you can use. +# Use content distribution networks for jquery and twitter-bootstrap css and js +# If this is True, jquery is served from the Google CDN and twitter-bootstrap +# is served from the NetDNA CDN +# Set this to False if you want to host your site without requiring access to +# external resources. +# USE_CDN = False + # Google analytics or whatever else you use. Added to the bottom of <body> # in the default template (base.tmpl). # ANALYTICS = "" diff --git a/nikola/console.py b/nikola/console.py index ad36010..fae0ecd 100644 --- a/nikola/console.py +++ b/nikola/console.py @@ -1,8 +1,11 @@ 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") +try: + import conf + SITE = Nikola(**conf.__dict__) + SITE.scan_posts() + print("You can now access your configuration as conf and your site engine " + "as SITE") +except ImportError: + print("No configuration found.") diff --git a/nikola/data/themes/default/assets/css/bootstrap-responsive.css b/nikola/data/themes/default/assets/css/bootstrap-responsive.css index a3352d7..5215a5d 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.2.2 + * Bootstrap Responsive v2.3.0 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 @@ -8,10 +8,6 @@ * Designed and built with all the love in the world @twitter by @mdo and @fat. */ -@-ms-viewport { - width: device-width; -} - .clearfix { *zoom: 1; } @@ -44,6 +40,10 @@ box-sizing: border-box; } +@-ms-viewport { + width: device-width; +} + .hidden { display: none; visibility: hidden; @@ -95,6 +95,19 @@ } } +.visible-print { + display: none !important; +} + +@media print { + .visible-print { + display: inherit !important; + } + .hidden-print { + display: none !important; + } +} + @media (min-width: 1200px) { .row { margin-left: -30px; @@ -1003,7 +1016,9 @@ margin-bottom: 2px; } .nav-collapse .nav > li > a:hover, - .nav-collapse .dropdown-menu a:hover { + .nav-collapse .nav > li > a:focus, + .nav-collapse .dropdown-menu a:hover, + .nav-collapse .dropdown-menu a:focus { background-color: #f2f2f2; } .navbar-inverse .nav-collapse .nav > li > a, @@ -1011,7 +1026,9 @@ color: #999999; } .navbar-inverse .nav-collapse .nav > li > a:hover, - .navbar-inverse .nav-collapse .dropdown-menu a:hover { + .navbar-inverse .nav-collapse .nav > li > a:focus, + .navbar-inverse .nav-collapse .dropdown-menu a:hover, + .navbar-inverse .nav-collapse .dropdown-menu a:focus { background-color: #111111; } .nav-collapse.in .btn-group { diff --git a/nikola/data/themes/default/assets/css/bootstrap.css b/nikola/data/themes/default/assets/css/bootstrap.css index 8ab3cef..b255056 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.2.2 + * Bootstrap v2.3.0 * * Copyright 2012 Twitter, Inc * Licensed under the Apache License v2.0 @@ -8,6 +8,38 @@ * Designed and built with all the love in the world @twitter by @mdo and @fat. */ +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + article, aside, details, @@ -189,38 +221,6 @@ textarea { } } -.clearfix { - *zoom: 1; -} - -.clearfix:before, -.clearfix:after { - display: table; - line-height: 0; - content: ""; -} - -.clearfix:after { - clear: both; -} - -.hide-text { - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; -} - -.input-block-level { - display: block; - width: 100%; - min-height: 30px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - body { margin: 0; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; @@ -235,7 +235,8 @@ a { text-decoration: none; } -a:hover { +a:hover, +a:focus { color: #005580; text-decoration: underline; } @@ -678,7 +679,8 @@ cite { color: #999999; } -a.muted:hover { +a.muted:hover, +a.muted:focus { color: #808080; } @@ -686,7 +688,8 @@ a.muted:hover { color: #c09853; } -a.text-warning:hover { +a.text-warning:hover, +a.text-warning:focus { color: #a47e3c; } @@ -694,7 +697,8 @@ a.text-warning:hover { color: #b94a48; } -a.text-error:hover { +a.text-error:hover, +a.text-error:focus { color: #953b39; } @@ -702,7 +706,8 @@ a.text-error:hover { color: #3a87ad; } -a.text-info:hover { +a.text-info:hover, +a.text-info:focus { color: #2d6987; } @@ -710,10 +715,23 @@ a.text-info:hover { color: #468847; } -a.text-success:hover { +a.text-success:hover, +a.text-success:focus { color: #356635; } +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + h1, h2, h3, @@ -823,8 +841,10 @@ ol.inline { ul.inline > li, ol.inline > li { display: inline-block; + *display: inline; padding-right: 5px; padding-left: 5px; + *zoom: 1; } dl { @@ -899,9 +919,9 @@ blockquote { blockquote p { margin-bottom: 0; - font-size: 16px; + font-size: 17.5px; font-weight: 300; - line-height: 25px; + line-height: 1.25; } blockquote small { @@ -1646,9 +1666,11 @@ select:focus:invalid:focus { .input-append, .input-prepend { - margin-bottom: 5px; + display: inline-block; + margin-bottom: 10px; font-size: 0; white-space: nowrap; + vertical-align: middle; } .input-append input, @@ -1658,7 +1680,9 @@ select:focus:invalid:focus { .input-append .uneditable-input, .input-prepend .uneditable-input, .input-append .dropdown-menu, -.input-prepend .dropdown-menu { +.input-prepend .dropdown-menu, +.input-append .popover, +.input-prepend .popover { font-size: 14px; } @@ -2049,14 +2073,16 @@ table { } .table-bordered thead:first-child tr:first-child > th:first-child, -.table-bordered tbody:first-child tr:first-child > td:first-child { +.table-bordered tbody:first-child tr:first-child > td:first-child, +.table-bordered tbody:first-child tr:first-child > th: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 tbody:first-child tr:first-child > td:last-child, +.table-bordered tbody:first-child tr:first-child > th:last-child { -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-topright: 4px; @@ -2064,7 +2090,9 @@ table { .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 { +.table-bordered tbody:last-child tr:last-child > th:first-child, +.table-bordered tfoot:last-child tr:last-child > td:first-child, +.table-bordered tfoot:last-child tr:last-child > th:first-child { -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomleft: 4px; @@ -2072,7 +2100,9 @@ table { .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 tbody:last-child tr:last-child > th:last-child, +.table-bordered tfoot:last-child tr:last-child > td:last-child, +.table-bordered tfoot:last-child tr:last-child > th:last-child { -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; -moz-border-radius-bottomright: 4px; @@ -2113,8 +2143,8 @@ table { background-color: #f9f9f9; } -.table-hover tbody tr:hover td, -.table-hover tbody tr:hover th { +.table-hover tbody tr:hover > td, +.table-hover tbody tr:hover > th { background-color: #f5f5f5; } @@ -2211,35 +2241,35 @@ table th[class*="span"], margin-left: 0; } -.table tbody tr.success td { +.table tbody tr.success > td { background-color: #dff0d8; } -.table tbody tr.error td { +.table tbody tr.error > td { background-color: #f2dede; } -.table tbody tr.warning td { +.table tbody tr.warning > td { background-color: #fcf8e3; } -.table tbody tr.info td { +.table tbody tr.info > td { background-color: #d9edf7; } -.table-hover tbody tr.success:hover td { +.table-hover tbody tr.success:hover > td { background-color: #d0e9c6; } -.table-hover tbody tr.error:hover td { +.table-hover tbody tr.error:hover > td { background-color: #ebcccc; } -.table-hover tbody tr.warning:hover td { +.table-hover tbody tr.warning:hover > td { background-color: #faf2cc; } -.table-hover tbody tr.info:hover td { +.table-hover tbody tr.info:hover > td { background-color: #c4e3f3; } @@ -2257,7 +2287,7 @@ table th[class*="span"], background-repeat: no-repeat; } -/* White icons with optional class, or on hover/active states of certain elements */ +/* White icons with optional class, or on hover/focus/active states of certain elements */ .icon-white, .nav-pills > .active > a > [class^="icon-"], @@ -2267,11 +2297,15 @@ table th[class*="span"], .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:focus > [class^="icon-"], .dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > li > a:focus > [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-"] { +.dropdown-submenu:focus > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"], +.dropdown-submenu:focus > a > [class*=" icon-"] { background-image: url("../img/glyphicons-halflings-white.png"); } @@ -2741,6 +2775,7 @@ table th[class*="span"], } .icon-folder-close { + width: 16px; background-position: -384px -120px; } @@ -2909,7 +2944,7 @@ table th[class*="span"], border-bottom: 1px solid #ffffff; } -.dropdown-menu li > a { +.dropdown-menu > li > a { display: block; padding: 3px 20px; clear: both; @@ -2919,9 +2954,10 @@ table th[class*="span"], white-space: nowrap; } -.dropdown-menu li > a:hover, -.dropdown-menu li > a:focus, -.dropdown-submenu:hover > a { +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +.dropdown-submenu:hover > a, +.dropdown-submenu:focus > a { color: #ffffff; text-decoration: none; background-color: #0081c2; @@ -2934,8 +2970,9 @@ table th[class*="span"], filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); } -.dropdown-menu .active > a, -.dropdown-menu .active > a:hover { +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { color: #ffffff; text-decoration: none; background-color: #0081c2; @@ -2949,12 +2986,14 @@ table th[class*="span"], filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); } -.dropdown-menu .disabled > a, -.dropdown-menu .disabled > a:hover { +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { color: #999999; } -.dropdown-menu .disabled > a:hover { +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { text-decoration: none; cursor: default; background-color: transparent; @@ -3130,7 +3169,8 @@ table th[class*="span"], filter: alpha(opacity=20); } -.close:hover { +.close:hover, +.close:focus { color: #000000; text-decoration: none; cursor: pointer; @@ -3167,11 +3207,11 @@ button.close { background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); background-repeat: repeat-x; - border: 1px solid #bbbbbb; + border: 1px solid #cccccc; *border: 0; 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; + border-bottom-color: #b3b3b3; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; @@ -3184,6 +3224,7 @@ button.close { } .btn:hover, +.btn:focus, .btn:active, .btn.active, .btn.disabled, @@ -3202,7 +3243,8 @@ button.close { *margin-left: 0; } -.btn:hover { +.btn:hover, +.btn:focus { color: #333333; text-decoration: none; background-position: 0 -15px; @@ -3306,11 +3348,6 @@ input[type="button"].btn-block { color: rgba(255, 255, 255, 0.75); } -.btn { - border-color: #c5c5c5; - border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25); -} - .btn-primary { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); @@ -3329,6 +3366,7 @@ input[type="button"].btn-block { } .btn-primary:hover, +.btn-primary:focus, .btn-primary:active, .btn-primary.active, .btn-primary.disabled, @@ -3361,6 +3399,7 @@ input[type="button"].btn-block { } .btn-warning:hover, +.btn-warning:focus, .btn-warning:active, .btn-warning.active, .btn-warning.disabled, @@ -3393,6 +3432,7 @@ input[type="button"].btn-block { } .btn-danger:hover, +.btn-danger:focus, .btn-danger:active, .btn-danger.active, .btn-danger.disabled, @@ -3425,6 +3465,7 @@ input[type="button"].btn-block { } .btn-success:hover, +.btn-success:focus, .btn-success:active, .btn-success.active, .btn-success.disabled, @@ -3457,6 +3498,7 @@ input[type="button"].btn-block { } .btn-info:hover, +.btn-info:focus, .btn-info:active, .btn-info.active, .btn-info.disabled, @@ -3489,6 +3531,7 @@ input[type="button"].btn-block { } .btn-inverse:hover, +.btn-inverse:focus, .btn-inverse:active, .btn-inverse.active, .btn-inverse.disabled, @@ -3552,13 +3595,15 @@ input[type="submit"].btn.btn-mini { border-radius: 0; } -.btn-link:hover { +.btn-link:hover, +.btn-link:focus { color: #005580; text-decoration: underline; background-color: transparent; } -.btn-link[disabled]:hover { +.btn-link[disabled]:hover, +.btn-link[disabled]:focus { color: #333333; text-decoration: none; } @@ -3744,8 +3789,6 @@ input[type="submit"].btn.btn-mini { margin-left: 0; } -.btn-mini .caret, -.btn-small .caret, .btn-large .caret { margin-top: 6px; } @@ -3756,6 +3799,11 @@ input[type="submit"].btn.btn-mini { border-left-width: 5px; } +.btn-mini .caret, +.btn-small .caret { + margin-top: 8px; +} + .dropup .btn-large .caret { border-bottom-width: 5px; } @@ -3899,7 +3947,8 @@ input[type="submit"].btn.btn-mini { display: block; } -.nav > li > a:hover { +.nav > li > a:hover, +.nav > li > a:focus { text-decoration: none; background-color: #eeeeee; } @@ -3945,7 +3994,8 @@ input[type="submit"].btn.btn-mini { } .nav-list > .active > a, -.nav-list > .active > a:hover { +.nav-list > .active > a:hover, +.nav-list > .active > a:focus { color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); background-color: #0088cc; @@ -4016,12 +4066,14 @@ input[type="submit"].btn.btn-mini { border-radius: 4px 4px 0 0; } -.nav-tabs > li > a:hover { +.nav-tabs > li > a:hover, +.nav-tabs > li > a:focus { border-color: #eeeeee #eeeeee #dddddd; } .nav-tabs > .active > a, -.nav-tabs > .active > a:hover { +.nav-tabs > .active > a:hover, +.nav-tabs > .active > a:focus { color: #555555; cursor: default; background-color: #ffffff; @@ -4040,7 +4092,8 @@ input[type="submit"].btn.btn-mini { } .nav-pills > .active > a, -.nav-pills > .active > a:hover { +.nav-pills > .active > a:hover, +.nav-pills > .active > a:focus { color: #ffffff; background-color: #0088cc; } @@ -4082,7 +4135,8 @@ input[type="submit"].btn.btn-mini { -moz-border-radius-bottomleft: 4px; } -.nav-tabs.nav-stacked > li > a:hover { +.nav-tabs.nav-stacked > li > a:hover, +.nav-tabs.nav-stacked > li > a:focus { z-index: 2; border-color: #ddd; } @@ -4113,7 +4167,8 @@ input[type="submit"].btn.btn-mini { border-bottom-color: #0088cc; } -.nav .dropdown-toggle:hover .caret { +.nav .dropdown-toggle:hover .caret, +.nav .dropdown-toggle:focus .caret { border-top-color: #005580; border-bottom-color: #005580; } @@ -4134,13 +4189,15 @@ input[type="submit"].btn.btn-mini { border-bottom-color: #555555; } -.nav > .dropdown.active > a:hover { +.nav > .dropdown.active > a:hover, +.nav > .dropdown.active > a:focus { cursor: pointer; } .nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, -.nav > li.dropdown.open.active > a:hover { +.nav > li.dropdown.open.active > a:hover, +.nav > li.dropdown.open.active > a:focus { color: #ffffff; background-color: #999999; border-color: #999999; @@ -4148,14 +4205,16 @@ input[type="submit"].btn.btn-mini { .nav li.dropdown.open .caret, .nav li.dropdown.open.active .caret, -.nav li.dropdown.open a:hover .caret { +.nav li.dropdown.open a:hover .caret, +.nav li.dropdown.open a:focus .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; opacity: 1; filter: alpha(opacity=100); } -.tabs-stacked .open > a:hover { +.tabs-stacked .open > a:hover, +.tabs-stacked .open > a:focus { border-color: #999999; } @@ -4209,13 +4268,15 @@ input[type="submit"].btn.btn-mini { border-radius: 0 0 4px 4px; } -.tabs-below > .nav-tabs > li > a:hover { +.tabs-below > .nav-tabs > li > a:hover, +.tabs-below > .nav-tabs > li > a:focus { border-top-color: #ddd; border-bottom-color: transparent; } .tabs-below > .nav-tabs > .active > a, -.tabs-below > .nav-tabs > .active > a:hover { +.tabs-below > .nav-tabs > .active > a:hover, +.tabs-below > .nav-tabs > .active > a:focus { border-color: transparent #ddd #ddd #ddd; } @@ -4244,12 +4305,14 @@ input[type="submit"].btn.btn-mini { border-radius: 4px 0 0 4px; } -.tabs-left > .nav-tabs > li > a:hover { +.tabs-left > .nav-tabs > li > a:hover, +.tabs-left > .nav-tabs > li > a:focus { border-color: #eeeeee #dddddd #eeeeee #eeeeee; } .tabs-left > .nav-tabs .active > a, -.tabs-left > .nav-tabs .active > a:hover { +.tabs-left > .nav-tabs .active > a:hover, +.tabs-left > .nav-tabs .active > a:focus { border-color: #ddd transparent #ddd #ddd; *border-right-color: #ffffff; } @@ -4267,12 +4330,14 @@ input[type="submit"].btn.btn-mini { border-radius: 0 4px 4px 0; } -.tabs-right > .nav-tabs > li > a:hover { +.tabs-right > .nav-tabs > li > a:hover, +.tabs-right > .nav-tabs > li > a:focus { border-color: #eeeeee #eeeeee #eeeeee #dddddd; } .tabs-right > .nav-tabs .active > a, -.tabs-right > .nav-tabs .active > a:hover { +.tabs-right > .nav-tabs .active > a:hover, +.tabs-right > .nav-tabs .active > a:focus { border-color: #ddd #ddd #ddd transparent; *border-left-color: #ffffff; } @@ -4281,7 +4346,8 @@ input[type="submit"].btn.btn-mini { color: #999999; } -.nav > .disabled > a:hover { +.nav > .disabled > a:hover, +.nav > .disabled > a:focus { text-decoration: none; cursor: default; background-color: transparent; @@ -4347,7 +4413,8 @@ input[type="submit"].btn.btn-mini { text-shadow: 0 1px 0 #ffffff; } -.navbar .brand:hover { +.navbar .brand:hover, +.navbar .brand:focus { text-decoration: none; } @@ -4361,7 +4428,8 @@ input[type="submit"].btn.btn-mini { color: #777777; } -.navbar-link:hover { +.navbar-link:hover, +.navbar-link:focus { color: #333333; } @@ -4379,7 +4447,9 @@ input[type="submit"].btn.btn-mini { .navbar .btn-group .btn, .navbar .input-prepend .btn, -.navbar .input-append .btn { +.navbar .input-append .btn, +.navbar .input-prepend .btn-group, +.navbar .input-append .btn-group { margin-top: 0; } @@ -4587,6 +4657,7 @@ input[type="submit"].btn.btn-mini { } .navbar .btn-navbar:hover, +.navbar .btn-navbar:focus, .navbar .btn-navbar:active, .navbar .btn-navbar.active, .navbar .btn-navbar.disabled, @@ -4656,9 +4727,10 @@ 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 > a:hover .caret, +.navbar .nav li.dropdown > a:focus .caret { + border-top-color: #333333; + border-bottom-color: #333333; } .navbar .nav li.dropdown.open > .dropdown-toggle, @@ -4728,7 +4800,9 @@ input[type="submit"].btn.btn-mini { } .navbar-inverse .brand:hover, -.navbar-inverse .nav > li > a:hover { +.navbar-inverse .nav > li > a:hover, +.navbar-inverse .brand:focus, +.navbar-inverse .nav > li > a:focus { color: #ffffff; } @@ -4757,7 +4831,8 @@ input[type="submit"].btn.btn-mini { color: #999999; } -.navbar-inverse .navbar-link:hover { +.navbar-inverse .navbar-link:hover, +.navbar-inverse .navbar-link:focus { color: #ffffff; } @@ -4773,7 +4848,8 @@ input[type="submit"].btn.btn-mini { background-color: #111111; } -.navbar-inverse .nav li.dropdown > a:hover .caret { +.navbar-inverse .nav li.dropdown > a:hover .caret, +.navbar-inverse .nav li.dropdown > a:focus .caret { border-top-color: #ffffff; border-bottom-color: #ffffff; } @@ -4846,6 +4922,7 @@ input[type="submit"].btn.btn-mini { } .navbar-inverse .btn-navbar:hover, +.navbar-inverse .btn-navbar:focus, .navbar-inverse .btn-navbar:active, .navbar-inverse .btn-navbar.active, .navbar-inverse .btn-navbar.disabled, @@ -4920,6 +4997,7 @@ input[type="submit"].btn.btn-mini { } .pagination ul > li > a:hover, +.pagination ul > li > a:focus, .pagination ul > .active > a, .pagination ul > .active > span { background-color: #f5f5f5; @@ -4933,7 +5011,8 @@ input[type="submit"].btn.btn-mini { .pagination ul > .disabled > span, .pagination ul > .disabled > a, -.pagination ul > .disabled > a:hover { +.pagination ul > .disabled > a:hover, +.pagination ul > .disabled > a:focus { color: #999999; cursor: default; background-color: transparent; @@ -5063,7 +5142,8 @@ input[type="submit"].btn.btn-mini { border-radius: 15px; } -.pager li > a:hover { +.pager li > a:hover, +.pager li > a:focus { text-decoration: none; background-color: #f5f5f5; } @@ -5080,6 +5160,7 @@ input[type="submit"].btn.btn-mini { .pager .disabled > a, .pager .disabled > a:hover, +.pager .disabled > a:focus, .pager .disabled > span { color: #999999; cursor: default; @@ -5209,8 +5290,8 @@ input[type="submit"].btn.btn-mini { position: absolute; z-index: 1030; display: block; - padding: 5px; font-size: 11px; + line-height: 1.4; opacity: 0; filter: alpha(opacity=0); visibility: visible; @@ -5222,24 +5303,28 @@ input[type="submit"].btn.btn-mini { } .tooltip.top { + padding: 5px 0; margin-top: -3px; } .tooltip.right { + padding: 0 5px; margin-left: 3px; } .tooltip.bottom { + padding: 5px 0; margin-top: 3px; } .tooltip.left { + padding: 0 5px; margin-left: -3px; } .tooltip-inner { max-width: 200px; - padding: 3px 8px; + padding: 8px; color: #ffffff; text-align: center; text-decoration: none; @@ -5295,7 +5380,7 @@ input[type="submit"].btn.btn-mini { left: 0; z-index: 1010; display: none; - width: 236px; + max-width: 276px; padding: 1px; text-align: left; white-space: normal; @@ -5342,6 +5427,10 @@ input[type="submit"].btn.btn-mini { border-radius: 5px 5px 0 0; } +.popover-title:empty { + display: none; +} + .popover-content { padding: 9px 14px; } @@ -5473,7 +5562,8 @@ input[type="submit"].btn.btn-mini { transition: all 0.2s ease-in-out; } -a.thumbnail:hover { +a.thumbnail:hover, +a.thumbnail:focus { border-color: #0088cc; -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); @@ -5516,11 +5606,11 @@ a.thumbnail:hover { margin: 0 0 5px; } -.media .pull-left { +.media > .pull-left { margin-right: 10px; } -.media .pull-right { +.media > .pull-right { margin-left: 10px; } @@ -5563,7 +5653,9 @@ a.thumbnail:hover { } a.label:hover, -a.badge:hover { +a.label:focus, +a.badge:hover, +a.badge:focus { color: #ffffff; text-decoration: none; cursor: pointer; @@ -5889,7 +5981,8 @@ a.badge:hover { transition: 0.6s ease-in-out left; } -.carousel-inner > .item > img { +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { display: block; line-height: 1; } @@ -5958,13 +6051,39 @@ a.badge:hover { left: auto; } -.carousel-control:hover { +.carousel-control:hover, +.carousel-control:focus { color: #ffffff; text-decoration: none; opacity: 0.9; filter: alpha(opacity=90); } +.carousel-indicators { + position: absolute; + top: 15px; + right: 15px; + z-index: 5; + margin: 0; + list-style: none; +} + +.carousel-indicators li { + display: block; + float: left; + width: 10px; + height: 10px; + margin-left: 5px; + text-indent: -999px; + background-color: #ccc; + background-color: rgba(255, 255, 255, 0.25); + border-radius: 5px; +} + +.carousel-indicators .active { + background-color: #fff; +} + .carousel-caption { position: absolute; right: 0; diff --git a/nikola/data/themes/default/assets/css/theme.css b/nikola/data/themes/default/assets/css/theme.css index 7fe11ac..6f3d4cb 100644 --- a/nikola/data/themes/default/assets/css/theme.css +++ b/nikola/data/themes/default/assets/css/theme.css @@ -24,3 +24,34 @@ img { } #addthisbox {margin-bottom: 12px;} + +td.label { + /* Issue #290 */ + background-color: inherit; +} + +.footnote-reference { + /* Issue 290 */ + vertical-align: super; + font-size: xx-small; +} + + +.caption { + /* Issue 292 */ + text-align: center; +} + +div.figure > a > img { + /* Issue 292 */ + display: block; + margin-left: auto; + margin-right: auto; +} + +div.admonition, div.attention, div.caution, div.danger, div.error, div.hint, div.important, div.note, div.tip, div.warning { + /* Issue 277 */ + border: 1px solid #aaa; + border-radius: 5px; +} + diff --git a/nikola/data/themes/default/assets/js/bootstrap.js b/nikola/data/themes/default/assets/js/bootstrap.js index 6c15a58..a81171b 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.2.2 + * bootstrap-transition.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#transitions * =================================================== * Copyright 2012 Twitter, Inc. @@ -58,7 +58,7 @@ }) }(window.jQuery);/* ========================================================== - * bootstrap-alert.js v2.2.2 + * bootstrap-alert.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#alerts * ========================================================== * Copyright 2012 Twitter, Inc. @@ -156,7 +156,7 @@ $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) }(window.jQuery);/* ============================================================ - * bootstrap-button.js v2.2.2 + * bootstrap-button.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#buttons * ============================================================ * Copyright 2012 Twitter, Inc. @@ -260,7 +260,7 @@ }) }(window.jQuery);/* ========================================================== - * bootstrap-carousel.js v2.2.2 + * bootstrap-carousel.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#carousel * ========================================================== * Copyright 2012 Twitter, Inc. @@ -289,6 +289,7 @@ var Carousel = function (element, options) { this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') this.options = options this.options.pause == 'hover' && this.$element .on('mouseenter', $.proxy(this.pause, this)) @@ -299,19 +300,24 @@ cycle: function (e) { if (!e) this.paused = false + if (this.interval) clearInterval(this.interval); this.options.interval && !this.paused && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) return this } + , getActiveIndex: function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + return this.$items.index(this.$active) + } + , to: function (pos) { - var $active = this.$element.find('.item.active') - , children = $active.parent().children() - , activePos = children.index($active) + var activeIndex = this.getActiveIndex() , that = this - if (pos > (children.length - 1) || pos < 0) return + if (pos > (this.$items.length - 1) || pos < 0) return if (this.sliding) { return this.$element.one('slid', function () { @@ -319,11 +325,11 @@ }) } - if (activePos == pos) { + if (activeIndex == pos) { return this.pause().cycle() } - return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos])) + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) } , pause: function (e) { @@ -364,10 +370,19 @@ e = $.Event('slide', { relatedTarget: $next[0] + , direction: direction }) if ($next.hasClass('active')) return + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + if ($.support.transition && this.$element.hasClass('slide')) { this.$element.trigger(e) if (e.isDefaultPrevented()) return @@ -412,7 +427,7 @@ if (!data) $this.data('carousel', (data = new Carousel(this, options))) if (typeof option == 'number') data.to(option) else if (action) data[action]() - else if (options.interval) data.cycle() + else if (options.interval) data.pause().cycle() }) } @@ -435,16 +450,23 @@ /* CAROUSEL DATA-API * ================= */ - $(document).on('click.carousel.data-api', '[data-slide]', function (e) { + $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', 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()) + , slideIndex + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('carousel').pause().to(slideIndex).cycle() + } + e.preventDefault() }) }(window.jQuery);/* ============================================================= - * bootstrap-collapse.js v2.2.2 + * bootstrap-collapse.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#collapse * ============================================================= * Copyright 2012 Twitter, Inc. @@ -497,7 +519,7 @@ , actives , hasData - if (this.transitioning) return + if (this.transitioning || this.$element.hasClass('in')) return dimension = this.dimension() scroll = $.camelCase(['scroll', dimension].join('-')) @@ -517,7 +539,7 @@ , hide: function () { var dimension - if (this.transitioning) return + if (this.transitioning || !this.$element.hasClass('in')) return dimension = this.dimension() this.reset(this.$element[dimension]()) this.transition('removeClass', $.Event('hide'), 'hidden') @@ -574,7 +596,7 @@ return this.each(function () { var $this = $(this) , data = $this.data('collapse') - , options = typeof option == 'object' && option + , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option) if (!data) $this.data('collapse', (data = new Collapse(this, options))) if (typeof option == 'string') data[option]() }) @@ -610,7 +632,7 @@ }) }(window.jQuery);/* ============================================================ - * bootstrap-dropdown.js v2.2.2 + * bootstrap-dropdown.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#dropdowns * ============================================================ * Copyright 2012 Twitter, Inc. @@ -692,7 +714,10 @@ isActive = $parent.hasClass('open') - if (!isActive || (isActive && e.keyCode == 27)) return $this.click() + if (!isActive || (isActive && e.keyCode == 27)) { + if (e.which == 27) $parent.find(toggle).focus() + return $this.click() + } $items = $('[role=menu] li:not(.divider):visible a', $parent) @@ -726,8 +751,9 @@ selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 } - $parent = $(selector) - $parent.length || ($parent = $this.parent()) + $parent = selector && $(selector) + + if (!$parent || !$parent.length) $parent = $this.parent() return $parent } @@ -763,14 +789,15 @@ * =================================== */ $(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.2.2 + .on('click.dropdown.data-api', clearMenus) + .on('click.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() }) + .on('.dropdown-menu', function (e) { e.stopPropagation() }) + .on('click.dropdown.data-api' , toggle, Dropdown.prototype.toggle) + .on('keydown.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown) + +}(window.jQuery); +/* ========================================================= + * bootstrap-modal.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#modals * ========================================================= * Copyright 2012 Twitter, Inc. @@ -831,8 +858,7 @@ that.$element.appendTo(document.body) //don't move modals dom position } - that.$element - .show() + that.$element.show() if (transition) { that.$element[0].offsetWidth // force reflow @@ -910,12 +936,13 @@ }) } - , hideModal: function (that) { - this.$element - .hide() - .trigger('hidden') - - this.backdrop() + , hideModal: function () { + var that = this + this.$element.hide() + this.backdrop(function () { + that.removeBackdrop() + that.$element.trigger('hidden') + }) } , removeBackdrop: function () { @@ -943,6 +970,8 @@ this.$backdrop.addClass('in') + if (!callback) return + doAnimate ? this.$backdrop.one($.support.transition.end, callback) : callback() @@ -951,8 +980,8 @@ this.$backdrop.removeClass('in') $.support.transition && this.$element.hasClass('fade')? - this.$backdrop.one($.support.transition.end, $.proxy(this.removeBackdrop, this)) : - this.removeBackdrop() + this.$backdrop.one($.support.transition.end, callback) : + callback() } else if (callback) { callback() @@ -1015,7 +1044,7 @@ }(window.jQuery); /* =========================================================== - * bootstrap-tooltip.js v2.2.2 + * bootstrap-tooltip.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#tooltips * Inspired by the original jQuery.tipsy by Jason Frame * =========================================================== @@ -1054,19 +1083,27 @@ , init: function (type, element, options) { var eventIn , eventOut + , triggers + , trigger + , i this.type = type this.$element = $(element) this.options = this.getOptions(options) this.enabled = true - if (this.options.trigger == 'click') { - this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) - } else if (this.options.trigger != 'manual') { - eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus' - eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur' - this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) - this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) + triggers = this.options.trigger.split(' ') + + for (i = triggers.length; i--;) { + trigger = triggers[i] + if (trigger == 'click') { + this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) + } else if (trigger != 'manual') { + eventIn = trigger == 'hover' ? 'mouseenter' : 'focus' + eventOut = trigger == 'hover' ? 'mouseleave' : 'blur' + this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) + this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) + } } this.options.selector ? @@ -1075,7 +1112,7 @@ } , getOptions: function (options) { - options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data()) + options = $.extend({}, $.fn[this.type].defaults, this.$element.data(), options) if (options.delay && typeof options.delay == 'number') { options.delay = { @@ -1113,14 +1150,16 @@ , show: function () { var $tip - , inside , pos , actualWidth , actualHeight , placement , tp + , e = $.Event('show') if (this.hasContent() && this.enabled) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return $tip = this.tip() this.setContent() @@ -1132,19 +1171,18 @@ this.options.placement.call(this, $tip[0], this.$element[0]) : this.options.placement - inside = /in/.test(placement) - $tip .detach() .css({ top: 0, left: 0, display: 'block' }) - .insertAfter(this.$element) - pos = this.getPosition(inside) + this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element) + + pos = this.getPosition() actualWidth = $tip[0].offsetWidth actualHeight = $tip[0].offsetHeight - switch (inside ? placement.split(' ')[1] : placement) { + switch (placement) { case 'bottom': tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2} break @@ -1159,11 +1197,56 @@ break } - $tip - .offset(tp) - .addClass(placement) - .addClass('in') + this.applyPlacement(tp, placement) + this.$element.trigger('shown') + } + } + + , applyPlacement: function(offset, placement){ + var $tip = this.tip() + , width = $tip[0].offsetWidth + , height = $tip[0].offsetHeight + , actualWidth + , actualHeight + , delta + , replace + + $tip + .offset(offset) + .addClass(placement) + .addClass('in') + + actualWidth = $tip[0].offsetWidth + actualHeight = $tip[0].offsetHeight + + if (placement == 'top' && actualHeight != height) { + offset.top = offset.top + height - actualHeight + replace = true } + + if (placement == 'bottom' || placement == 'top') { + delta = 0 + + if (offset.left < 0){ + delta = offset.left * -2 + offset.left = 0 + $tip.offset(offset) + actualWidth = $tip[0].offsetWidth + actualHeight = $tip[0].offsetHeight + } + + this.replaceArrow(delta - width + actualWidth, actualWidth, 'left') + } else { + this.replaceArrow(actualHeight - height, actualHeight, 'top') + } + + if (replace) $tip.offset(offset) + } + + , replaceArrow: function(delta, dimension, position){ + this + .arrow() + .css(position, delta ? (50 * (1 - delta / dimension) + "%") : '') } , setContent: function () { @@ -1177,6 +1260,10 @@ , hide: function () { var that = this , $tip = this.tip() + , e = $.Event('hide') + + this.$element.trigger(e) + if (e.isDefaultPrevented()) return $tip.removeClass('in') @@ -1195,13 +1282,15 @@ removeWithAnimation() : $tip.detach() + this.$element.trigger('hidden') + return this } , fixTitle: function () { var $e = this.$element if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') { - $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title') + $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') } } @@ -1209,11 +1298,12 @@ return this.getTitle() } - , getPosition: function (inside) { - return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), { - width: this.$element[0].offsetWidth - , height: this.$element[0].offsetHeight - }) + , getPosition: function () { + var el = this.$element[0] + return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : { + width: el.offsetWidth + , height: el.offsetHeight + }, this.$element.offset()) } , getTitle: function () { @@ -1231,6 +1321,10 @@ return this.$tip = this.$tip || $(this.options.template) } + , arrow: function(){ + return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow") + } + , validate: function () { if (!this.$element[0].parentNode) { this.hide() @@ -1252,8 +1346,8 @@ } , toggle: function (e) { - var self = $(e.currentTarget)[this.type](this._options).data(this.type) - self[self.tip().hasClass('in') ? 'hide' : 'show']() + var self = e ? $(e.currentTarget)[this.type](this._options).data(this.type) : this + self.tip().hasClass('in') ? self.hide() : self.show() } , destroy: function () { @@ -1285,10 +1379,11 @@ , placement: 'top' , selector: false , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>' - , trigger: 'hover' + , trigger: 'hover focus' , title: '' , delay: 0 , html: false + , container: false } @@ -1300,8 +1395,9 @@ return this } -}(window.jQuery);/* =========================================================== - * bootstrap-popover.js v2.2.2 +}(window.jQuery); +/* =========================================================== + * bootstrap-popover.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#popovers * =========================================================== * Copyright 2012 Twitter, Inc. @@ -1360,8 +1456,8 @@ , $e = this.$element , o = this.options - content = $e.attr('data-content') - || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content) + content = (typeof o.content == 'function' ? o.content.call($e[0]) : o.content) + || $e.attr('data-content') return content } @@ -1401,7 +1497,7 @@ 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"></div></div></div>' + , template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' }) @@ -1413,8 +1509,9 @@ return this } -}(window.jQuery);/* ============================================================= - * bootstrap-scrollspy.js v2.2.2 +}(window.jQuery); +/* ============================================================= + * bootstrap-scrollspy.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#scrollspy * ============================================================= * Copyright 2012 Twitter, Inc. @@ -1474,7 +1571,7 @@ , $href = /^#\w/.test(href) && $(href) return ( $href && $href.length - && [[ $href.position().top + self.$scrollElement.scrollTop(), href ]] ) || null + && [[ $href.position().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]] ) || null }) .sort(function (a, b) { return a[0] - b[0] }) .each(function () { @@ -1575,7 +1672,7 @@ }) }(window.jQuery);/* ======================================================== - * bootstrap-tab.js v2.2.2 + * bootstrap-tab.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#tabs * ======================================================== * Copyright 2012 Twitter, Inc. @@ -1718,7 +1815,7 @@ }) }(window.jQuery);/* ============================================================= - * bootstrap-typeahead.js v2.2.2 + * bootstrap-typeahead.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#typeahead * ============================================================= * Copyright 2012 Twitter, Inc. @@ -1891,6 +1988,7 @@ , listen: function () { this.$element + .on('focus', $.proxy(this.focus, this)) .on('blur', $.proxy(this.blur, this)) .on('keypress', $.proxy(this.keypress, this)) .on('keyup', $.proxy(this.keyup, this)) @@ -1902,6 +2000,7 @@ this.$menu .on('click', $.proxy(this.click, this)) .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) + .on('mouseleave', 'li', $.proxy(this.mouseleave, this)) } , eventSupported: function(eventName) { @@ -1975,22 +2074,33 @@ e.preventDefault() } + , focus: function (e) { + this.focused = true + } + , blur: function (e) { - var that = this - setTimeout(function () { that.hide() }, 150) + this.focused = false + if (!this.mousedover && this.shown) this.hide() } , click: function (e) { e.stopPropagation() e.preventDefault() this.select() + this.$element.focus() } , mouseenter: function (e) { + this.mousedover = true this.$menu.find('.active').removeClass('active') $(e.currentTarget).addClass('active') } + , mouseleave: function (e) { + this.mousedover = false + if (!this.focused && this.shown) this.hide() + } + } @@ -2035,13 +2145,12 @@ $(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.2.2 + * bootstrap-affix.js v2.3.0 * http://twitter.github.com/bootstrap/javascript.html#affix * ========================================================== * Copyright 2012 Twitter, Inc. diff --git a/nikola/data/themes/default/bundles b/nikola/data/themes/default/bundles index 8fe858b..10f44e7 100644 --- a/nikola/data/themes/default/bundles +++ b/nikola/data/themes/default/bundles @@ -1,2 +1,4 @@ -assets/css/all.css=bootstrap.css,bootstrap-responsive.css,rst.css,code.css,colorbox.css,slides.css,theme.css,custom.css -assets/js/all.js=bootstrap.min.js,jquery-1.7.2.min.js,jquery.colorbox-min.js,slides.min.jquery.js +assets/css/all-nocdn.css=bootstrap.css,bootstrap-responsive.css,rst.css,code.css,colorbox.css,slides.css,theme.css,custom.css +assets/css/all.css=rst.css,code.css,colorbox.css,slides.css,theme.css,custom.css +assets/js/all-nocdn.js=bootstrap.min.js,jquery-1.7.2.min.js,jquery.colorbox-min.js,slides.min.jquery.js +assets/js/all.js=jquery.colorbox-min.js,slides.min.jquery.js diff --git a/nikola/data/themes/default/messages/messages_pt-br.py b/nikola/data/themes/default/messages/messages_pt-br.py new file mode 100644 index 0000000..183c577 --- /dev/null +++ b/nikola/data/themes/default/messages/messages_pt-br.py @@ -0,0 +1,22 @@ +# -*- encoding:utf-8 -*- +from __future__ import unicode_literals + +MESSAGES = { + "LANGUAGE": "Português", + "Posts for year %s": "Posts do ano %s", + "Archive": "Arquivo", + "Posts about %s": "Posts sobre %s", + "Tags": "Tags", + "Also available in": "Também disponível em", + "More posts about": "Mais posts sobre", + "Posted": "Publicado", + "Original site": "Site original", + "Read in English": "Ler em português", + "Newer posts": "Posts mais recentes", + "Older posts": "Posts mais antigos", + "Previous post": "Post anterior", + "Next post": "Próximo post", + "old posts page %d": "Posts antigos página %d", + "Read more": "Leia mais", + "Source": "Código", +} diff --git a/nikola/data/themes/default/templates/base.tmpl b/nikola/data/themes/default/templates/base.tmpl index 9c134b7..7af8497 100644 --- a/nikola/data/themes/default/templates/base.tmpl +++ b/nikola/data/themes/default/templates/base.tmpl @@ -49,5 +49,6 @@ <!--End of sidebar content--> </div> ${analytics} + ${late_load_js()} <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/default/templates/base_helper.tmpl b/nikola/data/themes/default/templates/base_helper.tmpl index 170dee1..51969c9 100644 --- a/nikola/data/themes/default/templates/base_helper.tmpl +++ b/nikola/data/themes/default/templates/base_helper.tmpl @@ -1,16 +1,24 @@ ## -*- coding: utf-8 -*- <%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> + %if use_cdn: + <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet"> + <link href="/assets/css/all.css" rel="stylesheet" type="text/css"> + %else: + <link href="/assets/css/all-nocdn.css" rel="stylesheet" type="text/css"> + %endif %else: - <link href="/assets/css/bootstrap.css" rel="stylesheet" type="text/css"> + %if use_cdn: + <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet"> + %else: + <link href="/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css"> + <link href="/assets/css/bootstrap-responsive.min.css" rel="stylesheet" type="text/css"> + %endif <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"/> @@ -19,11 +27,6 @@ %if has_custom_css: <link href="/assets/css/custom.css" rel="stylesheet" type="text/css"> %endif - <link href="/assets/css/bootstrap-responsive.css" rel="stylesheet" type="text/css"> - <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> - <script src="/assets/js/bootstrap.min.js" type="text/javascript"></script> %endif <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements --> <!--[if lt IE 9]> @@ -43,6 +46,27 @@ %endif </%def> +<%def name="late_load_js()"> + %if use_bundles: + %if use_cdn: + <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script> + <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/js/bootstrap.min.js"></script> + <script src="/assets/js/all.js" type="text/javascript"></script> + %else: + <script src="/assets/js/all-nocdn.js" type="text/javascript"></script> + %endif + %else: + %if use_cdn: + <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script> + <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/js/bootstrap.min.js"></script> + %else: + <script src="/assets/js/jquery-1.7.2.min.js" type="text/javascript"></script> + <script src="/assets/js/bootstrap.min.js" type="text/javascript"></script> + %endif + <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 +</%def> <%def name="html_social()"> %if add_this_buttons: diff --git a/nikola/data/themes/jinja-default/templates/base.tmpl b/nikola/data/themes/jinja-default/templates/base.tmpl index 0f394d3..32e5d48 100644 --- a/nikola/data/themes/jinja-default/templates/base.tmpl +++ b/nikola/data/themes/jinja-default/templates/base.tmpl @@ -2,26 +2,32 @@ <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> + {% if use_cdn %} + <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet"> + <link href="/assets/css/all.css" rel="stylesheet" type="text/css"> + {% else %} + <link href="/assets/css/all-nocdn.css" rel="stylesheet" type="text/css"> + {% endif %} {% else %} - <link href="/assets/css/bootstrap.css" rel="stylesheet" type="text/css"> - <link href="/assets/css/bootstrap-responsive.css" rel="stylesheet" type="text/css"> + {% if use_cdn %} + <link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet"> + {% else %} + <link href="/assets/css/bootstrap.min.css" rel="stylesheet" type="text/css"> + <link href="/assets/css/bootstrap-responsive.min.css" rel="stylesheet" type="text/css"> + {% endif %} <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"> + <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]> @@ -97,5 +103,25 @@ <!-- End of social buttons --> {% endif %} {{analytics}} + <!-- late load javascript --> + {% if use_bundles %} + {% if use_cdn %} + <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script> + <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/js/bootstrap.min.js"></script> + <script src="/assets/js/all.js" type="text/javascript"></script> + {% else %} + <script src="/assets/js/all-nocdn.js" type="text/javascript"></script> + {% endif %} + {% else %} + {% if use_cdn %} + <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script> + <script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/js/bootstrap.min.js"></script> + {% else %} + <script src="/assets/js/jquery-1.7.2.min.js" type="text/javascript"></script> + <script src="/assets/js/bootstrap.min.js" type="text/javascript"></script> + {% endif %} + <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 %} <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/assets/css/colorbox.css b/nikola/data/themes/monospace/assets/css/colorbox.css deleted file mode 100644 index f67c346..0000000 --- a/nikola/data/themes/monospace/assets/css/colorbox.css +++ /dev/null @@ -1,85 +0,0 @@ -/*
- 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/templates/base.tmpl b/nikola/data/themes/monospace/templates/base.tmpl index 7758ded..9eecbd4 100644 --- a/nikola/data/themes/monospace/templates/base.tmpl +++ b/nikola/data/themes/monospace/templates/base.tmpl @@ -40,5 +40,4 @@ </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 index 170dee1..aba8dff 100644 --- a/nikola/data/themes/monospace/templates/base_helper.tmpl +++ b/nikola/data/themes/monospace/templates/base_helper.tmpl @@ -1,7 +1,6 @@ ## -*- coding: utf-8 -*- <%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> diff --git a/nikola/data/themes/orphan/assets/css/colorbox.css b/nikola/data/themes/orphan/assets/css/colorbox.css deleted file mode 120000 index 2c48dd8..0000000 --- a/nikola/data/themes/orphan/assets/css/colorbox.css +++ /dev/null @@ -1 +0,0 @@ -../../../default/assets/css/colorbox.css
\ No newline at end of file diff --git a/nikola/data/themes/orphan/templates/base.tmpl b/nikola/data/themes/orphan/templates/base.tmpl index f280d08..39e2b9d 100644 --- a/nikola/data/themes/orphan/templates/base.tmpl +++ b/nikola/data/themes/orphan/templates/base.tmpl @@ -32,5 +32,4 @@ <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 index 170dee1..aba8dff 100644 --- a/nikola/data/themes/orphan/templates/base_helper.tmpl +++ b/nikola/data/themes/orphan/templates/base_helper.tmpl @@ -1,7 +1,6 @@ ## -*- coding: utf-8 -*- <%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> diff --git a/nikola/data/themes/site/assets/css/theme.css b/nikola/data/themes/site/assets/css/theme.css index 32c9f24..0183c69 100644 --- a/nikola/data/themes/site/assets/css/theme.css +++ b/nikola/data/themes/site/assets/css/theme.css @@ -23,9 +23,37 @@ img { } .postbox { - border-bottom: 2px solid darkgrey; + border-bottom: 2px solid darkgrey; margin-bottom: 12px; } .footerbox {padding: 15px; text-align: center; margin-bottom: 15px;} +td.label { + /* Issue #290 */ + background-color: inherit; +} + +.footnote-reference { + /* Issue 290 */ + vertical-align: super; + font-size: xx-small; +} + +.caption { + /* Issue 292 */ + text-align: center; +} + +div.figure > a > img { + /* Issue 292 */ + display: block; + margin-left: auto; + margin-right: auto; +} + +div.admonition, div.attention, div.caution, div.danger, div.error, div.hint, div.important, div.note, div.tip, div.warning { + /* Issue 277 */ + border: 1px solid #aaa; + border-radius: 5px; +} diff --git a/nikola/data/themes/site/templates/base.tmpl b/nikola/data/themes/site/templates/base.tmpl index 2094d9a..416d04b 100644 --- a/nikola/data/themes/site/templates/base.tmpl +++ b/nikola/data/themes/site/templates/base.tmpl @@ -60,5 +60,6 @@ </div> ${html_social()} ${analytics} +${late_load_js()} <script type="text/javascript">jQuery("a.image-reference").colorbox({rel:"gal",maxWidth:"80%",maxHeight:"80%",scalePhotos:true});</script> </body> diff --git a/nikola/nikola.py b/nikola/nikola.py index e10c84e..88de88c 100644 --- a/nikola/nikola.py +++ b/nikola/nikola.py @@ -130,8 +130,9 @@ class Nikola(object): 'TAG_PAGES_ARE_INDEXES': False, 'THEME': 'site', 'THUMBNAIL_SIZE': 180, - 'USE_FILENAME_AS_TITLE': True, 'USE_BUNDLES': True, + 'USE_CDN': False, + 'USE_FILENAME_AS_TITLE': True, } self.config.update(config) @@ -184,16 +185,17 @@ class Nikola(object): self.GLOBAL_CONTEXT['rel_link'] = self.rel_link self.GLOBAL_CONTEXT['abs_link'] = self.abs_link self.GLOBAL_CONTEXT['exists'] = self.file_exists + self.GLOBAL_CONTEXT['SLUG_TAG_PATH'] = self.config[ + 'SLUG_TAG_PATH'] self.GLOBAL_CONTEXT['add_this_buttons'] = self.config[ 'ADD_THIS_BUTTONS'] self.GLOBAL_CONTEXT['index_display_post_count'] = self.config[ 'INDEX_DISPLAY_POST_COUNT'] self.GLOBAL_CONTEXT['use_bundles'] = self.config['USE_BUNDLES'] + self.GLOBAL_CONTEXT['use_cdn'] = self.config.get("USE_CDN") self.GLOBAL_CONTEXT['favicons'] = self.config['FAVICONS'] - if 'date_format' not in self.GLOBAL_CONTEXT: - self.GLOBAL_CONTEXT['date_format'] = '%Y-%m-%d %H:%M' - + self.GLOBAL_CONTEXT['date_format'] = self.config.get('DATE_FORMAT', '%Y-%m-%d %H:%M') self.GLOBAL_CONTEXT['blog_author'] = self.config.get('BLOG_AUTHOR') self.GLOBAL_CONTEXT['blog_title'] = self.config.get('BLOG_TITLE') self.GLOBAL_CONTEXT['blog_url'] = self.config.get('BLOG_URL') diff --git a/nikola/plugins/__init__.py b/nikola/plugins/__init__.py index b1de7f1..2d9b1b2 100644 --- a/nikola/plugins/__init__.py +++ b/nikola/plugins/__init__.py @@ -1,3 +1,4 @@ from __future__ import absolute_import from . import command_import_wordpress # NOQA +from . import command_build # NOQA diff --git a/nikola/plugins/command_build.py b/nikola/plugins/command_build.py index 29d4c9d..8a1de5f 100644 --- a/nikola/plugins/command_build.py +++ b/nikola/plugins/command_build.py @@ -38,8 +38,10 @@ class CommandBuild(Command): """Build the site using doit.""" # FIXME: this is crap, do it right - with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as dodo: - dodo.write(b''' + with tempfile.NamedTemporaryFile(suffix='.py', delete=False) as self.dodo: + self.dodo.write(b''' +import sys +sys.path.insert(0, '.') from doit.reporter import ExecutedOnlyReporter DOIT_CONFIG = { 'reporter': ExecutedOnlyReporter, @@ -53,12 +55,13 @@ SITE = Nikola(**conf.__dict__) def task_render_site(): return SITE.gen_tasks() ''') - dodo.flush() + self.dodo.flush() 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, + os.system('doit %s -f %s -d . %s' % (cmd, self.dodo.name, ''.join(args))) + os.unlink(self.dodo.name) diff --git a/nikola/plugins/command_new_post.py b/nikola/plugins/command_new_post.py index a5715de..9b6397b 100644 --- a/nikola/plugins/command_new_post.py +++ b/nikola/plugins/command_new_post.py @@ -110,9 +110,11 @@ class CommandNewPost(Command): print("-----------------\n") if title is None: print("Enter title: ", end='') + # WHY, PYTHON3???? WHY? + sys.stdout.flush() title = sys.stdin.readline() else: - print("Title: ", title) + print("Title:", title) if isinstance(title, bytes): title = title.decode(sys.stdin.encoding) title = title.strip() diff --git a/nikola/plugins/task_create_bundles.py b/nikola/plugins/task_create_bundles.py index d024636..95f10c2 100644 --- a/nikola/plugins/task_create_bundles.py +++ b/nikola/plugins/task_create_bundles.py @@ -51,6 +51,8 @@ class BuildBundles(LateTask): 'output_folder': self.site.config['OUTPUT_FOLDER'], 'cache_folder': self.site.config['CACHE_FOLDER'], 'theme_bundles': get_theme_bundles(self.site.THEMES), + 'themes': self.site.THEMES, + 'files_folders': self.site.config['FILES_FOLDERS'], } def build_bundle(output, inputs): @@ -74,8 +76,11 @@ class BuildBundles(LateTask): for name, files in kw['theme_bundles'].items(): output_path = os.path.join(kw['output_folder'], name) dname = os.path.dirname(name) - file_dep = [os.path.join('output', dname, fname) for fname in - files] + file_dep = [get_asset_path( + os.path.join(dname, fname), kw['themes'], kw['files_folders']) + for fname in files + ] + file_dep = filter(None, file_dep) # removes missing files task = { 'file_dep': file_dep, 'basename': str(self.name), @@ -95,6 +100,46 @@ class BuildBundles(LateTask): } +def get_asset_path(path, themes, files_folders={'files': ''}): + """Checks which theme provides the path with the given asset, + and returns the "real" path to the asset, relative to the + current directory. + + If the asset is not provided by a theme, then it will be checked for + in the FILES_FOLDERS + + >>> get_asset_path('assets/css/rst.css', ['site','default']) + 'nikola/data/themes/default/assets/css/rst.css' + + >>> get_asset_path('assets/css/theme.css', ['site','default']) + 'nikola/data/themes/site/assets/css/theme.css' + + >>> get_asset_path('nikola.py',['site','default'],{'nikola':''}) + 'nikola/nikola.py' + + >>> get_asset_path('nikola/nikola.py',['site','default'],{'nikola':'nikola'}) + 'nikola/nikola.py' + + """ + for theme_name in themes: + candidate = os.path.join( + utils.get_theme_path(theme_name), + path + ) + if os.path.isfile(candidate): + return os.path.relpath(candidate, os.getcwd()) + for src, rel_dst in files_folders.items(): + candidate = os.path.join( + src, + os.path.relpath(path, rel_dst) + ) + if os.path.isfile(candidate): + return os.path.relpath(candidate, os.getcwd()) + + # whatever! + return None + + def get_theme_bundles(themes): """Given a theme chain, return the bundle definitions.""" bundles = {} diff --git a/nikola/plugins/task_render_galleries.py b/nikola/plugins/task_render_galleries.py index 7fe1501..e69a457 100644 --- a/nikola/plugins/task_render_galleries.py +++ b/nikola/plugins/task_render_galleries.py @@ -91,6 +91,7 @@ class Galleries(Task): output_gallery = os.path.dirname(os.path.join( kw["output_folder"], self.site.path("gallery", gallery_name, None))) + output_name = os.path.join(output_gallery, "index.html") if not os.path.isdir(output_gallery): yield { 'basename': str('render_galleries'), @@ -126,15 +127,10 @@ class Galleries(Task): pass # List of sub-galleries - folder_list = [x.split(os.sep)[-2] + os.sep for x in + folder_list = [x.split(os.sep)[-2] for x in glob.glob(os.path.join(gallery_path, '*') + os.sep)] - crumbs = gallery_path.split(os.sep)[:-1] - crumbs.append(os.path.basename(gallery_name)) - # TODO: write this in human - paths = ['/'.join(['..'] * (len(crumbs) - 1 - i)) for i in - range(len(crumbs[:-1]))] + ['#'] - crumbs = list(zip(paths, crumbs)) + crumbs = utils.get_crumbs(gallery_path) image_list = [x for x in image_list if "thumbnail" not in x] # Sort by date @@ -213,7 +209,6 @@ class Galleries(Task): 'uptodate': [utils.config_changed(kw)], } - output_name = os.path.join(output_gallery, "index.html") context = {} context["lang"] = kw["default_lang"] context["title"] = os.path.basename(gallery_path) diff --git a/nikola/plugins/task_render_listings.py b/nikola/plugins/task_render_listings.py index 6d1d853..a899f10 100644 --- a/nikola/plugins/task_render_listings.py +++ b/nikola/plugins/task_render_listings.py @@ -22,6 +22,8 @@ # 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 os from pygments import highlight @@ -60,14 +62,16 @@ class Listings(Task): lineanchors=utils.slugify(f), anchorlinenos=True)) title = os.path.basename(in_name) - crumbs = out_name.split(os.sep)[1:-1] + [title] + print("CRUMBSINOUT", in_name, out_name) + #crumbs = out_name.split(os.sep)[1:-1] + [title] # TODO: write this in human - paths = ['/'.join(['..'] * (len(crumbs) - 2 - i)) for i in - range(len(crumbs[:-2]))] + ['.', '#'] + #paths = ['/'.join(['..'] * (len(crumbs) - 2 - i)) for i in + #range(len(crumbs[:-2]))] + ['.', '#'] + crumbs = utils.get_crumbs(os.path.relpath(out_name, kw['output_folder']), is_file=True) context = { 'code': code, 'title': title, - 'crumbs': zip(paths, crumbs), + 'crumbs': crumbs, 'lang': kw['default_lang'], 'description': title, } diff --git a/nikola/plugins/task_render_sources.py b/nikola/plugins/task_render_sources.py index bce8d69..529e68e 100644 --- a/nikola/plugins/task_render_sources.py +++ b/nikola/plugins/task_render_sources.py @@ -58,7 +58,6 @@ class Sources(Task): lang, post.source_ext())) source = post.source_path if source.endswith('.html'): - print("Avoiting to render source of .html page") continue if lang != kw["default_lang"]: source_lang = source + '.' + lang diff --git a/nikola/utils.py b/nikola/utils.py index f682c33..eeb0c45 100644 --- a/nikola/utils.py +++ b/nikola/utils.py @@ -60,7 +60,7 @@ import PyRSS2Gen as rss __all__ = ['get_theme_path', 'get_theme_chain', 'load_messages', 'copy_tree', 'generic_rss_renderer', 'copy_file', 'slugify', 'unslugify', 'get_meta', 'to_datetime', - 'apply_filters', 'config_changed'] + 'apply_filters', 'config_changed', 'get_crumbs'] class CustomEncoder(json.JSONEncoder): @@ -255,6 +255,8 @@ def load_messages(themes, translations): oldpath = sys.path[:] for theme_name in themes[::-1]: msg_folder = os.path.join(get_theme_path(theme_name), 'messages') + default_folder = os.path.join(get_theme_path('default'), 'messages') + sys.path.insert(0, default_folder) sys.path.insert(0, msg_folder) english = __import__('messages_en') for lang in list(translations.keys()): @@ -488,3 +490,31 @@ def apply_filters(task, filters): task['actions'].append((unlessLink, (action, target))) return task + + +def get_crumbs(path, is_file=False): + """Create proper links for a crumb bar. + + >>> get_crumbs('galleries') + [['#', 'galleries']] + + >>> get_crumbs(os.path.join('galleries','demo')) + [['..', 'galleries'], ['#', 'demo']] + + >>> get_crumbs(os.path.join('listings','foo','bar'), is_file=True) + [['..', 'listings'], ['.', 'foo'], ['#', 'bar']] + """ + + crumbs = path.split(os.sep) + _crumbs = [] + if is_file: + for i, crumb in enumerate(crumbs[-3::-1]): # Up to parent folder only + _path = '/'.join(['..'] * (i + 1)) + _crumbs.append([_path, crumb]) + _crumbs.insert(0, ['.', crumbs[-2]]) # file's folder + _crumbs.insert(0, ['#', crumbs[-1]]) # file itself + else: + for i, crumb in enumerate(crumbs[::-1]): + _path = '/'.join(['..'] * i) or '#' + _crumbs.append([_path, crumb]) + return list(reversed(_crumbs)) diff --git a/requirements-3.txt b/requirements-3.txt index 79dd75a..b5f9d95 100644 --- a/requirements-3.txt +++ b/requirements-3.txt @@ -12,3 +12,4 @@ markdown Jinja2 PyRSS2Gen bbcode +flake8 diff --git a/requirements.txt b/requirements.txt index c556843..923c2ed 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,3 +13,4 @@ markdown Jinja2 PyRSS2Gen bbcode +flake8 @@ -70,27 +70,30 @@ def copy_messages(): def install_manpages(root, prefix): - man_pages = [ - ('docs/man/nikola.1', 'share/man/man1/nikola.1'), - ] - join = os.path.join - normpath = os.path.normpath - if root is not None: - prefix = os.path.realpath(root) + os.path.sep + prefix - for src, dst in man_pages: - path_dst = join(normpath(prefix), normpath(dst)) - try: - os.makedirs(os.path.dirname(path_dst)) - except OSError: - pass - rst2man_cmd = ['rst2man.py', 'rst2man'] - for rst2man in rst2man_cmd: + try: + man_pages = [ + ('docs/man/nikola.1', 'share/man/man1/nikola.1'), + ] + join = os.path.join + normpath = os.path.normpath + if root is not None: + prefix = os.path.realpath(root) + os.path.sep + prefix + for src, dst in man_pages: + path_dst = join(normpath(prefix), normpath(dst)) try: - subprocess.call([rst2man, src, path_dst]) + os.makedirs(os.path.dirname(path_dst)) except OSError: - continue - else: - break + pass + rst2man_cmd = ['rst2man.py', 'rst2man'] + for rst2man in rst2man_cmd: + try: + subprocess.call([rst2man, src, path_dst]) + except OSError: + continue + else: + break + except Exception as e: + print("Not installing the man pages:", e) class nikola_install(install): @@ -179,7 +182,7 @@ def find_package_data( return out setup(name='Nikola', - version='5.2', + version='5.3', description='Static blog/website generator', author='Roberto Alsina and others', author_email='ralsina@netmanagers.com.ar', diff --git a/tests/context.py b/tests/context.py index f292b79..28eb872 100644 --- a/tests/context.py +++ b/tests/context.py @@ -6,4 +6,4 @@ import os import sys sys.path.insert(0, os.path.abspath('..')) -import nikola +import nikola # NOQA diff --git a/tests/test_command_init.py b/tests/test_command_init.py index 3176c1f..32ce345 100644 --- a/tests/test_command_init.py +++ b/tests/test_command_init.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals from context import nikola -import os import unittest import mock diff --git a/tests/test_integration.py b/tests/test_integration.py new file mode 100644 index 0000000..947a832 --- /dev/null +++ b/tests/test_integration.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals, print_function + +from contextlib import contextmanager +import os +import shutil +import tempfile +import unittest + +from context import nikola + + +@contextmanager +def cd(path): + old_dir = os.getcwd() + os.chdir(path) + yield + os.chdir(old_dir) + + +class IntegrationTest(unittest.TestCase): + """Basic integration testcase.""" + def setUp(self): + """Setup a demo site.""" + self.tmpdir = tempfile.mkdtemp() + self.target_dir = os.path.join(self.tmpdir, "target") + self.build_command = nikola.plugins.command_build.CommandBuild() + self.init_command = nikola.plugins.command_init.CommandInit() + self.init_command.copy_sample_site(self.target_dir) + self.init_command.create_configuration(self.target_dir) + self.patch_site() + self.build() + + def patch_site(self): + """Make any modifications you need to the site.""" + pass + + def build(self): + """Build the site.""" + with cd(self.target_dir): + self.build_command.run() + + def tearDown(self): + """Reove the demo site.""" + shutil.rmtree(self.tmpdir) + + +class EmptytBuild(IntegrationTest): + """Basic integration testcase.""" + def setUp(self): + """Setup a demo site.""" + self.tmpdir = tempfile.mkdtemp() + self.target_dir = os.path.join(self.tmpdir, "target") + self.build_command = nikola.plugins.command_build.CommandBuild() + self.init_command = nikola.plugins.command_init.CommandInit() + self.init_command.create_empty_site(self.target_dir) + self.init_command.create_configuration(self.target_dir) + self.patch_site() + self.build() + + def test_deleted_dodo(self): + """Test that a default build of --demo works.""" + # Ensure the temprary dodo file is deleted (Issue #302) + self.assertFalse(os.path.isfile(self.build_command.dodo.name)) + + +class DefaultBuild(IntegrationTest): + """Test that a default build of --demo works.""" + + def test_deleted_dodo(self): + """Test that a default build of --demo works.""" + # Ensure the temprary dodo file is deleted (Issue #302) + self.assertFalse(os.path.isfile(self.build_command.dodo.name)) diff --git a/tests/test_plugin_importing.py b/tests/test_plugin_importing.py index 7e1e013..1a610bf 100644 --- a/tests/test_plugin_importing.py +++ b/tests/test_plugin_importing.py @@ -1,16 +1,16 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals, absolute_import -from context import nikola +from context import nikola # NOQA import unittest class ImportPluginsTest(unittest.TestCase): def test_importing_command_import_wordpress(self): - import nikola.plugins.command_import_wordpress + import nikola.plugins.command_import_wordpress # NOQA def test_importing_task_sitemap(self): - import nikola.plugins.task_sitemap.sitemap_gen + import nikola.plugins.task_sitemap.sitemap_gen # NOQA def test_importing_compile_rest(self): - import nikola.plugins.compile_rest
\ No newline at end of file + import nikola.plugins.compile_rest # NOQA diff --git a/tests/test_utils.py b/tests/test_utils.py index 8ec016f..2cb36a8 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -2,7 +2,6 @@ from __future__ import unicode_literals from context import nikola -import os import unittest import mock |
