summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatarAgustin Henze <tin@sluc.org.ar>2013-02-27 09:13:31 -0300
committerLibravatarAgustin Henze <tin@sluc.org.ar>2013-02-27 09:13:31 -0300
commitcb2680529d9447d94546c8c0960f0c4e299af18c (patch)
tree335ce0e66c214a120aa51ac78e25afe6585c1a13
parent6e0996d54cad4586645fdc59164708e4b4b9dcec (diff)
parent878ba1152ebc64a4a2609d23c9e400a6111db642 (diff)
Merge tag 'upstream/5.3'
Upstream version 5.3
-rw-r--r--.travis.yml2
-rw-r--r--CHANGES.txt29
-rw-r--r--docs/manual.txt23
-rw-r--r--extra_plugins/README.txt62
-rw-r--r--extra_plugins/command_planetoid.plugin9
-rw-r--r--extra_plugins/command_planetoid/__init__.py248
-rw-r--r--extra_plugins/command_planetoid/index.tmpl26
-rw-r--r--extra_plugins/command_planetoid/post.tmpl10
-rw-r--r--extra_plugins/task_localsearch/README.txt12
-rw-r--r--extra_plugins/task_mustache/__init__.py3
-rw-r--r--nikola/conf.py.in7
-rw-r--r--nikola/console.py13
-rw-r--r--nikola/data/themes/default/assets/css/bootstrap-responsive.css31
-rw-r--r--nikola/data/themes/default/assets/css/bootstrap.css357
-rw-r--r--nikola/data/themes/default/assets/css/theme.css31
-rw-r--r--nikola/data/themes/default/assets/js/bootstrap.js269
-rw-r--r--nikola/data/themes/default/bundles6
-rw-r--r--nikola/data/themes/default/messages/messages_pt-br.py22
-rw-r--r--nikola/data/themes/default/templates/base.tmpl1
-rw-r--r--nikola/data/themes/default/templates/base_helper.tmpl42
-rw-r--r--nikola/data/themes/jinja-default/templates/base.tmpl42
-rw-r--r--nikola/data/themes/monospace/assets/css/colorbox.css85
-rw-r--r--nikola/data/themes/monospace/templates/base.tmpl1
-rw-r--r--nikola/data/themes/monospace/templates/base_helper.tmpl1
l---------nikola/data/themes/orphan/assets/css/colorbox.css1
-rw-r--r--nikola/data/themes/orphan/templates/base.tmpl1
-rw-r--r--nikola/data/themes/orphan/templates/base_helper.tmpl1
-rw-r--r--nikola/data/themes/site/assets/css/theme.css30
-rw-r--r--nikola/data/themes/site/templates/base.tmpl1
-rw-r--r--nikola/nikola.py10
-rw-r--r--nikola/plugins/__init__.py1
-rw-r--r--nikola/plugins/command_build.py11
-rw-r--r--nikola/plugins/command_new_post.py4
-rw-r--r--nikola/plugins/task_create_bundles.py49
-rw-r--r--nikola/plugins/task_render_galleries.py11
-rw-r--r--nikola/plugins/task_render_listings.py12
-rw-r--r--nikola/plugins/task_render_sources.py1
-rw-r--r--nikola/utils.py32
-rw-r--r--requirements-3.txt1
-rw-r--r--requirements.txt1
-rw-r--r--setup.py43
-rw-r--r--tests/context.py2
-rw-r--r--tests/test_command_init.py1
-rw-r--r--tests/test_integration.py73
-rw-r--r--tests/test_plugin_importing.py8
-rw-r--r--tests/test_utils.py1
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>&nbsp;&nbsp;
+ Publicado: ${post.date}
+ </small></h1>
+ ${post.text(lang)}
+ </div>
+ % endfor
+ <div>
+<ul class="pager">
+ %if prevlink:
+ <li class="previous">
+ <a href="${prevlink}">&larr; Posts posteriores</a>
+ </li>
+ %endif
+ %if nextlink:
+ <li class="next">
+ <a href="${nextlink}">Posts anteriores &rarr;</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
diff --git a/setup.py b/setup.py
index c86b45c..2ff115f 100644
--- a/setup.py
+++ b/setup.py
@@ -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