From 0c4dfdec5b55b6064dccc38bbfb0a7c0699c895a Mon Sep 17 00:00:00 2001 From: Agustin Henze Date: Thu, 30 May 2013 17:41:06 -0300 Subject: Imported Upstream version 5.4.4 --- nikola/conf.py.in | 43 +- nikola/data/themes/default/assets/css/code.css | 62 - nikola/data/themes/default/assets/css/slides.css | 11 - nikola/data/themes/default/assets/css/theme.css | 11 + .../data/themes/default/assets/js/slides.jquery.js | 555 ----- nikola/data/themes/default/bundles | 8 +- nikola/data/themes/default/messages/messages_ca.py | 23 +- nikola/data/themes/default/messages/messages_de.py | 25 +- nikola/data/themes/default/messages/messages_el.py | 23 + nikola/data/themes/default/messages/messages_en.py | 21 +- nikola/data/themes/default/messages/messages_es.py | 23 +- nikola/data/themes/default/messages/messages_fr.py | 24 +- nikola/data/themes/default/messages/messages_it.py | 24 +- nikola/data/themes/default/messages/messages_ja.py | 23 + nikola/data/themes/default/messages/messages_pl.py | 25 +- .../data/themes/default/messages/messages_pt-br.py | 22 - .../data/themes/default/messages/messages_pt_br.py | 23 + nikola/data/themes/default/messages/messages_ru.py | 23 +- .../data/themes/default/messages/messages_zh-cn.py | 22 - .../data/themes/default/messages/messages_zh_cn.py | 23 + nikola/data/themes/default/templates/base.tmpl | 6 +- .../data/themes/default/templates/base_helper.tmpl | 14 +- .../themes/default/templates/disqus_helper.tmpl | 7 +- nikola/data/themes/default/templates/index.tmpl | 10 +- .../themes/default/templates/index_helper.tmpl | 4 +- .../data/themes/default/templates/list_post.tmpl | 2 +- nikola/data/themes/default/templates/post.tmpl | 12 +- .../data/themes/default/templates/post_helper.tmpl | 26 +- nikola/data/themes/default/templates/story.tmpl | 10 +- nikola/data/themes/default/templates/tag.tmpl | 27 +- nikola/data/themes/default/templates/tags.tmpl | 18 +- .../data/themes/jinja-default/templates/base.tmpl | 10 +- .../data/themes/jinja-default/templates/index.tmpl | 12 +- .../themes/jinja-default/templates/list_post.tmpl | 2 +- .../data/themes/jinja-default/templates/post.tmpl | 27 +- .../data/themes/jinja-default/templates/story.tmpl | 21 +- .../data/themes/jinja-default/templates/tag.tmpl | 2 +- .../data/themes/jinja-default/templates/tags.tmpl | 4 +- nikola/data/themes/monospace/assets/css/code.css | 62 - nikola/data/themes/monospace/bundles | 1 + nikola/data/themes/monospace/templates/base.tmpl | 6 +- .../themes/monospace/templates/base_helper.tmpl | 36 +- .../themes/monospace/templates/disqus_helper.tmpl | 7 +- nikola/data/themes/monospace/templates/index.tmpl | 12 +- .../themes/monospace/templates/index_helper.tmpl | 4 +- .../data/themes/monospace/templates/list_post.tmpl | 2 +- nikola/data/themes/monospace/templates/post.tmpl | 15 +- .../themes/monospace/templates/post_helper.tmpl | 42 +- nikola/data/themes/monospace/templates/story.tmpl | 10 +- nikola/data/themes/monospace/templates/tag.tmpl | 2 +- nikola/data/themes/orphan/assets/css/code.css | 1 - nikola/data/themes/orphan/templates/base.tmpl | 4 +- .../data/themes/orphan/templates/base_helper.tmpl | 36 +- .../themes/orphan/templates/disqus_helper.tmpl | 7 +- nikola/data/themes/orphan/templates/index.tmpl | 10 +- .../data/themes/orphan/templates/index_helper.tmpl | 4 +- nikola/data/themes/orphan/templates/list_post.tmpl | 2 +- nikola/data/themes/orphan/templates/post.tmpl | 12 +- .../data/themes/orphan/templates/post_helper.tmpl | 44 +- nikola/data/themes/orphan/templates/story.tmpl | 10 +- nikola/data/themes/orphan/templates/tag.tmpl | 2 +- nikola/data/themes/site-planetoid/README | 1 + nikola/data/themes/site-planetoid/engine | 1 + nikola/data/themes/site-planetoid/parent | 1 + .../themes/site-planetoid/templates/index.tmpl | 16 + .../data/themes/site-planetoid/templates/post.tmpl | 9 + .../themes/site-planetoid/templates/story.tmpl | 25 + nikola/data/themes/site/assets/css/theme.css | 14 + nikola/data/themes/site/templates/base.tmpl | 12 +- nikola/main.py | 7 +- nikola/nikola.py | 157 +- nikola/plugin_categories.py | 11 +- nikola/plugins/command_check.py | 21 +- nikola/plugins/command_console.py | 76 +- nikola/plugins/command_deploy.py | 26 +- nikola/plugins/command_import_blogger.py | 17 +- nikola/plugins/command_import_wordpress.py | 32 +- nikola/plugins/command_install_theme.py | 4 + nikola/plugins/command_new_post.py | 36 +- nikola/plugins/command_planetoid.plugin | 9 + nikola/plugins/command_planetoid/__init__.py | 287 +++ nikola/plugins/compile_bbcode.py | 16 +- nikola/plugins/compile_html.py | 14 +- nikola/plugins/compile_ipynb.plugin | 10 + nikola/plugins/compile_ipynb/README.txt | 35 + nikola/plugins/compile_ipynb/__init__.py | 100 + nikola/plugins/compile_markdown/__init__.py | 51 +- nikola/plugins/compile_markdown/mdx_gist.py | 189 ++ nikola/plugins/compile_markdown/mdx_nikola.py | 56 + nikola/plugins/compile_markdown/mdx_podcast.py | 87 + nikola/plugins/compile_misaka.plugin | 10 + nikola/plugins/compile_misaka/__init__.py | 82 + nikola/plugins/compile_rest/__init__.py | 81 +- nikola/plugins/compile_rest/dummy.py | 44 + nikola/plugins/compile_rest/gist_directive.py | 2 +- nikola/plugins/compile_rest/listing.py | 121 ++ .../compile_rest/pygments_code_block_directive.py | 424 ---- nikola/plugins/compile_rest/slides.py | 79 +- nikola/plugins/compile_rest/soundcloud.py | 62 +- nikola/plugins/compile_rest/vimeo.py | 114 +- nikola/plugins/compile_rest/youtube.py | 57 +- nikola/plugins/compile_textile.py | 14 +- nikola/plugins/compile_txt2tags.py | 14 +- nikola/plugins/compile_wiki.py | 12 +- nikola/plugins/task_archive.py | 66 +- nikola/plugins/task_copy_assets.py | 25 + nikola/plugins/task_create_bundles.py | 46 +- nikola/plugins/task_indexes.py | 35 +- nikola/plugins/task_localsearch.plugin | 10 + nikola/plugins/task_localsearch/MIT-LICENSE.txt | 20 + nikola/plugins/task_localsearch/__init__.py | 102 + .../files/assets/css/img/expand.png | Bin 0 -> 424 bytes .../task_localsearch/files/assets/css/img/link.png | Bin 0 -> 463 bytes .../files/assets/css/img/loader.gif | Bin 0 -> 4178 bytes .../files/assets/css/img/search.gif | Bin 0 -> 208 bytes .../files/assets/css/tipuesearch.css | 232 +++ .../files/assets/js/tipuesearch.js | 426 ++++ .../files/assets/js/tipuesearch_set.js | 28 + .../task_localsearch/files/tipue_search.html | 31 + nikola/plugins/task_mustache.plugin | 10 + nikola/plugins/task_mustache/__init__.py | 197 ++ .../plugins/task_mustache/mustache-template.html | 29 + nikola/plugins/task_mustache/mustache.html | 36 + nikola/plugins/task_redirect.py | 2 +- nikola/plugins/task_render_galleries.py | 29 +- nikola/plugins/task_render_listings.py | 12 +- nikola/plugins/task_render_pages.py | 5 + nikola/plugins/task_render_posts.py | 84 +- nikola/plugins/task_render_rss.py | 11 +- nikola/plugins/task_render_sources.py | 21 +- nikola/plugins/task_render_tags.py | 20 +- nikola/plugins/task_sitemap/__init__.py | 94 +- nikola/plugins/task_sitemap/sitemap_gen.py | 2137 -------------------- nikola/post.py | 312 ++- nikola/rc4.py | 76 + nikola/utils.py | 149 +- 136 files changed, 4089 insertions(+), 4151 deletions(-) delete mode 100644 nikola/data/themes/default/assets/css/code.css delete mode 100644 nikola/data/themes/default/assets/css/slides.css delete mode 100755 nikola/data/themes/default/assets/js/slides.jquery.js create mode 100644 nikola/data/themes/default/messages/messages_el.py create mode 100644 nikola/data/themes/default/messages/messages_ja.py delete mode 100644 nikola/data/themes/default/messages/messages_pt-br.py create mode 100644 nikola/data/themes/default/messages/messages_pt_br.py delete mode 100644 nikola/data/themes/default/messages/messages_zh-cn.py create mode 100644 nikola/data/themes/default/messages/messages_zh_cn.py delete mode 100644 nikola/data/themes/monospace/assets/css/code.css delete mode 120000 nikola/data/themes/orphan/assets/css/code.css create mode 100644 nikola/data/themes/site-planetoid/README create mode 100644 nikola/data/themes/site-planetoid/engine create mode 100644 nikola/data/themes/site-planetoid/parent create mode 100644 nikola/data/themes/site-planetoid/templates/index.tmpl create mode 100644 nikola/data/themes/site-planetoid/templates/post.tmpl create mode 100644 nikola/data/themes/site-planetoid/templates/story.tmpl create mode 100644 nikola/plugins/command_planetoid.plugin create mode 100644 nikola/plugins/command_planetoid/__init__.py create mode 100644 nikola/plugins/compile_ipynb.plugin create mode 100644 nikola/plugins/compile_ipynb/README.txt create mode 100644 nikola/plugins/compile_ipynb/__init__.py create mode 100644 nikola/plugins/compile_markdown/mdx_gist.py create mode 100644 nikola/plugins/compile_markdown/mdx_nikola.py create mode 100644 nikola/plugins/compile_markdown/mdx_podcast.py create mode 100644 nikola/plugins/compile_misaka.plugin create mode 100644 nikola/plugins/compile_misaka/__init__.py create mode 100644 nikola/plugins/compile_rest/dummy.py create mode 100644 nikola/plugins/compile_rest/listing.py delete mode 100644 nikola/plugins/compile_rest/pygments_code_block_directive.py create mode 100644 nikola/plugins/task_localsearch.plugin create mode 100644 nikola/plugins/task_localsearch/MIT-LICENSE.txt create mode 100644 nikola/plugins/task_localsearch/__init__.py create mode 100755 nikola/plugins/task_localsearch/files/assets/css/img/expand.png create mode 100755 nikola/plugins/task_localsearch/files/assets/css/img/link.png create mode 100644 nikola/plugins/task_localsearch/files/assets/css/img/loader.gif create mode 100644 nikola/plugins/task_localsearch/files/assets/css/img/search.gif create mode 100755 nikola/plugins/task_localsearch/files/assets/css/tipuesearch.css create mode 100644 nikola/plugins/task_localsearch/files/assets/js/tipuesearch.js create mode 100644 nikola/plugins/task_localsearch/files/assets/js/tipuesearch_set.js create mode 100755 nikola/plugins/task_localsearch/files/tipue_search.html create mode 100644 nikola/plugins/task_mustache.plugin create mode 100644 nikola/plugins/task_mustache/__init__.py create mode 100644 nikola/plugins/task_mustache/mustache-template.html create mode 100644 nikola/plugins/task_mustache/mustache.html delete mode 100644 nikola/plugins/task_sitemap/sitemap_gen.py create mode 100644 nikola/rc4.py (limited to 'nikola') diff --git a/nikola/conf.py.in b/nikola/conf.py.in index 7d75295..c2bf8ff 100644 --- a/nikola/conf.py.in +++ b/nikola/conf.py.in @@ -17,7 +17,7 @@ BLOG_TITLE = "${BLOG_TITLE}" SITE_URL = "${SITE_URL}" # This is the URL where nikola's output will be deployed. # If not set, defaults to SITE_URL -# BASE_URL = "${SITE_URL} +# BASE_URL = "${SITE_URL}" BLOG_EMAIL = "${BLOG_EMAIL}" BLOG_DESCRIPTION = "${BLOG_DESCRIPTION}" @@ -47,7 +47,7 @@ DEFAULT_LANG = "${DEFAULT_LANG}" # The format is {"translationcode" : "path/to/translation" } # the path will be used as a prefix for the generated pages location TRANSLATIONS = { - "${DEFAULT_LANG}": "", + DEFAULT_LANG: "", # Example for another language: # "es": "./es", } @@ -58,6 +58,7 @@ SIDEBAR_LINKS = { DEFAULT_LANG: ( ('/archive.html', 'Archives'), ('/categories/index.html', 'Tags'), + ('/rss.xml', 'RSS'), ), } @@ -109,6 +110,12 @@ post_compilers = ${POST_COMPILERS} # Set to False for two-file posts, with separate metadata. # ONE_FILE_POSTS = True +# If this is set to True, then posts that are not translated to a language +# LANG will not be visible at all in the pages in that language. +# If set to False, the DEFAULT_LANG version will be displayed for +# untranslated posts. +# HIDE_UNTRANSLATED_POSTS = False + # Paths for different autogenerated bits. These are combined with the # translation paths. @@ -124,11 +131,16 @@ post_compilers = ${POST_COMPILERS} # Final location is output / TRANSLATION[lang] / INDEX_PATH / index-*.html # INDEX_PATH = "" + +# Create per-month archives instead of per-year +# CREATE_MONTHLY_ARCHIVE = False # Final locations for the archives are: # output / TRANSLATION[lang] / ARCHIVE_PATH / ARCHIVE_FILENAME # output / TRANSLATION[lang] / ARCHIVE_PATH / YEAR / index.html +# output / TRANSLATION[lang] / ARCHIVE_PATH / YEAR / MONTH / index.html # ARCHIVE_PATH = "" # ARCHIVE_FILENAME = "archive.html" + # Final locations are: # output / TRANSLATION[lang] / RSS_PATH / rss.xml # RSS_PATH = "" @@ -208,11 +220,17 @@ post_compilers = ${POST_COMPILERS} # INDEXES_TITLE = "" # If this is empty, the default is BLOG_TITLE # INDEXES_PAGES = "" # If this is empty, the default is 'old posts page %d' translated -# Name of the theme to use. Themes are located in themes/theme_name +# Name of the theme to use. # THEME = 'site' +# Color scheme to be used for code blocks. If your theme provide "assets/css/code.css" this +# is ignored. +# Can be any of autumn borland bw colorful default emacs friendly fruity manni monokai +# murphy native pastie perldoc rrt tango trac vim vs +# CODE_COLOR_SCHEME = default + # If you use 'site-reveal' theme you can select several subthemes -# THEME_REVEAL_CONGIF_SUBTHEME = 'sky' # You can also use: beige/serif/simple/night/default +# THEME_REVEAL_CONGIF_SUBTHEME = 'sky' # You can also use: beige/serif/simple/night/default # Again, if you use 'site-reveal' theme you can select several transitions between the slides # THEME_REVEAL_CONGIF_TRANSITION = 'cube' # You can also use: page/concave/linear/none/default @@ -261,6 +279,11 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL, # Enable comments on picture gallery pages? # COMMENTS_IN_GALLERIES = False +# If a link ends in /index.html, drop the index.html part. +# http://mysite/foo/bar/index.html => http://mysite/foo/bar/ +# Default = False +# STRIP_INDEX_HTML = False + # Do you want a add a Mathjax config file? # MATHJAX_CONFIG = "" @@ -328,6 +351,9 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL, # external resources. # USE_CDN = False +# Extra things you want in the pages HEAD tag. This will be added right +# before +# EXTRA_HEAD_DATA = "" # Google analytics or whatever else you use. Added to the bottom of # in the default template (base.tmpl). # ANALYTICS = "" @@ -379,6 +405,15 @@ CONTENT_FOOTER = CONTENT_FOOTER.format(email=BLOG_EMAIL, # Plugins you don't want to use. Be careful :-) # DISABLED_PLUGINS = ["render_galleries"] +# Experimental plugins - use at your own risk. +# They probably need some manual adjustments - please see their respective readme. +# ENABLED_EXTRAS = [ +# 'planetoid', +# 'ipynb', +# 'localsearch', +# 'mustache', +# ] + # Put in global_context things you want available on all your templates. # It can be anything, data, functions, modules, etc. diff --git a/nikola/data/themes/default/assets/css/code.css b/nikola/data/themes/default/assets/css/code.css deleted file mode 100644 index b1d7ace..0000000 --- a/nikola/data/themes/default/assets/css/code.css +++ /dev/null @@ -1,62 +0,0 @@ -pre { word-break: pre; white-space: pre; word-wrap: pre; overflow: auto; max-width: 100%;} -td.linenos { vertical-align: top; width: 4em;} -div.code > pre, .code -{ background: #f8f8f8; white-space: pre;} -.code .c { color: #008800; font-style: italic } /* Comment */ -.code .err { border: 1px solid #FF0000 } /* Error */ -.code .k { color: #AA22FF; font-weight: bold } /* Keyword */ -.code .o { color: #666666 } /* Operator */ -.code .cm { color: #008800; font-style: italic } /* Comment.Multiline */ -.code .cp { color: #008800 } /* Comment.Preproc */ -.code .c1 { color: #008800; font-style: italic } /* Comment.Single */ -.code .cs { color: #008800; font-weight: bold } /* Comment.Special */ -.code .gd { color: #A00000 } /* Generic.Deleted */ -.code .ge { font-style: italic } /* Generic.Emph */ -.code .gr { color: #FF0000 } /* Generic.Error */ -.code .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.code .gi { color: #00A000 } /* Generic.Inserted */ -.code .go { color: #808080 } /* Generic.Output */ -.code .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -.code .gs { font-weight: bold } /* Generic.Strong */ -.code .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.code .gt { color: #0040D0 } /* Generic.Traceback */ -.code .kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */ -.code .kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */ -.code .kp { color: #AA22FF } /* Keyword.Pseudo */ -.code .kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */ -.code .kt { color: #AA22FF; font-weight: bold } /* Keyword.Type */ -.code .m { color: #666666 } /* Literal.Number */ -.code .s { color: #BB4444 } /* Literal.String */ -.code .na { color: #BB4444 } /* Name.Attribute */ -.code .nb { color: #AA22FF } /* Name.Builtin */ -.code .nc { color: #0000FF } /* Name.Class */ -.code .no { color: #880000 } /* Name.Constant */ -.code .nd { color: #AA22FF } /* Name.Decorator */ -.code .ni { color: #999999; font-weight: bold } /* Name.Entity */ -.code .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -.code .nf { color: #00A000 } /* Name.Function */ -.code .nl { color: #A0A000 } /* Name.Label */ -.code .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ -.code .nt { color: #008000; font-weight: bold } /* Name.Tag */ -.code .nv { color: #B8860B } /* Name.Variable */ -.code .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ -.code .mf { color: #666666 } /* Literal.Number.Float */ -.code .mh { color: #666666 } /* Literal.Number.Hex */ -.code .mi { color: #666666 } /* Literal.Number.Integer */ -.code .mo { color: #666666 } /* Literal.Number.Oct */ -.code .sb { color: #BB4444 } /* Literal.String.Backtick */ -.code .sc { color: #BB4444 } /* Literal.String.Char */ -.code .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */ -.code .s2 { color: #BB4444 } /* Literal.String.Double */ -.code .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -.code .sh { color: #BB4444 } /* Literal.String.Heredoc */ -.code .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -.code .sx { color: #008000 } /* Literal.String.Other */ -.code .sr { color: #BB6688 } /* Literal.String.Regex */ -.code .s1 { color: #BB4444 } /* Literal.String.Single */ -.code .ss { color: #B8860B } /* Literal.String.Symbol */ -.code .bp { color: #AA22FF } /* Name.Builtin.Pseudo */ -.code .vc { color: #B8860B } /* Name.Variable.Class */ -.code .vg { color: #B8860B } /* Name.Variable.Global */ -.code .vi { color: #B8860B } /* Name.Variable.Instance */ -.code .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/nikola/data/themes/default/assets/css/slides.css b/nikola/data/themes/default/assets/css/slides.css deleted file mode 100644 index 272c83e..0000000 --- a/nikola/data/themes/default/assets/css/slides.css +++ /dev/null @@ -1,11 +0,0 @@ -.slides_container { - display: block; - margin-left: auto; - margin-right: auto; - max-width: 80%; - width: 400px; - height: 300px; -} -.slide-current { - font-weight: bold; -} diff --git a/nikola/data/themes/default/assets/css/theme.css b/nikola/data/themes/default/assets/css/theme.css index 0523ce9..08a71f3 100644 --- a/nikola/data/themes/default/assets/css/theme.css +++ b/nikola/data/themes/default/assets/css/theme.css @@ -60,3 +60,14 @@ blockquote p, blockquote { font-weight: 300; line-height: 1.25; } + +ul.bricks > li { + display: inline; + background-color: lightblue; + padding: 8px; + border-radius: 5px; + line-height: 3; + white-space:nowrap; + margin: 3px; +} + diff --git a/nikola/data/themes/default/assets/js/slides.jquery.js b/nikola/data/themes/default/assets/js/slides.jquery.js deleted file mode 100755 index f2e09c8..0000000 --- a/nikola/data/themes/default/assets/js/slides.jquery.js +++ /dev/null @@ -1,555 +0,0 @@ -/* -* Slides, A Slideshow Plugin for jQuery -* Intructions: http://slidesjs.com -* By: Nathan Searles, http://nathansearles.com -* Version: 1.1.9 -* Updated: September 5th, 2011 -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -(function($){ - $.fn.slides = function( option ) { - // override defaults with specified option - option = $.extend( {}, $.fn.slides.option, option ); - - return this.each(function(){ - // wrap slides in control container, make sure slides are block level - $('.' + option.container, $(this)).children().wrapAll('
'); - - var elem = $(this), - control = $('.slides_control',elem), - total = control.children().size(), - width = control.children().outerWidth(), - height = control.children().outerHeight(), - start = option.start - 1, - effect = option.effect.indexOf(',') < 0 ? option.effect : option.effect.replace(' ', '').split(',')[0], - paginationEffect = option.effect.indexOf(',') < 0 ? effect : option.effect.replace(' ', '').split(',')[1], - next = 0, prev = 0, number = 0, current = 0, loaded, active, clicked, position, direction, imageParent, pauseTimeout, playInterval; - - // is there only one slide? - if (total < 2) { - // Fade in .slides_container - $('.' + option.container, $(this)).fadeIn(option.fadeSpeed, option.fadeEasing, function(){ - // let the script know everything is loaded - loaded = true; - // call the loaded funciton - option.slidesLoaded(); - }); - // Hide the next/previous buttons - $('.' + option.next + ', .' + option.prev).fadeOut(0); - return false; - } - - // animate slides - function animate(direction, effect, clicked) { - if (!active && loaded) { - active = true; - // start of animation - option.animationStart(current + 1); - switch(direction) { - case 'next': - // change current slide to previous - prev = current; - // get next from current + 1 - next = current + 1; - // if last slide, set next to first slide - next = total === next ? 0 : next; - // set position of next slide to right of previous - position = width*2; - // distance to slide based on width of slides - direction = -width*2; - // store new current slide - current = next; - break; - case 'prev': - // change current slide to previous - prev = current; - // get next from current - 1 - next = current - 1; - // if first slide, set next to last slide - next = next === -1 ? total-1 : next; - // set position of next slide to left of previous - position = 0; - // distance to slide based on width of slides - direction = 0; - // store new current slide - current = next; - break; - case 'pagination': - // get next from pagination item clicked, convert to number - next = parseInt(clicked,10); - // get previous from pagination item with class of current - prev = $('.' + option.paginationClass + ' li.'+ option.currentClass +' a', elem).attr('href').match('[^#/]+$'); - // if next is greater then previous set position of next slide to right of previous - if (next > prev) { - position = width*2; - direction = -width*2; - } else { - // if next is less then previous set position of next slide to left of previous - position = 0; - direction = 0; - } - // store new current slide - current = next; - break; - } - - // fade animation - if (effect === 'fade') { - // fade animation with crossfade - if (option.crossfade) { - // put hidden next above current - control.children(':eq('+ next +')', elem).css({ - zIndex: 10 - // fade in next - }).fadeIn(option.fadeSpeed, option.fadeEasing, function(){ - if (option.autoHeight) { - // animate container to height of next - control.animate({ - height: control.children(':eq('+ next +')', elem).outerHeight() - }, option.autoHeightSpeed, function(){ - // hide previous - control.children(':eq('+ prev +')', elem).css({ - display: 'none', - zIndex: 0 - }); - // reset z index - control.children(':eq('+ next +')', elem).css({ - zIndex: 0 - }); - // end of animation - option.animationComplete(next + 1); - active = false; - }); - } else { - // hide previous - control.children(':eq('+ prev +')', elem).css({ - display: 'none', - zIndex: 0 - }); - // reset zindex - control.children(':eq('+ next +')', elem).css({ - zIndex: 0 - }); - // end of animation - option.animationComplete(next + 1); - active = false; - } - }); - } else { - // fade animation with no crossfade - control.children(':eq('+ prev +')', elem).fadeOut(option.fadeSpeed, option.fadeEasing, function(){ - // animate to new height - if (option.autoHeight) { - control.animate({ - // animate container to height of next - height: control.children(':eq('+ next +')', elem).outerHeight() - }, option.autoHeightSpeed, - // fade in next slide - function(){ - control.children(':eq('+ next +')', elem).fadeIn(option.fadeSpeed, option.fadeEasing); - }); - } else { - // if fixed height - control.children(':eq('+ next +')', elem).fadeIn(option.fadeSpeed, option.fadeEasing, function(){ - // fix font rendering in ie, lame - if($.browser.msie) { - $(this).get(0).style.removeAttribute('filter'); - } - }); - } - // end of animation - option.animationComplete(next + 1); - active = false; - }); - } - // slide animation - } else { - // move next slide to right of previous - control.children(':eq('+ next +')').css({ - left: position, - display: 'block' - }); - // animate to new height - if (option.autoHeight) { - control.animate({ - left: direction, - height: control.children(':eq('+ next +')').outerHeight() - },option.slideSpeed, option.slideEasing, function(){ - control.css({ - left: -width - }); - control.children(':eq('+ next +')').css({ - left: width, - zIndex: 5 - }); - // reset previous slide - control.children(':eq('+ prev +')').css({ - left: width, - display: 'none', - zIndex: 0 - }); - // end of animation - option.animationComplete(next + 1); - active = false; - }); - // if fixed height - } else { - // animate control - control.animate({ - left: direction - },option.slideSpeed, option.slideEasing, function(){ - // after animation reset control position - control.css({ - left: -width - }); - // reset and show next - control.children(':eq('+ next +')').css({ - left: width, - zIndex: 5 - }); - // reset previous slide - control.children(':eq('+ prev +')').css({ - left: width, - display: 'none', - zIndex: 0 - }); - // end of animation - option.animationComplete(next + 1); - active = false; - }); - } - } - // set current state for pagination - if (option.pagination) { - // remove current class from all - $('.'+ option.paginationClass +' li.' + option.currentClass, elem).removeClass(option.currentClass); - // add current class to next - $('.' + option.paginationClass + ' li:eq('+ next +')', elem).addClass(option.currentClass); - } - } - } // end animate function - - function stop() { - // clear interval from stored id - clearInterval(elem.data('interval')); - } - - function pause() { - if (option.pause) { - // clear timeout and interval - clearTimeout(elem.data('pause')); - clearInterval(elem.data('interval')); - // pause slide show for option.pause amount - pauseTimeout = setTimeout(function() { - // clear pause timeout - clearTimeout(elem.data('pause')); - // start play interval after pause - playInterval = setInterval( function(){ - animate("next", effect); - },option.play); - // store play interval - elem.data('interval',playInterval); - },option.pause); - // store pause interval - elem.data('pause',pauseTimeout); - } else { - // if no pause, just stop - stop(); - } - } - - // 2 or more slides required - if (total < 2) { - return; - } - - // error corection for start slide - if (start < 0) { - start = 0; - } - - if (start > total) { - start = total - 1; - } - - // change current based on start option number - if (option.start) { - current = start; - } - - // randomizes slide order - if (option.randomize) { - control.randomize(); - } - - // make sure overflow is hidden, width is set - $('.' + option.container, elem).css({ - overflow: 'hidden', - // fix for ie - position: 'relative' - }); - - // set css for slides - control.children().css({ - position: 'absolute', - top: 0, - left: control.children().outerWidth(), - zIndex: 0, - display: 'none' - }); - - // set css for control div - control.css({ - position: 'relative', - // size of control 3 x slide width - width: (width * 3), - // set height to slide height - height: height, - // center control to slide - left: -width - }); - - // show slides - $('.' + option.container, elem).css({ - display: 'block' - }); - - // if autoHeight true, get and set height of first slide - if (option.autoHeight) { - control.children().css({ - height: 'auto' - }); - control.animate({ - height: control.children(':eq('+ start +')').outerHeight() - },option.autoHeightSpeed); - } - - // checks if image is loaded - if (option.preload && control.find('img:eq(' + start + ')').length) { - // adds preload image - $('.' + option.container, elem).css({ - background: 'url(' + option.preloadImage + ') no-repeat 50% 50%' - }); - - // gets image src, with cache buster - var img = control.find('img:eq(' + start + ')').attr('src') + '?' + (new Date()).getTime(); - - // check if the image has a parent - if ($('img', elem).parent().attr('class') != 'slides_control') { - // If image has parent, get tag name - imageParent = control.children(':eq(0)')[0].tagName.toLowerCase(); - } else { - // Image doesn't have parent, use image tag name - imageParent = control.find('img:eq(' + start + ')'); - } - - // checks if image is loaded - control.find('img:eq(' + start + ')').attr('src', img).load(function() { - // once image is fully loaded, fade in - control.find(imageParent + ':eq(' + start + ')').fadeIn(option.fadeSpeed, option.fadeEasing, function(){ - $(this).css({ - zIndex: 5 - }); - // removes preload image - $('.' + option.container, elem).css({ - background: '' - }); - // let the script know everything is loaded - loaded = true; - // call the loaded funciton - option.slidesLoaded(); - }); - }); - } else { - // if no preloader fade in start slide - control.children(':eq(' + start + ')').fadeIn(option.fadeSpeed, option.fadeEasing, function(){ - // let the script know everything is loaded - loaded = true; - // call the loaded funciton - option.slidesLoaded(); - }); - } - - // click slide for next - if (option.bigTarget) { - // set cursor to pointer - control.children().css({ - cursor: 'pointer' - }); - // click handler - control.children().click(function(){ - // animate to next on slide click - animate('next', effect); - return false; - }); - } - - // pause on mouseover - if (option.hoverPause && option.play) { - control.bind('mouseover',function(){ - // on mouse over stop - stop(); - }); - control.bind('mouseleave',function(){ - // on mouse leave start pause timeout - pause(); - }); - } - - // generate next/prev buttons - if (option.generateNextPrev) { - $('.' + option.container, elem).after('Prev'); - $('.' + option.prev, elem).after('Next'); - } - - // next button - $('.' + option.next ,elem).click(function(e){ - e.preventDefault(); - if (option.play) { - pause(); - } - animate('next', effect); - }); - - // previous button - $('.' + option.prev, elem).click(function(e){ - e.preventDefault(); - if (option.play) { - pause(); - } - animate('prev', effect); - }); - - // generate pagination - if (option.generatePagination) { - // create unordered list - if (option.prependPagination) { - elem.prepend(''); - } else { - elem.append(''); - } - // for each slide create a list item and link - control.children().each(function(){ - $('.' + option.paginationClass, elem).append('
  • '+ (number+1) +'
  • '); - number++; - }); - } else { - // if pagination exists, add href w/ value of item number to links - $('.' + option.paginationClass + ' li a', elem).each(function(){ - $(this).attr('href', '#' + number); - number++; - }); - } - - // add current class to start slide pagination - $('.' + option.paginationClass + ' li:eq('+ start +')', elem).addClass(option.currentClass); - - // click handling - $('.' + option.paginationClass + ' li a', elem ).click(function(){ - // pause slideshow - if (option.play) { - pause(); - } - // get clicked, pass to animate function - clicked = $(this).attr('href').match('[^#/]+$'); - // if current slide equals clicked, don't do anything - if (current != clicked) { - animate('pagination', paginationEffect, clicked); - } - return false; - }); - - // click handling - $('a.link', elem).click(function(){ - // pause slideshow - if (option.play) { - pause(); - } - // get clicked, pass to animate function - clicked = $(this).attr('href').match('[^#/]+$') - 1; - // if current slide equals clicked, don't do anything - if (current != clicked) { - animate('pagination', paginationEffect, clicked); - } - return false; - }); - - if (option.play) { - // set interval - playInterval = setInterval(function() { - animate('next', effect); - }, option.play); - // store interval id - elem.data('interval',playInterval); - } - }); - }; - - // default options - $.fn.slides.option = { - preload: false, // boolean, Set true to preload images in an image based slideshow - preloadImage: '/img/loading.gif', // string, Name and location of loading image for preloader. Default is "/img/loading.gif" - container: 'slides_container', // string, Class name for slides container. Default is "slides_container" - generateNextPrev: false, // boolean, Auto generate next/prev buttons - next: 'next', // string, Class name for next button - prev: 'prev', // string, Class name for previous button - pagination: true, // boolean, If you're not using pagination you can set to false, but don't have to - generatePagination: true, // boolean, Auto generate pagination - prependPagination: false, // boolean, prepend pagination - paginationClass: 'pagination', // string, Class name for pagination - currentClass: 'current', // string, Class name for current class - fadeSpeed: 350, // number, Set the speed of the fading animation in milliseconds - fadeEasing: '', // string, must load jQuery's easing plugin before http://gsgd.co.uk/sandbox/jquery/easing/ - slideSpeed: 350, // number, Set the speed of the sliding animation in milliseconds - slideEasing: '', // string, must load jQuery's easing plugin before http://gsgd.co.uk/sandbox/jquery/easing/ - start: 1, // number, Set the speed of the sliding animation in milliseconds - effect: 'slide', // string, '[next/prev], [pagination]', e.g. 'slide, fade' or simply 'fade' for both - crossfade: false, // boolean, Crossfade images in a image based slideshow - randomize: false, // boolean, Set to true to randomize slides - play: 0, // number, Autoplay slideshow, a positive number will set to true and be the time between slide animation in milliseconds - pause: 0, // number, Pause slideshow on click of next/prev or pagination. A positive number will set to true and be the time of pause in milliseconds - hoverPause: false, // boolean, Set to true and hovering over slideshow will pause it - autoHeight: false, // boolean, Set to true to auto adjust height - autoHeightSpeed: 350, // number, Set auto height animation time in milliseconds - bigTarget: false, // boolean, Set to true and the whole slide will link to next slide on click - animationStart: function(){}, // Function called at the start of animation - animationComplete: function(){}, // Function called at the completion of animation - slidesLoaded: function() {} // Function is called when slides is fully loaded - }; - - // Randomize slide order on load - $.fn.randomize = function(callback) { - function randomizeOrder() { return(Math.round(Math.random())-0.5); } - return($(this).each(function() { - var $this = $(this); - var $children = $this.children(); - var childCount = $children.length; - if (childCount > 1) { - $children.hide(); - var indices = []; - for (i=0;i +${set_locale(lang)} ${html_head()} <%block name="extra_head"> + ${extra_head_data} %if add_this_buttons: @@ -22,7 +24,7 @@ <%block name="belowtitle"> %if len(translations) > 1: - ${(messages[lang][u"Also available in"])}:  + ${(messages("Also available in"))}:  ${html_translations()} %endif @@ -52,7 +54,7 @@
    - ${analytics} ${late_load_js()} + ${analytics} diff --git a/nikola/data/themes/default/templates/base_helper.tmpl b/nikola/data/themes/default/templates/base_helper.tmpl index eb22905..a833c51 100644 --- a/nikola/data/themes/default/templates/base_helper.tmpl +++ b/nikola/data/themes/default/templates/base_helper.tmpl @@ -22,7 +22,6 @@ - %if has_custom_css: @@ -34,9 +33,13 @@ %if rss_link: ${rss_link} %else: - %for language in translations: - - %endfor + %if len(translations) > 1: + %for language in translations: + + %endfor + %else: + + %endif %endif %if favicons: %for name, file, size in favicons: @@ -63,7 +66,6 @@ %endif - %endif @@ -98,7 +100,7 @@ <%def name="html_translations()"> %for langname in translations.keys(): %if langname != lang: - ${messages[langname]["LANGUAGE"]} + ${messages("LANGUAGE", langname)} %endif %endfor diff --git a/nikola/data/themes/default/templates/disqus_helper.tmpl b/nikola/data/themes/default/templates/disqus_helper.tmpl index 674e20e..4c60f85 100644 --- a/nikola/data/themes/default/templates/disqus_helper.tmpl +++ b/nikola/data/themes/default/templates/disqus_helper.tmpl @@ -1,6 +1,9 @@ ## -*- coding: utf-8 -*- <%! import json + translations = { + 'es': 'es_ES', + } %> <%def name="html_disqus(url, title, identifier)"> %if disqus_forum: @@ -12,8 +15,8 @@ %endif var disqus_title=${json.dumps(title)}; var disqus_identifier="${identifier}"; - var disqus_config = function () { - this.language = "${lang}"; + var disqus_config = function () { + this.language = "${translations.get(lang, lang)}"; }; (function() { var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; diff --git a/nikola/data/themes/default/templates/index.tmpl b/nikola/data/themes/default/templates/index.tmpl index 4f66867..b49e764 100644 --- a/nikola/data/themes/default/templates/index.tmpl +++ b/nikola/data/themes/default/templates/index.tmpl @@ -5,13 +5,15 @@ <%block name="content"> % for post in posts:
    -

    ${post.title(lang)} +

    ${post.title()}    - ${messages[lang]["Posted"]}: + ${messages("Posted")}:


    - ${post.text(lang, index_teasers)} - ${disqus.html_disqus_link(post.permalink()+"#disqus_thread", post.base_path)} + ${post.text(teaser_only=index_teasers)} + % if not post.meta('nocomments'): + ${disqus.html_disqus_link(post.permalink()+"#disqus_thread", post.base_path)} + % endif
    % endfor ${helper.html_pager()} diff --git a/nikola/data/themes/default/templates/index_helper.tmpl b/nikola/data/themes/default/templates/index_helper.tmpl index 151b4d2..7859972 100644 --- a/nikola/data/themes/default/templates/index_helper.tmpl +++ b/nikola/data/themes/default/templates/index_helper.tmpl @@ -4,11 +4,11 @@ diff --git a/nikola/data/themes/default/templates/list_post.tmpl b/nikola/data/themes/default/templates/list_post.tmpl index 1a1cdee..f0e159d 100644 --- a/nikola/data/themes/default/templates/list_post.tmpl +++ b/nikola/data/themes/default/templates/list_post.tmpl @@ -6,7 +6,7 @@

    ${title}

    diff --git a/nikola/data/themes/default/templates/post.tmpl b/nikola/data/themes/default/templates/post.tmpl index 22d8a58..f9e24d2 100644 --- a/nikola/data/themes/default/templates/post.tmpl +++ b/nikola/data/themes/default/templates/post.tmpl @@ -10,20 +10,24 @@ ${helper.twitter_card_information(post)} ${helper.html_title()}
    - ${messages[lang]["Posted"]}: + ${messages("Posted")}: ${helper.html_translations(post)} ${helper.html_tags(post)}
    - ${post.text(lang)} + ${post.text()} ${helper.html_pager(post)} - ${disqus.html_disqus(post.permalink(absolute=True), post.title(lang), post.base_path)} + % if not post.meta('nocomments'): + ${disqus.html_disqus(post.permalink(absolute=True), post.title(), post.base_path)} + % endif ${helper.mathjax_script(post)} <%block name="sourcelink"> +% if not post.meta('password'):
  • - ${messages[lang]["Source"]} + ${messages("Source")}
  • +% endif diff --git a/nikola/data/themes/default/templates/post_helper.tmpl b/nikola/data/themes/default/templates/post_helper.tmpl index 911a831..cce0ecf 100644 --- a/nikola/data/themes/default/templates/post_helper.tmpl +++ b/nikola/data/themes/default/templates/post_helper.tmpl @@ -2,7 +2,7 @@ <%def name="html_title()">

    ${title}

    % if link: -

    ${messages[lang]["Original site"]}

    +

    ${messages("Original site")}

    % endif @@ -12,7 +12,7 @@ %for langname in translations.keys(): %if langname != lang and post.is_translation_available(langname):   |   - ${messages[langname]["Read in English"]} + ${messages("Read in English", langname)} %endif %endfor %endif @@ -21,9 +21,9 @@ <%def name="html_tags(post)"> %if post.tags: -   |  ${messages[lang]["More posts about"]} +   |  ${messages("More posts about")} %for tag in post.tags: - ${tag} + ${tag} %endfor %endif @@ -32,19 +32,21 @@ <%def name="twitter_card_information(post)"> %if twitter_card and twitter_card['use_twitter_cards']: - - + + %if 'site:id' in twitter_card: %elif 'site' in twitter_card: @@ -55,11 +57,11 @@ %elif 'creator' in twitter_card: %endif - - %if post.description(lang): - + + %if post.description(): + %else: - + %endif %endif diff --git a/nikola/data/themes/default/templates/story.tmpl b/nikola/data/themes/default/templates/story.tmpl index d5c2f44..c1c06d8 100644 --- a/nikola/data/themes/default/templates/story.tmpl +++ b/nikola/data/themes/default/templates/story.tmpl @@ -1,12 +1,16 @@ ## -*- coding: utf-8 -*- <%inherit file="post.tmpl"/> +<%namespace name="helper" file="post_helper.tmpl"/> <%namespace name="disqus" file="disqus_helper.tmpl"/> +<%block name="extra_head"> +${helper.twitter_card_information(post)} + <%block name="content"> %if title:

    ${title}

    %endif - ${post.text(lang)} -%if enable_comments: - ${disqus.html_disqus(post.permalink(absolute=True), post.title(lang), post.base_path)} + ${post.text()} +%if enable_comments and not post.meta('nocomments'): + ${disqus.html_disqus(post.permalink(absolute=True), post.title(), post.base_path)} %endif diff --git a/nikola/data/themes/default/templates/tag.tmpl b/nikola/data/themes/default/templates/tag.tmpl index 7c89ad1..7fb43c0 100644 --- a/nikola/data/themes/default/templates/tag.tmpl +++ b/nikola/data/themes/default/templates/tag.tmpl @@ -1,7 +1,32 @@ ## -*- coding: utf-8 -*- <%inherit file="list_post.tmpl"/> <%block name="extra_head"> + %if len(translations) > 1: %for language in translations: - + %endfor + %else: + + %endif + + +<%block name="content"> + +
    +

    ${title}

    + %if len(translations) > 1: + %for language in translations: + RSS (${language})  + %endfor + %else: + RSS + %endif +
    + +
    + diff --git a/nikola/data/themes/default/templates/tags.tmpl b/nikola/data/themes/default/templates/tags.tmpl index 369a3d5..5727dc5 100644 --- a/nikola/data/themes/default/templates/tags.tmpl +++ b/nikola/data/themes/default/templates/tags.tmpl @@ -1,14 +1,12 @@ ## -*- coding: utf-8 -*- <%inherit file="base.tmpl"/> <%block name="content"> -
    - -

    ${title}

    - - -
    + +

    ${title}

    + + diff --git a/nikola/data/themes/jinja-default/templates/base.tmpl b/nikola/data/themes/jinja-default/templates/base.tmpl index 97cddff..c104b20 100644 --- a/nikola/data/themes/jinja-default/templates/base.tmpl +++ b/nikola/data/themes/jinja-default/templates/base.tmpl @@ -1,4 +1,5 @@ +{{set_locale(lang)}} @@ -23,7 +24,6 @@ - {% if has_custom_css %} @@ -42,6 +42,7 @@ {% endif %} {% block extra_head %} {% endblock %} + {{extra_head_data}} {% if add_this_buttons %} @@ -58,10 +59,10 @@ {% block belowtitle%} {% if translations|length > 1 %} - {{ messages[lang]["Also available in"] }}:  + {{ messages("Also available in") }}:  {% for langname in translations.keys() %} {% if langname != lang %} - {{messages[langname]["LANGUAGE"]}} + {{messages("LANGUAGE", langname)}} {% endif %} {% endfor %} @@ -106,7 +107,6 @@ - {{analytics}} {% if use_bundles %} {% if use_cdn %} @@ -125,7 +125,7 @@ {% endif %} - {% endif %} + {{analytics}} diff --git a/nikola/data/themes/jinja-default/templates/index.tmpl b/nikola/data/themes/jinja-default/templates/index.tmpl index ab0392c..7d1aa00 100644 --- a/nikola/data/themes/jinja-default/templates/index.tmpl +++ b/nikola/data/themes/jinja-default/templates/index.tmpl @@ -2,14 +2,14 @@ {% block content %} {% for post in posts %}
    -

    {{post.title(lang)}} +

    {{post.title()}}    - {{messages[lang]["Posted"]}}: {{post.date.strftime(date_format)}} + {{messages("Posted")}}: {{post.formatted_date(date_format)}}


    - {{post.text(lang, index_teasers)}} + {{post.text(teaser_only=index_teasers)}}

    - {% if disqus_forum %} + {% if disqus_forum and not post.meta('nocomments')%} Comments {% endif %}

    @@ -18,11 +18,11 @@ diff --git a/nikola/data/themes/jinja-default/templates/list_post.tmpl b/nikola/data/themes/jinja-default/templates/list_post.tmpl index 7723214..b4ac59e 100644 --- a/nikola/data/themes/jinja-default/templates/list_post.tmpl +++ b/nikola/data/themes/jinja-default/templates/list_post.tmpl @@ -5,7 +5,7 @@

    {{title}}

    diff --git a/nikola/data/themes/jinja-default/templates/post.tmpl b/nikola/data/themes/jinja-default/templates/post.tmpl index d14e973..ab96682 100644 --- a/nikola/data/themes/jinja-default/templates/post.tmpl +++ b/nikola/data/themes/jinja-default/templates/post.tmpl @@ -3,49 +3,50 @@

    {{title}}

    {% if link %} -

    {{messages[lang]["Original site"]}}

    +

    {{messages("Original site")}}

    {% endif %}
    - {{messages[lang]["Posted"]}}: {{post.date.strftime(date_format)}}  |   + {{messages("Posted")}}: {{post.formatted_date(date_format)}}  |   {% if translations|length > 1 %} {% for langname in translations.keys() %} {% if langname != lang and post.is_translation_available(langname) %} - {{messages[langname]["Read in English"]}} + {{messages("Read in English", langname)}}   |   {% endif %} {% endfor %} {% endif %} - - {{messages[lang]["Source"]}} + {% if not post.meta('password') + {{messages("Source")}} + {% endif %} {% if post.tags %} -   |  {{messages[lang]["More posts about"]}} +   |  {{messages("More posts about")}} {% for tag in post.tags %} - {{tag}} + {{tag}} {% endfor %} {% endif %}
    - {{post.text(lang)}} + {{post.text()}} - {% if disqus_forum %} + {% if disqus_forum and not post.meta('nocomments')%}
    + {%endif%} {% endblock %} diff --git a/nikola/data/themes/jinja-default/templates/tag.tmpl b/nikola/data/themes/jinja-default/templates/tag.tmpl index 42720fd..77db27d 100644 --- a/nikola/data/themes/jinja-default/templates/tag.tmpl +++ b/nikola/data/themes/jinja-default/templates/tag.tmpl @@ -1,6 +1,6 @@ {% extends "list_post.tmpl"%} {%block extra_head %} {% for language in translations %} - + {% endfor %} {% endblock %} diff --git a/nikola/data/themes/jinja-default/templates/tags.tmpl b/nikola/data/themes/jinja-default/templates/tags.tmpl index 3eae88d..0fa9d0f 100644 --- a/nikola/data/themes/jinja-default/templates/tags.tmpl +++ b/nikola/data/themes/jinja-default/templates/tags.tmpl @@ -3,9 +3,9 @@

    {{title}}

    -
      + diff --git a/nikola/data/themes/monospace/assets/css/code.css b/nikola/data/themes/monospace/assets/css/code.css deleted file mode 100644 index b1d7ace..0000000 --- a/nikola/data/themes/monospace/assets/css/code.css +++ /dev/null @@ -1,62 +0,0 @@ -pre { word-break: pre; white-space: pre; word-wrap: pre; overflow: auto; max-width: 100%;} -td.linenos { vertical-align: top; width: 4em;} -div.code > pre, .code -{ background: #f8f8f8; white-space: pre;} -.code .c { color: #008800; font-style: italic } /* Comment */ -.code .err { border: 1px solid #FF0000 } /* Error */ -.code .k { color: #AA22FF; font-weight: bold } /* Keyword */ -.code .o { color: #666666 } /* Operator */ -.code .cm { color: #008800; font-style: italic } /* Comment.Multiline */ -.code .cp { color: #008800 } /* Comment.Preproc */ -.code .c1 { color: #008800; font-style: italic } /* Comment.Single */ -.code .cs { color: #008800; font-weight: bold } /* Comment.Special */ -.code .gd { color: #A00000 } /* Generic.Deleted */ -.code .ge { font-style: italic } /* Generic.Emph */ -.code .gr { color: #FF0000 } /* Generic.Error */ -.code .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -.code .gi { color: #00A000 } /* Generic.Inserted */ -.code .go { color: #808080 } /* Generic.Output */ -.code .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -.code .gs { font-weight: bold } /* Generic.Strong */ -.code .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -.code .gt { color: #0040D0 } /* Generic.Traceback */ -.code .kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */ -.code .kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */ -.code .kp { color: #AA22FF } /* Keyword.Pseudo */ -.code .kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */ -.code .kt { color: #AA22FF; font-weight: bold } /* Keyword.Type */ -.code .m { color: #666666 } /* Literal.Number */ -.code .s { color: #BB4444 } /* Literal.String */ -.code .na { color: #BB4444 } /* Name.Attribute */ -.code .nb { color: #AA22FF } /* Name.Builtin */ -.code .nc { color: #0000FF } /* Name.Class */ -.code .no { color: #880000 } /* Name.Constant */ -.code .nd { color: #AA22FF } /* Name.Decorator */ -.code .ni { color: #999999; font-weight: bold } /* Name.Entity */ -.code .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -.code .nf { color: #00A000 } /* Name.Function */ -.code .nl { color: #A0A000 } /* Name.Label */ -.code .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ -.code .nt { color: #008000; font-weight: bold } /* Name.Tag */ -.code .nv { color: #B8860B } /* Name.Variable */ -.code .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ -.code .mf { color: #666666 } /* Literal.Number.Float */ -.code .mh { color: #666666 } /* Literal.Number.Hex */ -.code .mi { color: #666666 } /* Literal.Number.Integer */ -.code .mo { color: #666666 } /* Literal.Number.Oct */ -.code .sb { color: #BB4444 } /* Literal.String.Backtick */ -.code .sc { color: #BB4444 } /* Literal.String.Char */ -.code .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */ -.code .s2 { color: #BB4444 } /* Literal.String.Double */ -.code .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -.code .sh { color: #BB4444 } /* Literal.String.Heredoc */ -.code .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -.code .sx { color: #008000 } /* Literal.String.Other */ -.code .sr { color: #BB6688 } /* Literal.String.Regex */ -.code .s1 { color: #BB4444 } /* Literal.String.Single */ -.code .ss { color: #B8860B } /* Literal.String.Symbol */ -.code .bp { color: #AA22FF } /* Name.Builtin.Pseudo */ -.code .vc { color: #B8860B } /* Name.Variable.Class */ -.code .vg { color: #B8860B } /* Name.Variable.Global */ -.code .vi { color: #B8860B } /* Name.Variable.Instance */ -.code .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/nikola/data/themes/monospace/bundles b/nikola/data/themes/monospace/bundles index aa35d9c..4760181 100644 --- a/nikola/data/themes/monospace/bundles +++ b/nikola/data/themes/monospace/bundles @@ -1 +1,2 @@ assets/css/all.css=rst.css,code.css,theme.css +assets/css/all-nocdn.css=rst.css,code.css,theme.css diff --git a/nikola/data/themes/monospace/templates/base.tmpl b/nikola/data/themes/monospace/templates/base.tmpl index 9eecbd4..806795d 100644 --- a/nikola/data/themes/monospace/templates/base.tmpl +++ b/nikola/data/themes/monospace/templates/base.tmpl @@ -1,11 +1,13 @@ ## -*- coding: utf-8 -*- <%namespace file="base_helper.tmpl" import="*"/> +${set_locale(lang)} ${html_head()} <%block name="extra_head"> + ${extra_head_data} %if add_this_buttons: @@ -23,7 +25,7 @@ <%block name="belowtitle"> %if len(translations) > 1: - ${(messages[lang][u"Also available in"])}:  + ${(messages("Also available in"))}:  ${html_translations()} %endif @@ -38,6 +40,6 @@ -
    +
    ${analytics} diff --git a/nikola/data/themes/monospace/templates/base_helper.tmpl b/nikola/data/themes/monospace/templates/base_helper.tmpl index aba8dff..4f3e45b 100644 --- a/nikola/data/themes/monospace/templates/base_helper.tmpl +++ b/nikola/data/themes/monospace/templates/base_helper.tmpl @@ -4,27 +4,29 @@ ${title} | ${blog_title} - + ${mathjax_config} %if use_bundles: - - + %if use_cdn: + + + %else: + + %endif %else: - + %if use_cdn: + + %else: + + + %endif - %if has_custom_css: %endif - - - - - %endif - @@ -32,7 +34,7 @@ ${rss_link} %else: %for language in translations: - + %endfor %endif %if favicons: @@ -48,10 +50,10 @@
    Share -
    @@ -74,7 +76,7 @@ <%def name="html_translations()"> %for langname in translations.keys(): %if langname != lang: - ${messages[langname]["LANGUAGE"]} + ${messages("LANGUAGE", langname)} %endif %endfor diff --git a/nikola/data/themes/monospace/templates/disqus_helper.tmpl b/nikola/data/themes/monospace/templates/disqus_helper.tmpl index 674e20e..4c60f85 100644 --- a/nikola/data/themes/monospace/templates/disqus_helper.tmpl +++ b/nikola/data/themes/monospace/templates/disqus_helper.tmpl @@ -1,6 +1,9 @@ ## -*- coding: utf-8 -*- <%! import json + translations = { + 'es': 'es_ES', + } %> <%def name="html_disqus(url, title, identifier)"> %if disqus_forum: @@ -12,8 +15,8 @@ %endif var disqus_title=${json.dumps(title)}; var disqus_identifier="${identifier}"; - var disqus_config = function () { - this.language = "${lang}"; + var disqus_config = function () { + this.language = "${translations.get(lang, lang)}"; }; (function() { var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; diff --git a/nikola/data/themes/monospace/templates/index.tmpl b/nikola/data/themes/monospace/templates/index.tmpl index ee57d26..4a0c630 100644 --- a/nikola/data/themes/monospace/templates/index.tmpl +++ b/nikola/data/themes/monospace/templates/index.tmpl @@ -5,22 +5,24 @@ <%block name="content"> % for post in posts:
    -

    ${post.title(lang)}

    +

    ${post.title()}

    - ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} + ${messages("Posted")}: ${post.formatted_date(date_format)}
    Tags:  %if post.tags: %for tag in post.tags: - ${tag} + ${tag} %endfor %endif
    - ${post.text(lang, index_teasers)} - ${disqus.html_disqus_link(post.permalink()+"#disqus_thread", post.base_path)} + ${post.text(teaser_only=index_teasers)} + % if not post.meta('nocomments'): + ${disqus.html_disqus_link(post.permalink()+"#disqus_thread", post.base_path)} + % endif
    % endfor ${helper.html_pager()} diff --git a/nikola/data/themes/monospace/templates/index_helper.tmpl b/nikola/data/themes/monospace/templates/index_helper.tmpl index 114a730..1bb700c 100644 --- a/nikola/data/themes/monospace/templates/index_helper.tmpl +++ b/nikola/data/themes/monospace/templates/index_helper.tmpl @@ -4,12 +4,12 @@ diff --git a/nikola/data/themes/monospace/templates/list_post.tmpl b/nikola/data/themes/monospace/templates/list_post.tmpl index 1a1cdee..f0e159d 100644 --- a/nikola/data/themes/monospace/templates/list_post.tmpl +++ b/nikola/data/themes/monospace/templates/list_post.tmpl @@ -6,7 +6,7 @@

    ${title}

    diff --git a/nikola/data/themes/monospace/templates/post.tmpl b/nikola/data/themes/monospace/templates/post.tmpl index 2ba27f1..0ec360d 100644 --- a/nikola/data/themes/monospace/templates/post.tmpl +++ b/nikola/data/themes/monospace/templates/post.tmpl @@ -7,13 +7,16 @@ ${helper.html_title()}
    - ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} [${messages[lang]["Source"]}] + ${messages("Posted")}: ${post.formatted_date(date_format)} + % if not post.meta('password'): + [${messages("Source")}] + % endif
    %if post.tags: - ${messages[lang]["Tags"]}:  + ${messages("Tags")}:  %for tag in post.tags: - ${tag} + ${tag} %endfor
    @@ -22,8 +25,10 @@ ${helper.html_translations(post)}
    - ${post.text(lang)} + ${post.text()} ${helper.html_pager(post)} - ${disqus.html_disqus(post.permalink(absolute=True), post.title(lang), post.base_path)} + % if not post.meta('nocomments'): + ${disqus.html_disqus(post.permalink(absolute=True), post.title(), post.base_path)} + % endif diff --git a/nikola/data/themes/monospace/templates/post_helper.tmpl b/nikola/data/themes/monospace/templates/post_helper.tmpl index 8651c65..cce0ecf 100644 --- a/nikola/data/themes/monospace/templates/post_helper.tmpl +++ b/nikola/data/themes/monospace/templates/post_helper.tmpl @@ -2,7 +2,7 @@ <%def name="html_title()">

    ${title}

    % if link: -

    ${messages[lang]["Original site"]}

    +

    ${messages("Original site")}

    % endif @@ -12,7 +12,7 @@ %for langname in translations.keys(): %if langname != lang and post.is_translation_available(langname):   |   - ${messages[langname]["Read in English"]} + ${messages("Read in English", langname)} %endif %endfor %endif @@ -21,25 +21,53 @@ <%def name="html_tags(post)"> %if post.tags: -   |  ${messages[lang]["More posts about"]} +   |  ${messages("More posts about")} %for tag in post.tags: - ${tag} + ${tag} %endfor %endif - <%def name="html_pager(post)"> + +<%def name="twitter_card_information(post)"> + %if twitter_card and twitter_card['use_twitter_cards']: + + + %if 'site:id' in twitter_card: + + %elif 'site' in twitter_card: + + %endif + %if 'creator:id' in twitter_card: + + %elif 'creator' in twitter_card: + + %endif + + %if post.description(): + + %else: + + %endif + %endif + + +<%def name="mathjax_script(post)"> + %if post.is_mathjax: + + %endif + diff --git a/nikola/data/themes/monospace/templates/story.tmpl b/nikola/data/themes/monospace/templates/story.tmpl index 30d263b..21d0e2f 100644 --- a/nikola/data/themes/monospace/templates/story.tmpl +++ b/nikola/data/themes/monospace/templates/story.tmpl @@ -1,11 +1,15 @@ ## -*- coding: utf-8 -*- <%inherit file="post.tmpl"/> +<%namespace name="helper" file="post_helper.tmpl"/> +<%block name="extra_head"> +${helper.twitter_card_information(post)} + <%block name="content"> %if title:

    ${title}

    %endif - ${post.text(lang)} -%if enable_comments: - ${disqus.html_disqus(post.permalink(absolute=True), post.title(lang), post.base_path)} + ${post.text()} +%if enable_comments and not post.meta('nocomments'): + ${disqus.html_disqus(post.permalink(absolute=True), post.title(), post.base_path)} %endif diff --git a/nikola/data/themes/monospace/templates/tag.tmpl b/nikola/data/themes/monospace/templates/tag.tmpl index 7c89ad1..97aafeb 100644 --- a/nikola/data/themes/monospace/templates/tag.tmpl +++ b/nikola/data/themes/monospace/templates/tag.tmpl @@ -2,6 +2,6 @@ <%inherit file="list_post.tmpl"/> <%block name="extra_head"> %for language in translations: - + %endfor diff --git a/nikola/data/themes/orphan/assets/css/code.css b/nikola/data/themes/orphan/assets/css/code.css deleted file mode 120000 index 6b2b872..0000000 --- a/nikola/data/themes/orphan/assets/css/code.css +++ /dev/null @@ -1 +0,0 @@ -../../../default/assets/css/code.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 39e2b9d..2a62b58 100644 --- a/nikola/data/themes/orphan/templates/base.tmpl +++ b/nikola/data/themes/orphan/templates/base.tmpl @@ -1,11 +1,13 @@ ## -*- coding: utf-8 -*- <%namespace file="base_helper.tmpl" import="*"/> +${set_locale(lang)} ${html_head()} <%block name="extra_head"> + ${extra_head_data} %if add_this_buttons: @@ -17,7 +19,7 @@ <%block name="belowtitle"> %if len(translations) > 1: - ${(messages[lang][u"Also available in"])}:  + ${(messages("Also available in"))}:  ${html_translations()} %endif diff --git a/nikola/data/themes/orphan/templates/base_helper.tmpl b/nikola/data/themes/orphan/templates/base_helper.tmpl index aba8dff..4f3e45b 100644 --- a/nikola/data/themes/orphan/templates/base_helper.tmpl +++ b/nikola/data/themes/orphan/templates/base_helper.tmpl @@ -4,27 +4,29 @@ ${title} | ${blog_title} - + ${mathjax_config} %if use_bundles: - - + %if use_cdn: + + + %else: + + %endif %else: - + %if use_cdn: + + %else: + + + %endif - %if has_custom_css: %endif - - - - - %endif - @@ -32,7 +34,7 @@ ${rss_link} %else: %for language in translations: - + %endfor %endif %if favicons: @@ -48,10 +50,10 @@
    Share -
    @@ -74,7 +76,7 @@ <%def name="html_translations()"> %for langname in translations.keys(): %if langname != lang: - ${messages[langname]["LANGUAGE"]} + ${messages("LANGUAGE", langname)} %endif %endfor diff --git a/nikola/data/themes/orphan/templates/disqus_helper.tmpl b/nikola/data/themes/orphan/templates/disqus_helper.tmpl index 674e20e..4c60f85 100644 --- a/nikola/data/themes/orphan/templates/disqus_helper.tmpl +++ b/nikola/data/themes/orphan/templates/disqus_helper.tmpl @@ -1,6 +1,9 @@ ## -*- coding: utf-8 -*- <%! import json + translations = { + 'es': 'es_ES', + } %> <%def name="html_disqus(url, title, identifier)"> %if disqus_forum: @@ -12,8 +15,8 @@ %endif var disqus_title=${json.dumps(title)}; var disqus_identifier="${identifier}"; - var disqus_config = function () { - this.language = "${lang}"; + var disqus_config = function () { + this.language = "${translations.get(lang, lang)}"; }; (function() { var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; diff --git a/nikola/data/themes/orphan/templates/index.tmpl b/nikola/data/themes/orphan/templates/index.tmpl index 1a436e2..59d391a 100644 --- a/nikola/data/themes/orphan/templates/index.tmpl +++ b/nikola/data/themes/orphan/templates/index.tmpl @@ -5,13 +5,15 @@ <%block name="content"> % for post in posts:
    -

    ${post.title(lang)} +

    ${post.title()}    - ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} + ${messages("Posted")}: ${post.formatted_date(date_format)}


    - ${post.text(lang, index_teasers)} - ${disqus.html_disqus_link(post.permalink()+"#disqus_thread", post.base_path)} + ${post.text(teaser_only=index_teasers)} + % if not post.meta('nocomments'): + ${disqus.html_disqus_link(post.permalink()+"#disqus_thread", post.base_path)} + % endif
    % endfor ${helper.html_pager()} diff --git a/nikola/data/themes/orphan/templates/index_helper.tmpl b/nikola/data/themes/orphan/templates/index_helper.tmpl index 114a730..1bb700c 100644 --- a/nikola/data/themes/orphan/templates/index_helper.tmpl +++ b/nikola/data/themes/orphan/templates/index_helper.tmpl @@ -4,12 +4,12 @@ diff --git a/nikola/data/themes/orphan/templates/list_post.tmpl b/nikola/data/themes/orphan/templates/list_post.tmpl index 1a1cdee..f0e159d 100644 --- a/nikola/data/themes/orphan/templates/list_post.tmpl +++ b/nikola/data/themes/orphan/templates/list_post.tmpl @@ -6,7 +6,7 @@

    ${title}

    diff --git a/nikola/data/themes/orphan/templates/post.tmpl b/nikola/data/themes/orphan/templates/post.tmpl index 672d4f6..6f6529d 100644 --- a/nikola/data/themes/orphan/templates/post.tmpl +++ b/nikola/data/themes/orphan/templates/post.tmpl @@ -7,15 +7,19 @@ ${helper.html_title()}
    - ${messages[lang]["Posted"]}: ${post.date.strftime(date_format)} + ${messages("Posted")}: ${post.formatted_date(date_format)} ${helper.html_translations(post)}   |   - ${messages[lang]["Source"]} + % if not post.meta('password'): + ${messages("Source")} + % endif ${helper.html_tags(post)}
    - ${post.text(lang)} + ${post.text()} ${helper.html_pager(post)} - ${disqus.html_disqus(post.permalink(absolute=True), post.title(lang), post.base_path)} + % if not post.meta('nocomments'): + ${disqus.html_disqus(post.permalink(absolute=True), post.title(), post.base_path)} + % endif diff --git a/nikola/data/themes/orphan/templates/post_helper.tmpl b/nikola/data/themes/orphan/templates/post_helper.tmpl index a3dc75f..cce0ecf 100644 --- a/nikola/data/themes/orphan/templates/post_helper.tmpl +++ b/nikola/data/themes/orphan/templates/post_helper.tmpl @@ -2,7 +2,7 @@ <%def name="html_title()">

    ${title}

    % if link: -

    ${messages[lang]["Original site"]}

    +

    ${messages("Original site")}

    % endif @@ -10,9 +10,9 @@ <%def name="html_translations(post)"> %if len(translations) > 1: %for langname in translations.keys(): - %if langname != lang and post.is_translation_available(langname): + %if langname != lang and post.is_translation_available(langname):   |   - ${messages[langname]["Read in English"]} + ${messages("Read in English", langname)} %endif %endfor %endif @@ -21,25 +21,53 @@ <%def name="html_tags(post)"> %if post.tags: -   |  ${messages[lang]["More posts about"]} +   |  ${messages("More posts about")} %for tag in post.tags: - ${tag} + ${tag} %endfor %endif - <%def name="html_pager(post)"> + +<%def name="twitter_card_information(post)"> + %if twitter_card and twitter_card['use_twitter_cards']: + + + %if 'site:id' in twitter_card: + + %elif 'site' in twitter_card: + + %endif + %if 'creator:id' in twitter_card: + + %elif 'creator' in twitter_card: + + %endif + + %if post.description(): + + %else: + + %endif + %endif + + +<%def name="mathjax_script(post)"> + %if post.is_mathjax: + + %endif + diff --git a/nikola/data/themes/orphan/templates/story.tmpl b/nikola/data/themes/orphan/templates/story.tmpl index 30d263b..21d0e2f 100644 --- a/nikola/data/themes/orphan/templates/story.tmpl +++ b/nikola/data/themes/orphan/templates/story.tmpl @@ -1,11 +1,15 @@ ## -*- coding: utf-8 -*- <%inherit file="post.tmpl"/> +<%namespace name="helper" file="post_helper.tmpl"/> +<%block name="extra_head"> +${helper.twitter_card_information(post)} + <%block name="content"> %if title:

    ${title}

    %endif - ${post.text(lang)} -%if enable_comments: - ${disqus.html_disqus(post.permalink(absolute=True), post.title(lang), post.base_path)} + ${post.text()} +%if enable_comments and not post.meta('nocomments'): + ${disqus.html_disqus(post.permalink(absolute=True), post.title(), post.base_path)} %endif diff --git a/nikola/data/themes/orphan/templates/tag.tmpl b/nikola/data/themes/orphan/templates/tag.tmpl index 7c89ad1..97aafeb 100644 --- a/nikola/data/themes/orphan/templates/tag.tmpl +++ b/nikola/data/themes/orphan/templates/tag.tmpl @@ -2,6 +2,6 @@ <%inherit file="list_post.tmpl"/> <%block name="extra_head"> %for language in translations: - + %endfor diff --git a/nikola/data/themes/site-planetoid/README b/nikola/data/themes/site-planetoid/README new file mode 100644 index 0000000..c148591 --- /dev/null +++ b/nikola/data/themes/site-planetoid/README @@ -0,0 +1 @@ +A version of the site theme for the use with the "planetoid" plugin. diff --git a/nikola/data/themes/site-planetoid/engine b/nikola/data/themes/site-planetoid/engine new file mode 100644 index 0000000..2951cdd --- /dev/null +++ b/nikola/data/themes/site-planetoid/engine @@ -0,0 +1 @@ +mako diff --git a/nikola/data/themes/site-planetoid/parent b/nikola/data/themes/site-planetoid/parent new file mode 100644 index 0000000..1320f90 --- /dev/null +++ b/nikola/data/themes/site-planetoid/parent @@ -0,0 +1 @@ +site diff --git a/nikola/data/themes/site-planetoid/templates/index.tmpl b/nikola/data/themes/site-planetoid/templates/index.tmpl new file mode 100644 index 0000000..29243e0 --- /dev/null +++ b/nikola/data/themes/site-planetoid/templates/index.tmpl @@ -0,0 +1,16 @@ +## -*- coding: utf-8 -*- +<%namespace name="helper" file="index_helper.tmpl"/> +<%inherit file="base.tmpl"/> +<%block name="content"> + % for post in posts: +
    +

    ${post.title(lang)} +    + ${messages("Posted")}: +

    + ${post.text(lang)} +
    + % endfor + ${helper.html_pager()} + + diff --git a/nikola/data/themes/site-planetoid/templates/post.tmpl b/nikola/data/themes/site-planetoid/templates/post.tmpl new file mode 100644 index 0000000..d60de78 --- /dev/null +++ b/nikola/data/themes/site-planetoid/templates/post.tmpl @@ -0,0 +1,9 @@ +## -*- coding: utf-8 -*- + + + + + +Redirecting you to the original location. + + diff --git a/nikola/data/themes/site-planetoid/templates/story.tmpl b/nikola/data/themes/site-planetoid/templates/story.tmpl new file mode 100644 index 0000000..7712e71 --- /dev/null +++ b/nikola/data/themes/site-planetoid/templates/story.tmpl @@ -0,0 +1,25 @@ +## -*- coding: utf-8 -*- +<%namespace name="helper" file="post_helper.tmpl"/> +<%namespace name="disqus" file="disqus_helper.tmpl"/> +<%inherit file="base.tmpl"/> +<%block name="extra_head"> +${helper.twitter_card_information(post)} + + +<%block name="content"> +%if title: +

    ${title}

    +%endif + ${post.text()} +%if enable_comments and not post.meta('nocomments'): + ${disqus.html_disqus(post.permalink(absolute=True), post.title(), post.base_path)} +%endif + + +<%block name="sourcelink"> +% if not post.meta('password'): +
  • + ${messages("Source")} +
  • +% endif + diff --git a/nikola/data/themes/site/assets/css/theme.css b/nikola/data/themes/site/assets/css/theme.css index aa0ee4a..24072ac 100644 --- a/nikola/data/themes/site/assets/css/theme.css +++ b/nikola/data/themes/site/assets/css/theme.css @@ -64,3 +64,17 @@ blockquote p, blockquote { line-height: 1.25; } +ul.bricks > li { + display: inline; + background-color: lightblue; + padding: 8px; + border-radius: 5px; + line-height: 3; + white-space:nowrap; + margin: 3px; +} + +h1, h2, h3, h4, h5, h6, h7 { + margin-top: -40px; + padding-top: 40px; +} diff --git a/nikola/data/themes/site/templates/base.tmpl b/nikola/data/themes/site/templates/base.tmpl index 416d04b..4efd0ad 100644 --- a/nikola/data/themes/site/templates/base.tmpl +++ b/nikola/data/themes/site/templates/base.tmpl @@ -1,5 +1,6 @@ ## -*- coding: utf-8 -*- <%namespace file="base_helper.tmpl" import="*"/> +${set_locale(lang)} @@ -7,20 +8,21 @@ ${html_head()} <%block name="extra_head"> + ${extra_head_data}
    ${content_footer}
    ${html_social()} -${analytics} ${late_load_js()} +${analytics} diff --git a/nikola/main.py b/nikola/main.py index b390387..8263b7e 100644 --- a/nikola/main.py +++ b/nikola/main.py @@ -35,16 +35,13 @@ from doit.cmd_help import Help as DoitHelp from doit.cmd_run import Run as DoitRun from .nikola import Nikola +from .utils import _reload def main(args): sys.path.append('') try: import conf - if sys.version_info[0] > 2: - from imp import reload as _reload - else: - _reload = reload # NOQA _reload(conf) config = conf.__dict__ except ImportError: @@ -111,7 +108,7 @@ class DoitNikola(DoitMain): sub_cmds = self.get_commands() args = self.process_args(cmd_args) - if len(args) == 0 or args == ["--help"]: + if len(args) == 0 or any(arg in ["--help", '-h'] for arg in args): cmd_args = ['help'] args = ['help'] diff --git a/nikola/nikola.py b/nikola/nikola.py index a1506e7..8660a0f 100644 --- a/nikola/nikola.py +++ b/nikola/nikola.py @@ -28,12 +28,14 @@ from collections import defaultdict from copy import copy import glob import gzip +import locale import os import sys try: from urlparse import urlparse, urlsplit, urljoin except ImportError: from urllib.parse import urlparse, urlsplit, urljoin # NOQA +import warnings import lxml.html from yapsy.PluginManager import PluginManager @@ -67,12 +69,19 @@ class Nikola(object): Takes a site config as argument on creation. """ + EXTRA_PLUGINS = [ + 'planetoid', + 'ipynb', + 'local_search', + 'render_mustache', + ] def __init__(self, **config): """Setup proper environment for running tasks.""" self.global_data = {} self.posts_per_year = defaultdict(list) + self.posts_per_month = defaultdict(list) self.posts_per_tag = defaultdict(list) self.timeline = [] self.pages = [] @@ -83,21 +92,24 @@ class Nikola(object): self.configured = True # This is the default config - # TODO: fill it self.config = { 'ADD_THIS_BUTTONS': True, 'ANALYTICS': '', 'ARCHIVE_PATH': "", 'ARCHIVE_FILENAME': "archive.html", 'CACHE_FOLDER': 'cache', + 'CODE_COLOR_SCHEME': 'default', 'COMMENTS_IN_GALLERIES': False, 'COMMENTS_IN_STORIES': False, 'CONTENT_FOOTER': '', + 'CREATE_MONTHLY_ARCHIVE': False, 'DATE_FORMAT': '%Y-%m-%d %H:%M', 'DEFAULT_LANG': "en", 'DEPLOY_COMMANDS': [], 'DISABLED_PLUGINS': (), 'DISQUS_FORUM': 'nikolademo', + 'ENABLED_EXTRAS': (), + 'EXTRA_HEAD_DATA': '', 'FAVICONS': {}, 'FILE_METADATA_REGEXP': None, 'FILES_FOLDERS': {'files': ''}, @@ -105,6 +117,7 @@ class Nikola(object): 'GALLERY_PATH': 'galleries', 'GZIP_FILES': False, 'GZIP_EXTENSIONS': ('.txt', '.htm', '.html', '.css', '.js', '.json'), + 'HIDE_UNTRANSLATED_POSTS': False, 'INDEX_DISPLAY_POST_COUNT': 10, 'INDEX_TEASERS': False, 'INDEXES_TITLE': "", @@ -114,6 +127,7 @@ class Nikola(object): 'LISTINGS_FOLDER': 'listings', 'MAX_IMAGE_SIZE': 1280, 'MATHJAX_CONFIG': '', + 'OLD_THEME_SUPPORT': True, 'OUTPUT_FOLDER': 'output', 'post_compilers': { "rest": ('.txt', '.rst'), @@ -136,6 +150,7 @@ class Nikola(object): 'SEARCH_FORM': '', 'SLUG_TAG_PATH': True, 'STORY_INDEX': False, + 'STRIP_INDEX_HTML': False, 'TAG_PATH': 'categories', 'TAG_PAGES_ARE_INDEXES': False, 'THEME': 'site', @@ -156,16 +171,19 @@ class Nikola(object): self.THEMES = utils.get_theme_chain(self.config['THEME']) self.MESSAGES = utils.load_messages(self.THEMES, - self.config['TRANSLATIONS']) + self.config['TRANSLATIONS'], + self.config['DEFAULT_LANG']) # SITE_URL is required, but if the deprecated BLOG_URL # is available, use it and warn if 'SITE_URL' not in self.config: if 'BLOG_URL' in self.config: print("WARNING: You should configure SITE_URL instead of BLOG_URL") - print("See docs at FIXME put URL") self.config['SITE_URL'] = self.config['BLOG_URL'] + self.default_lang = self.config['DEFAULT_LANG'] + self.translations = self.config['TRANSLATIONS'] + # BASE_URL defaults to SITE_URL if 'BASE_URL' not in self.config: self.config['BASE_URL'] = self.config.get('SITE_URL') @@ -187,23 +205,28 @@ class Nikola(object): self.commands = {} # Activate all command plugins - for pluginInfo in self.plugin_manager.getPluginsOfCategory("Command"): - if pluginInfo.name in self.config['DISABLED_PLUGINS']: - self.plugin_manager.removePluginFromCategory(pluginInfo, "Command") + for plugin_info in self.plugin_manager.getPluginsOfCategory("Command"): + if (plugin_info.name in self.config['DISABLED_PLUGINS'] + or (plugin_info.name in self.EXTRA_PLUGINS and + plugin_info.name not in self.config['ENABLED_EXTRAS'])): + self.plugin_manager.removePluginFromCategory(plugin_info, "Command") continue - self.plugin_manager.activatePluginByName(pluginInfo.name) - pluginInfo.plugin_object.set_site(self) - pluginInfo.plugin_object.short_help = pluginInfo.description - self.commands[pluginInfo.name] = pluginInfo.plugin_object + + self.plugin_manager.activatePluginByName(plugin_info.name) + plugin_info.plugin_object.set_site(self) + plugin_info.plugin_object.short_help = plugin_info.description + self.commands[plugin_info.name] = plugin_info.plugin_object # Activate all task plugins for task_type in ["Task", "LateTask"]: - for pluginInfo in self.plugin_manager.getPluginsOfCategory(task_type): - if pluginInfo.name in self.config['DISABLED_PLUGINS']: - self.plugin_manager.removePluginFromCategory(pluginInfo, task_type) + for plugin_info in self.plugin_manager.getPluginsOfCategory(task_type): + if (plugin_info.name in self.config['DISABLED_PLUGINS'] + or (plugin_info.name in self.EXTRA_PLUGINS and + plugin_info.name not in self.config['ENABLED_EXTRAS'])): + self.plugin_manager.removePluginFromCategory(plugin_info, task_type) continue - self.plugin_manager.activatePluginByName(pluginInfo.name) - pluginInfo.plugin_object.set_site(self) + self.plugin_manager.activatePluginByName(plugin_info.name) + plugin_info.plugin_object.set_site(self) # set global_context for template rendering self.GLOBAL_CONTEXT = { @@ -211,6 +234,7 @@ class Nikola(object): self.GLOBAL_CONTEXT['messages'] = self.MESSAGES self.GLOBAL_CONTEXT['_link'] = self.link + self.GLOBAL_CONTEXT['set_locale'] = s_l self.GLOBAL_CONTEXT['rel_link'] = self.rel_link self.GLOBAL_CONTEXT['abs_link'] = self.abs_link self.GLOBAL_CONTEXT['exists'] = self.file_exists @@ -244,9 +268,14 @@ class Nikola(object): 'CONTENT_FOOTER') self.GLOBAL_CONTEXT['rss_path'] = self.config.get('RSS_PATH') self.GLOBAL_CONTEXT['rss_link'] = self.config.get('RSS_LINK') - self.GLOBAL_CONTEXT['sidebar_links'] = self.config.get('SIDEBAR_LINKS') + + self.GLOBAL_CONTEXT['sidebar_links'] = utils.Functionary(list, self.config['DEFAULT_LANG']) + for k, v in self.config.get('SIDEBAR_LINKS', {}).items(): + self.GLOBAL_CONTEXT['sidebar_links'][k] = v + self.GLOBAL_CONTEXT['twitter_card'] = self.config.get( 'TWITTER_CARD', {}) + self.GLOBAL_CONTEXT['extra_head_data'] = self.config.get('EXTRA_HEAD_DATA') self.GLOBAL_CONTEXT.update(self.config.get('GLOBAL_CONTEXT', {})) @@ -273,14 +302,21 @@ class Nikola(object): self.template_system.set_directories(lookup_dirs, self.config['CACHE_FOLDER']) + # Check consistency of USE_CDN and the current THEME (Issue #386) + if self.config['USE_CDN']: + bootstrap_path = utils.get_asset_path(os.path.join( + 'assets', 'css', 'bootstrap.min.css'), self.THEMES) + if bootstrap_path.split(os.sep)[-4] != 'site': + warnings.warn('The USE_CDN option may be incompatible with your theme, because it uses a hosted version of bootstrap.') + # Load compiler plugins self.compilers = {} self.inverse_compilers = {} - for pluginInfo in self.plugin_manager.getPluginsOfCategory( + for plugin_info in self.plugin_manager.getPluginsOfCategory( "PageCompiler"): - self.compilers[pluginInfo.name] = \ - pluginInfo.plugin_object.compile_html + self.compilers[plugin_info.name] = \ + plugin_info.plugin_object.compile_html def get_compiler(self, source_name): """Get the correct compiler for a post from `conf.post_compilers` @@ -324,11 +360,9 @@ class Nikola(object): data = self.template_system.render_template( template_name, None, local_context) - assert isinstance(output_name, bytes) assert output_name.startswith( - self.config["OUTPUT_FOLDER"].encode('utf8')) - url_part = output_name.decode('utf8')[len(self.config["OUTPUT_FOLDER"]) - + 1:] + self.config["OUTPUT_FOLDER"]) + url_part = output_name[len(self.config["OUTPUT_FOLDER"]) + 1:] # Treat our site as if output/ is "/" and then make all URLs relative, # making the site "relocatable" @@ -392,7 +426,20 @@ class Nikola(object): with open(output_name, "wb+") as post_file: post_file.write(data) - def path(self, kind, name, lang, is_link=False): + def current_lang(self): # FIXME: this is duplicated, turn into a mixin + """Return the currently set locale, if it's one of the + available translations, or default_lang.""" + lang = utils.LocaleBorg().current_lang + if lang: + if lang in self.translations: + return lang + lang = lang.split('_')[0] + if lang in self.translations: + return lang + # whatever + return self.default_lang + + def path(self, kind, name, lang=None, is_link=False): """Build the path to a certain kind of page. kind is one of: @@ -417,6 +464,9 @@ class Nikola(object): (ex: "archive\\index.html") """ + if lang is None: + lang = self.current_lang() + path = [] if kind == "tag_index": @@ -465,7 +515,11 @@ class Nikola(object): path = [_f for _f in [self.config['LISTINGS_FOLDER'], name + '.html'] if _f] if is_link: - return '/' + ('/'.join(path)) + link = '/' + ('/'.join(path)) + if self.config['STRIP_INDEX_HTML'] and link.endswith('/index.html'): + return link[:-10] + else: + return link else: return os.path.join(*path) @@ -528,12 +582,14 @@ class Nikola(object): def add_gzipped_copies(task): if not self.config['GZIP_FILES']: return None + if task.get('name') is None: + return None gzip_task = { 'file_dep': [], 'targets': [], 'actions': [], 'basename': 'gzip', - 'name': task.get('name', 'unknown'), + 'name': task.get('name') + '.gz', 'clean': True, } targets = task.get('targets', []) @@ -597,7 +653,18 @@ class Nikola(object): dir_glob = os.path.join(dirpath, os.path.basename(wildcard)) dest_dir = os.path.normpath(os.path.join(destination, os.path.relpath(dirpath, dirname))) - for base_path in glob.glob(dir_glob): + full_list = glob.glob(dir_glob) + # Now let's look for things that are not in default_lang + for lang in self.config['TRANSLATIONS'].keys(): + lang_glob = dir_glob + "." + lang + translated_list = glob.glob(lang_glob) + for fname in translated_list: + orig_name = os.path.splitext(fname)[0] + if orig_name in full_list: + continue + full_list.append(orig_name) + + for base_path in full_list: post = Post( base_path, self.config['CACHE_FOLDER'], @@ -609,26 +676,32 @@ class Nikola(object): self.MESSAGES, template_name, self.config['FILE_METADATA_REGEXP'], + self.config['STRIP_INDEX_HTML'], tzinfo, + self.config['HIDE_UNTRANSLATED_POSTS'], ) for lang, langpath in list( self.config['TRANSLATIONS'].items()): dest = (destination, langpath, dir_glob, - post.pagenames[lang]) + post.meta[lang]['slug']) if dest in targets: raise Exception('Duplicated output path {0!r} ' 'in post {1!r}'.format( - post.pagenames[lang], + post.meta[lang]['slug'], base_path)) targets.add(dest) self.global_data[post.post_name] = post if post.use_in_feeds: self.posts_per_year[ str(post.date.year)].append(post.post_name) - for tag in post.tags: + self.posts_per_month[ + '{0}/{1:02d}'.format(post.date.year, post.date.month)].append(post.post_name) + for tag in post.alltags: self.posts_per_tag[tag].append(post.post_name) else: self.pages.append(post) + if self.config['OLD_THEME_SUPPORT']: + post._add_old_metadata() for name, post in list(self.global_data.items()): self.timeline.append(post) self.timeline.sort(key=lambda p: p.date) @@ -657,7 +730,7 @@ class Nikola(object): else: context['enable_comments'] = self.config['COMMENTS_IN_STORIES'] output_name = os.path.join(self.config['OUTPUT_FOLDER'], - post.destination_path(lang)).encode('utf8') + post.destination_path(lang)) deps_dict = copy(context) deps_dict.pop('post') if post.prev_post: @@ -668,9 +741,11 @@ class Nikola(object): deps_dict['TRANSLATIONS'] = self.config['TRANSLATIONS'] deps_dict['global'] = self.GLOBAL_CONTEXT deps_dict['comments'] = context['enable_comments'] + if post: + deps_dict['post_translations'] = post.translated_to task = { - 'name': output_name, + 'name': os.path.normpath(output_name), 'file_dep': deps, 'targets': [output_name], 'actions': [(self.render_template, [post.template_name, @@ -685,9 +760,6 @@ class Nikola(object): template_name, filters, extra_context): """Renders pages with lists of posts.""" - # This is a name on disk, has to be bytes - assert isinstance(output_name, bytes) - deps = self.template_system.template_deps(template_name) for post in posts: deps += post.deps(lang) @@ -700,11 +772,11 @@ class Nikola(object): context["nextlink"] = None context.update(extra_context) deps_context = copy(context) - deps_context["posts"] = [(p.titles[lang], p.permalink(lang)) for p in + deps_context["posts"] = [(p.meta[lang]['title'], p.permalink(lang)) for p in posts] deps_context["global"] = self.GLOBAL_CONTEXT task = { - 'name': output_name, + 'name': os.path.normpath(output_name), 'targets': [output_name], 'file_dep': deps, 'actions': [(self.render_template, [template_name, output_name, @@ -714,3 +786,14 @@ class Nikola(object): } return utils.apply_filters(task, filters) + + +def s_l(lang): + """A set_locale that uses utf8 encoding and returns ''.""" + utils.LocaleBorg().current_lang = lang + try: + locale.setlocale(locale.LC_ALL, (lang, "utf8")) + except Exception: + print("WARNING: could not set locale to {0}." + "This may cause some i18n features not to work.".format(lang)) + return '' diff --git a/nikola/plugin_categories.py b/nikola/plugin_categories.py index cff9b65..c4ca788 100644 --- a/nikola/plugin_categories.py +++ b/nikola/plugin_categories.py @@ -145,12 +145,19 @@ class PageCompiler(object): """Plugins that compile text files into HTML.""" name = "dummy compiler" + default_metadata = { + 'title': '', + 'slug': '', + 'date': '', + 'tags': '', + 'link': '', + 'description': '', + } def compile_html(self, source, dest): """Compile the source, save it on dest.""" raise NotImplementedError() - def create_post(self, path, onefile=False, title="", slug="", date="", - tags=""): + def create_post(self, path, onefile=False, **kw): """Create post file with optional metadata.""" raise NotImplementedError() diff --git a/nikola/plugins/command_check.py b/nikola/plugins/command_check.py index a396f63..ea82703 100644 --- a/nikola/plugins/command_check.py +++ b/nikola/plugins/command_check.py @@ -24,6 +24,7 @@ from __future__ import print_function import os +import sys try: from urllib import unquote from urlparse import urlparse @@ -74,14 +75,17 @@ class CommandCheck(Command): print(self.help()) return False if options['links']: - scan_links(options['find_sources']) + failure = scan_links(options['find_sources']) if options['files']: - scan_files() + failure = scan_files() + if failure: + sys.exit(1) existing_targets = set([]) def analize(task, find_sources=False): + rv = False try: filename = task.split(":")[-1] d = lxml.html.fromstring(open(filename).read()) @@ -100,6 +104,7 @@ def analize(task, find_sources=False): if os.path.exists(target_filename): existing_targets.add(target_filename) else: + rv = True print("Broken link in {0}: ".format(filename), target) if find_sources: print("Possible sources:") @@ -109,17 +114,21 @@ def analize(task, find_sources=False): except Exception as exc: print("Error with:", filename, exc) + return rv def scan_links(find_sources=False): print("Checking Links:\n===============\n") + failure = False for task in os.popen('nikola list --all', 'r').readlines(): task = task.strip() if task.split(':')[0] in ('render_tags', 'render_archive', 'render_galleries', 'render_indexes', - 'render_pages', + 'render_pages' 'render_site') and '.html' in task: - analize(task, find_sources) + if analize(task, find_sources): + failure = True + return failure def scan_files(): @@ -127,6 +136,7 @@ def scan_files(): task_fnames = set([]) real_fnames = set([]) # First check that all targets are generated in the right places + failure = False for task in os.popen('nikola list --all', 'r').readlines(): task = task.strip() if 'output' in task and ':' in task: @@ -144,6 +154,7 @@ def scan_files(): print("\nFiles from unknown origins:\n") for f in only_on_output: print(f) + failure = True only_on_input = list(task_fnames - real_fnames) if only_on_input: @@ -151,3 +162,5 @@ def scan_files(): print("\nFiles not generated:\n") for f in only_on_input: print(f) + + return failure diff --git a/nikola/plugins/command_console.py b/nikola/plugins/command_console.py index 4af759f..f4d0295 100644 --- a/nikola/plugins/command_console.py +++ b/nikola/plugins/command_console.py @@ -29,35 +29,77 @@ import os from nikola.plugin_categories import Command -class Deploy(Command): +class Console(Command): """Start debugging console.""" name = "console" + shells = ['ipython', 'bpython', 'plain'] + doc_purpose = "Start an interactive python console with access to your site and configuration." - def _execute(self, options, args): - """Start the console.""" + def ipython(self): + """IPython shell.""" from nikola import Nikola try: import conf + except ImportError: + print("No configuration found, cannot run the console.") + else: + import IPython SITE = Nikola(**conf.__dict__) SITE.scan_posts() - print("You can now access your configuration as conf and your " - "site engine as SITE.") + IPython.embed(header='Nikola Console (conf = configuration, SITE ' + '= site engine)') + + def bpython(self): + """bpython shell.""" + from nikola import Nikola + try: + import conf except ImportError: - print("No configuration found.") - import code + print("No configuration found, cannot run the console.") + else: + import bpython + SITE = Nikola(**conf.__dict__) + SITE.scan_posts() + gl = {'conf': conf, 'SITE': SITE, 'Nikola': Nikola} + bpython.embed(banner='Nikola Console (conf = configuration, SITE ' + '= site engine)', locals_=gl) + + def plain(self): + """Plain Python shell.""" + from nikola import Nikola try: - import readline + import conf + SITE = Nikola(**conf.__dict__) + SITE.scan_posts() + gl = {'conf': conf, 'SITE': SITE, 'Nikola': Nikola} except ImportError: - pass + print("No configuration found, cannot run the console.") else: - import rlcompleter - readline.set_completer(rlcompleter.Completer(globals()).complete) - readline.parse_and_bind("tab:complete") + import code + try: + import readline + except ImportError: + pass + else: + import rlcompleter + readline.set_completer(rlcompleter.Completer(gl).complete) + readline.parse_and_bind("tab:complete") + + pythonrc = os.environ.get("PYTHONSTARTUP") + if pythonrc and os.path.isfile(pythonrc): + try: + execfile(pythonrc) # NOQA + except NameError: + pass + + code.interact(local=gl, banner='Nikola Console (conf = ' + 'configuration, SITE = site engine)') - pythonrc = os.environ.get("PYTHONSTARTUP") - if pythonrc and os.path.isfile(pythonrc): + def _execute(self, options, args): + """Start the console.""" + for shell in self.shells: try: - execfile(pythonrc) # NOQA - except NameError: + return getattr(self, shell)() + except ImportError: pass - code.interact(local=globals()) + raise ImportError diff --git a/nikola/plugins/command_deploy.py b/nikola/plugins/command_deploy.py index ffa86ab..3277567 100644 --- a/nikola/plugins/command_deploy.py +++ b/nikola/plugins/command_deploy.py @@ -23,7 +23,12 @@ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. from __future__ import print_function +from ast import literal_eval +import codecs +from datetime import datetime import os +import subprocess + from nikola.plugin_categories import Command @@ -37,5 +42,24 @@ class Deploy(Command): def _execute(self, command, args): for command in self.site.config['DEPLOY_COMMANDS']: + + # Get last succesful deploy date + timestamp_path = os.path.join(self.site.config['CACHE_FOLDER'], 'lastdeploy') + try: + with open(timestamp_path, 'rb') as inf: + last_deploy = literal_eval(inf.read().strip()) + except Exception: + last_deploy = datetime(1970, 1, 1) # NOQA + print("==>", command) - os.system(command) + ret = subprocess.check_call(command, shell=True) + if ret != 0: # failed deployment + raise Exception("Failed deployment") + print("Successful deployment") + new_deploy = datetime.now() + # Store timestamp of successful deployment + with codecs.open(timestamp_path, 'wb+', 'utf8') as outf: + outf.write(repr(new_deploy)) + # Here is where we would do things with whatever is + # on self.site.timeline and is newer than + # last_deploy diff --git a/nikola/plugins/command_import_blogger.py b/nikola/plugins/command_import_blogger.py index 35a702e..ecc4676 100644 --- a/nikola/plugins/command_import_blogger.py +++ b/nikola/plugins/command_import_blogger.py @@ -73,7 +73,7 @@ class CommandImportBlogger(Command): ] def _execute(self, options, args): - """Import a Wordpress blog from an export file into a Nikola site.""" + """Import a Blogger blog from an export file into a Nikola site.""" # Parse the data if feedparser is None: @@ -126,7 +126,7 @@ class CommandImportBlogger(Command): def generate_base_site(self): if not os.path.exists(self.output_folder): - os.system('nikola init --empty ' + self.output_folder) + os.system('nikola init ' + self.output_folder) else: self.import_into_existing_site = True print('The folder {0} already exists - assuming that this is a ' @@ -176,9 +176,16 @@ class CommandImportBlogger(Command): @staticmethod def write_metadata(filename, title, slug, post_date, description, tags): + if not description: + description = "" + with codecs.open(filename, "w+", "utf8") as fd: - fd.write('\n'.join((title, slug, post_date, ','.join(tags), '', - description))) + fd.write('{0}\n'.format(title)) + fd.write('{0}\n'.format(slug)) + fd.write('{0}\n'.format(post_date)) + fd.write('{0}\n'.format(','.join(tags))) + fd.write('\n') + fd.write('{0}\n'.format(description)) def import_item(self, item, out_folder=None): """Takes an item from the feed and creates a post file.""" @@ -284,7 +291,7 @@ class CommandImportBlogger(Command): if not self.import_into_existing_site: filename = 'conf.py' else: - filename = 'conf.py.wordpress_import-{0}'.format( + filename = 'conf.py.blogger_import-{0}'.format( datetime.datetime.now().strftime('%Y%m%d_%H%M%s')) config_output_path = os.path.join(self.output_folder, filename) print('Configuration will be written to: ' + config_output_path) diff --git a/nikola/plugins/command_import_wordpress.py b/nikola/plugins/command_import_wordpress.py index e7ecca0..b45fe78 100644 --- a/nikola/plugins/command_import_wordpress.py +++ b/nikola/plugins/command_import_wordpress.py @@ -90,7 +90,6 @@ class CommandImportWordpress(Command): def _execute(self, options={}, args=[]): """Import a Wordpress blog from an export file into a Nikola site.""" # Parse the data - print(options, args) if requests is None: print('To use the import_wordpress command,' ' you have to install the "requests" package.') @@ -100,10 +99,16 @@ class CommandImportWordpress(Command): print(self.help()) return - options['filename'] = args[0] + options['filename'] = args.pop(0) - if len(args) > 1: - options['output_folder'] = args[1] + if args and ('output_folder' not in args or + options['output_folder'] == 'new_site'): + options['output_folder'] = args.pop(0) + + if args: + print('You specified additional arguments ({0}). Please consider ' + 'putting these arguments before the filename if you ' + 'are running into problems.'.format(args)) self.wordpress_export_file = options['filename'] self.squash_newlines = options.get('squash_newlines', False) @@ -204,8 +209,12 @@ class CommandImportWordpress(Command): 'PUT TITLE HERE') context['BLOG_DESCRIPTION'] = get_text_tag( channel, 'description', 'PUT DESCRIPTION HERE') - context['SITE_URL'] = get_text_tag(channel, 'link', '#') context['BASE_URL'] = get_text_tag(channel, 'link', '#') + if not context['BASE_URL']: + base_site_url = channel.find('{{{0}}}author'.format(wordpress_namespace)) + context['BASE_URL'] = get_text_tag(base_site_url, None, "http://foo.com") + context['SITE_URL'] = context['BASE_URL'] + author = channel.find('{{{0}}}author'.format(wordpress_namespace)) context['BLOG_EMAIL'] = get_text_tag( author, @@ -314,7 +323,13 @@ class CommandImportWordpress(Command): # link is something like http://foo.com/2012/09/01/hello-world/ # So, take the path, utils.slugify it, and that's our slug link = get_text_tag(item, 'link', None) - slug = utils.slugify(urlparse(link).path) + path = urlparse(link).path + + # In python 2, path is a str. slug requires a unicode + # object. Luckily, paths are also ASCII + if isinstance(path, utils.bytes_str): + path = path.decode('ASCII') + slug = utils.slugify(path) if not slug: # it happens if the post has no "nice" URL slug = get_text_tag( item, '{{{0}}}post_name'.format(wordpress_namespace), None) @@ -334,7 +349,10 @@ class CommandImportWordpress(Command): item, '{http://purl.org/rss/1.0/modules/content/}encoded', '') tags = [] - if status != 'publish': + if status == 'trash': + print('Trashed post "{0}" will not be imported.'.format(title)) + return + elif status != 'publish': tags.append('draft') is_draft = True else: diff --git a/nikola/plugins/command_install_theme.py b/nikola/plugins/command_install_theme.py index 04a2cce..2a0a0cc 100644 --- a/nikola/plugins/command_install_theme.py +++ b/nikola/plugins/command_install_theme.py @@ -64,6 +64,10 @@ class CommandInstallTheme(Command): def _execute(self, options, args): """Install theme into current site.""" + if requests is None: + print('This command requires the requests package be installed.') + return False + listing = options['list'] url = options['url'] if args: diff --git a/nikola/plugins/command_new_post.py b/nikola/plugins/command_new_post.py index a823da3..933a51a 100644 --- a/nikola/plugins/command_new_post.py +++ b/nikola/plugins/command_new_post.py @@ -49,13 +49,31 @@ def filter_post_pages(compiler, is_post, post_compilers, post_pages): if not filtered: type_name = "post" if is_post else "page" - raise Exception("Can't find a way, using your configuration, to create" + raise Exception("Can't find a way, using your configuration, to create " "a {0} in format {1}. You may want to tweak " "post_compilers or post_pages in conf.py".format( type_name, compiler)) return filtered[0] +def get_default_compiler(is_post, post_compilers, post_pages): + """Given post_compilers and post_pages, return a reasonable + default compiler for this kind of post/page. + """ + + # First throw away all the post_pages with the wrong is_post + filtered = [entry for entry in post_pages if entry[3] == is_post] + + # Get extensions in filtered post_pages until one matches a compiler + for entry in filtered: + extension = os.path.splitext(entry[0])[-1] + for compiler, extensions in post_compilers.items(): + if extension in extensions: + return compiler + # No idea, back to default behaviour + return 'rest' + + class CommandNewPost(Command): """Create a new post.""" @@ -105,7 +123,7 @@ class CommandNewPost(Command): 'short': 'f', 'long': 'format', 'type': str, - 'default': 'rest', + 'default': '', 'help': 'Markup format for post, one of rest, markdown, wiki, ' 'bbcode, html, textile, txt2tags', } @@ -140,6 +158,12 @@ class CommandNewPost(Command): post_format = options['post_format'] + if not post_format: # Issue #400 + post_format = get_default_compiler( + is_post, + self.site.config['post_compilers'], + self.site.config['post_pages']) + if post_format not in compiler_names: print("ERROR: Unknown post format " + post_format) return @@ -160,12 +184,14 @@ class CommandNewPost(Command): title = sys.stdin.readline() else: print("Title:", title) - if isinstance(title, bytes): + if isinstance(title, utils.bytes_str): title = title.decode(sys.stdin.encoding) title = title.strip() if not path: slug = utils.slugify(title) else: + if isinstance(path, utils.bytes_str): + path = path.decode(sys.stdin.encoding) slug = utils.slugify(os.path.splitext(os.path.basename(path))[0]) date = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S') data = [title, slug, date, tags] @@ -186,7 +212,9 @@ class CommandNewPost(Command): d_name = os.path.dirname(txt_path) if not os.path.exists(d_name): os.makedirs(d_name) - compiler_plugin.create_post(txt_path, onefile, title, slug, date, tags) + compiler_plugin.create_post( + txt_path, onefile, title=title, + slug=slug, date=date, tags=tags) if not onefile: # write metadata file with codecs.open(meta_path, "wb+", "utf8") as fd: diff --git a/nikola/plugins/command_planetoid.plugin b/nikola/plugins/command_planetoid.plugin new file mode 100644 index 0000000..8636d49 --- /dev/null +++ b/nikola/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/nikola/plugins/command_planetoid/__init__.py b/nikola/plugins/command_planetoid/__init__.py new file mode 100644 index 0000000..183dd51 --- /dev/null +++ b/nikola/plugins/command_planetoid/__init__.py @@ -0,0 +1,287 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function, unicode_literals +import codecs +import datetime +import hashlib +from optparse import OptionParser +import os +import sys + +from doit.tools import timeout +from nikola.plugin_categories import Command, Task +from nikola.utils import config_changed + +try: + import feedparser +except ImportError: + feedparser = None # NOQA + +try: + import peewee +except ImportError: + peewee = None + + +if peewee is not None: + 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): + if peewee is None or sys.version_info[0] == 3: + if sys.version_info[0] == 3: + message = 'Peewee is currently incompatible with Python 3.' + else: + message = 'You need to install the \"peewee\" module.' + + yield { + 'basename': self.name, + 'name': '', + 'verbosity': 2, + 'actions': ['echo "%s"' % message] + } + else: + self.init_db() + self.load_feeds() + for task in self.task_update_feeds(): + yield task + for task in self.task_generate_posts(): + yield task + yield { + 'basename': self.name, + 'name': '', + 'actions': [], + 'file_dep': ['feeds'], + 'task_dep': [ + self.name + "_fetch_feed", + self.name + "_generate_posts", + ] + } + + def run(self, *args): + parser = OptionParser(usage="nikola %s [options]" % self.name) + (options, args) = parser.parse_args(list(args)) + + def 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('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): + add_feed(name, feed) + elif list(f)[0].url != feed: + 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() + flag = False + for feed in Feed.select(): + flag = True + task = { + 'basename': self.name + "_fetch_feed", + 'name': str(feed.url), + 'actions': [(update_feed, (feed, ))], + 'uptodate': [timeout(datetime.timedelta(minutes= + self.site.config.get('PLANETOID_REFRESH', 60)))], + } + yield task + if not flag: + yield { + 'basename': self.name + "_fetch_feed", + 'name': '', + 'actions': [], + } + + 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('%s\n' % entry.title.replace('\n', ' ')) + fd.write('%s\n' % unique_id) + fd.write('%s\n' % entry.date.strftime('%Y/%m/%d %H:%M')) + fd.write('\n') + fd.write('%s\n' % entry.link) + with codecs.open(post_path, 'wb+', 'utf8') as fd: + fd.write('.. raw:: html\n\n') + content = entry.content + if not content: + content = 'Sin contenido' + for line in content.splitlines(): + fd.write(' %s\n' % line) + + if not os.path.isdir('posts'): + os.mkdir('posts') + flag = False + for entry in Entry.select().order_by(Entry.date.desc()): + flag = True + entry_id = gen_id(entry) + yield { + 'basename': self.name + "_generate_posts", + '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})], + 'task_dep': [self.name + "_fetch_feed"], + } + if not flag: + yield { + 'basename': self.name + "_generate_posts", + 'name': '', + 'actions': [], + } diff --git a/nikola/plugins/compile_bbcode.py b/nikola/plugins/compile_bbcode.py index 26de727..f8022f3 100644 --- a/nikola/plugins/compile_bbcode.py +++ b/nikola/plugins/compile_bbcode.py @@ -60,19 +60,17 @@ class CompileTextile(PageCompiler): output = self.parser.format(data) out_file.write(output) - def create_post(self, path, onefile=False, title="", slug="", date="", - tags=""): + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) d_name = os.path.dirname(path) if not os.path.isdir(d_name): os.makedirs(os.path.dirname(path)) with codecs.open(path, "wb+", "utf8") as fd: if onefile: fd.write('[note][/note]\n\n') - fd.write("\nWrite your post here.") + fd.write("Write your post here.") diff --git a/nikola/plugins/compile_html.py b/nikola/plugins/compile_html.py index 6c1c381..7551b33 100644 --- a/nikola/plugins/compile_html.py +++ b/nikola/plugins/compile_html.py @@ -43,19 +43,17 @@ class CompileHtml(PageCompiler): pass shutil.copyfile(source, dest) - def create_post(self, path, onefile=False, title="", slug="", - date="", tags=""): + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) d_name = os.path.dirname(path) if not os.path.isdir(d_name): os.makedirs(os.path.dirname(path)) with codecs.open(path, "wb+", "utf8") as fd: if onefile: fd.write('\n\n') fd.write("\n

    Write your post here.

    ") diff --git a/nikola/plugins/compile_ipynb.plugin b/nikola/plugins/compile_ipynb.plugin new file mode 100644 index 0000000..51051e0 --- /dev/null +++ b/nikola/plugins/compile_ipynb.plugin @@ -0,0 +1,10 @@ +[Core] +Name = ipynb +Module = compile_ipynb + +[Documentation] +Author = Damián Avila +Version = 0.1 +Website = http://www.oquanta.info +Description = Compile IPython notebooks into HTML + diff --git a/nikola/plugins/compile_ipynb/README.txt b/nikola/plugins/compile_ipynb/README.txt new file mode 100644 index 0000000..2cfd45e --- /dev/null +++ b/nikola/plugins/compile_ipynb/README.txt @@ -0,0 +1,35 @@ +To make this work... + +1- First, you have to put this plugin in your_site/plugins/ folder. + +2- Then, you have to download the custom nbconvert from here: https://github.com/damianavila/compile_ipynb-for-Nikola.git +and put it inside your_site/plugins/compile_ipynb/ folder + +3- Also, you have to use the site-ipython theme (or make a new one containing the ipython css, mathjax.js and the proper template). +You can get it here: https://github.com/damianavila/site-ipython-theme-for-Nikola + +4- Finally, you have to put: + +post_pages = ( + ("posts/*.ipynb", "posts", "post.tmpl", True), + ("stories/*.ipynb", "stories", "story.tmpl", False), +) + +in your conf.py + +Then... to use it: + +$nikola new_page -f ipynb + +**NOTE**: Just IGNORE the "-1" and "-2" options in nikola new_page command, by default this compiler +create one metadata file and the corresponding naive IPython notebook. + +$nikola build + +And deploy the output folder... to see it locally: $nikola serve + +If you have any doubts, just ask: @damianavila + +Cheers. + +Damián diff --git a/nikola/plugins/compile_ipynb/__init__.py b/nikola/plugins/compile_ipynb/__init__.py new file mode 100644 index 0000000..d38f6f2 --- /dev/null +++ b/nikola/plugins/compile_ipynb/__init__.py @@ -0,0 +1,100 @@ +# Copyright (c) 2013 Damian Avila. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +"""Implementation of compile_html based on nbconvert.""" + +from __future__ import unicode_literals, print_function +import codecs +import os + +try: + from .nbformat import current as nbformat + from .nbconvert.converters import bloggerhtml as nbconverter + bloggerhtml = True +except ImportError: + bloggerhtml = None + +from nikola.plugin_categories import PageCompiler + + +class CompileIPynb(PageCompiler): + """Compile IPynb into HTML.""" + + name = "ipynb" + + def compile_html(self, source, dest): + if bloggerhtml is None: + raise Exception('To build this site, you also need ' + 'https://github.com/damianavila/com' + 'pile_ipynb-for-Nikola.git.') + try: + os.makedirs(os.path.dirname(dest)) + except: + pass + converter = nbconverter.ConverterBloggerHTML() + with codecs.open(dest, "w+", "utf8") as out_file: + with codecs.open(source, "r", "utf8") as in_file: + data = in_file.read() + converter.nb = nbformat.reads_json(data) + output = converter.convert() + out_file.write(output) + + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + d_name = os.path.dirname(path) + if not os.path.isdir(d_name): + os.makedirs(os.path.dirname(path)) + meta_path = os.path.join(d_name, kw['slug'] + ".meta") + with codecs.open(meta_path, "wb+", "utf8") as fd: + if onefile: + fd.write('%s\n' % kw['title']) + fd.write('%s\n' % kw['slug']) + fd.write('%s\n' % kw['date']) + fd.write('%s\n' % kw['tags']) + print("Your post's metadata is at: ", meta_path) + with codecs.open(path, "wb+", "utf8") as fd: + fd.write("""{ + "metadata": { + "name": "%s" + }, + "nbformat": 3, + "nbformat_minor": 0, + "worksheets": [ + { + "cells": [ + { + "cell_type": "code", + "collapsed": false, + "input": [], + "language": "python", + "metadata": {}, + "outputs": [] + } + ], + "metadata": {} + } + ] +}""" % kw['slug']) diff --git a/nikola/plugins/compile_markdown/__init__.py b/nikola/plugins/compile_markdown/__init__.py index 7aa03a9..ae700e6 100644 --- a/nikola/plugins/compile_markdown/__init__.py +++ b/nikola/plugins/compile_markdown/__init__.py @@ -24,14 +24,28 @@ """Implementation of compile_html based on markdown.""" +from __future__ import unicode_literals + import codecs import os -import re try: from markdown import markdown + + from nikola.plugins.compile_markdown.mdx_nikola import NikolaExtension + nikola_extension = NikolaExtension() + + from nikola.plugins.compile_markdown.mdx_gist import GistExtension + gist_extension = GistExtension() + + from nikola.plugins.compile_markdown.mdx_podcast import PodcastExtension + podcast_extension = PodcastExtension() + except ImportError: markdown = None # NOQA + nikola_extension = None + gist_extension = None + podcast_extension = None from nikola.plugin_categories import PageCompiler @@ -41,6 +55,9 @@ class CompileMarkdown(PageCompiler): name = "markdown" + extensions = ['fenced_code', 'codehilite', gist_extension, + nikola_extension, podcast_extension] + def compile_html(self, source, dest): if markdown is None: raise Exception('To build this site, you need to install the ' @@ -52,30 +69,20 @@ class CompileMarkdown(PageCompiler): with codecs.open(dest, "w+", "utf8") as out_file: with codecs.open(source, "r", "utf8") as in_file: data = in_file.read() - output = markdown(data, ['fenced_code', 'codehilite']) - # h1 is reserved for the title so increment all header levels - for n in reversed(range(1, 9)): - output = re.sub(''.format(n), ''.format(n + 1), - output) - output = re.sub(''.format(n), ''.format(n + 1), - output) - # python-markdown's highlighter uses the class 'codehilite' to wrap - # code, # instead of the standard 'code'. None of the standard - # pygments stylesheets use this class, so swap it to be 'code' - output = re.sub(r'(]+class="[^"]*)codehilite([^>]+)', - r'\1code\2', output) + output = markdown(data, self.extensions) out_file.write(output) - def create_post(self, path, onefile=False, title="", slug="", date="", - tags=""): + def create_post(self, path, onefile=False, **kw): + metadata = {} + metadata.update(self.default_metadata) + metadata.update(kw) + d_name = os.path.dirname(path) + if not os.path.isdir(d_name): + os.makedirs(os.path.dirname(path)) with codecs.open(path, "wb+", "utf8") as fd: if onefile: fd.write('\n\n') - fd.write("\nWrite your post here.") + fd.write("Write your post here.") diff --git a/nikola/plugins/compile_markdown/mdx_gist.py b/nikola/plugins/compile_markdown/mdx_gist.py new file mode 100644 index 0000000..808e383 --- /dev/null +++ b/nikola/plugins/compile_markdown/mdx_gist.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2013 Michael Rabbitt. +# +# 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. +# +# Inspired by "[Python] reStructuredText GitHub Gist directive" +# (https://gist.github.com/brianhsu/1407759), public domain by Brian Hsu + +from __future__ import print_function + + +''' +Extension to Python Markdown for Embedded Gists (gist.github.com) + +Basic Example: + + >>> import markdown + >>> text = """ + ... Text of the gist: + ... [:gist: 4747847] + ... """ + >>> html = markdown.markdown(text, [GistExtension()]) + >>> print(html) +

    Text of the gist: +

    + + +
    +

    + +Example with filename: + + >>> import markdown + >>> text = """ + ... Text of the gist: + ... [:gist: 4747847 zen.py] + ... """ + >>> html = markdown.markdown(text, [GistExtension()]) + >>> print(html) +

    Text of the gist: +

    + + +
    +

    + +Example using reStructuredText syntax: + + >>> import markdown + >>> text = """ + ... Text of the gist: + ... .. gist:: 4747847 zen.py + ... """ + >>> html = markdown.markdown(text, [GistExtension()]) + >>> print(html) +

    Text of the gist: +

    + + +
    +

    +''' +from __future__ import unicode_literals +import warnings +from markdown.extensions import Extension +from markdown.inlinepatterns import Pattern +from markdown.util import AtomicString +from markdown.util import etree + +try: + import requests +except ImportError: + requests = None # NOQA + +GIST_JS_URL = "https://gist.github.com/{0}.js" +GIST_FILE_JS_URL = "https://gist.github.com/{0}.js?file={1}" +GIST_RAW_URL = "https://raw.github.com/gist/{0}" +GIST_FILE_RAW_URL = "https://raw.github.com/gist/{0}/{1}" + +GIST_MD_RE = r'\[:gist:\s*(?P\d+)(?:\s*(?P.+?))?\]' +GIST_RST_RE = r'(?m)^\.\.\s*gist::\s*(?P\d+)(?:\s*(?P.+))\s*$' + + +class GistPattern(Pattern): + """ InlinePattern for footnote markers in a document's body text. """ + + def __init__(self, pattern, configs): + Pattern.__init__(self, pattern) + + def get_raw_gist_with_filename(self, gist_id, filename): + url = GIST_FILE_RAW_URL.format(gist_id, filename) + return requests.get(url).text + + def get_raw_gist(self, gist_id): + url = GIST_RAW_URL.format(gist_id) + return requests.get(url).text + + def handleMatch(self, m): + gist_id = m.group('gist_id') + gist_file = m.group('filename') + + gist_elem = etree.Element('div') + gist_elem.set('class', 'gist') + script_elem = etree.SubElement(gist_elem, 'script') + + if gist_file: + script_elem.set('src', GIST_FILE_JS_URL.format( + gist_id, gist_file)) + + else: + script_elem.set('src', GIST_JS_URL.format( + gist_id)) + + if requests: + if gist_file: + raw_gist = (self.get_raw_gist_with_filename( + gist_id, gist_file)) + script_elem.set('src', GIST_FILE_JS_URL.format( + gist_id, gist_file)) + + else: + raw_gist = (self.get_raw_gist(gist_id)) + script_elem.set('src', GIST_JS_URL.format( + gist_id)) + + # Insert source as
     within