aboutsummaryrefslogtreecommitdiff
path: root/themes
diff options
context:
space:
mode:
Diffstat (limited to 'themes')
-rw-r--r--themes/classic/_plugins/blockquote.rb109
-rw-r--r--themes/classic/_plugins/category.rb65
-rw-r--r--themes/classic/_plugins/compass_compiler.rb1
-rw-r--r--themes/classic/_plugins/custom_filters.rb59
-rw-r--r--themes/classic/_plugins/generate_sitemap.rb133
-rw-r--r--themes/classic/_plugins/gist_tag.rb83
-rw-r--r--themes/classic/_plugins/haml.rb24
-rw-r--r--themes/classic/_plugins/iterator.rb49
-rw-r--r--themes/classic/_plugins/pygments_cache_patch.rb30
-rw-r--r--themes/classic/_plugins/sitemap_generator.rb309
-rw-r--r--themes/classic/_plugins/titlecase.rb36
11 files changed, 898 insertions, 0 deletions
diff --git a/themes/classic/_plugins/blockquote.rb b/themes/classic/_plugins/blockquote.rb
new file mode 100644
index 00000000..7a885175
--- /dev/null
+++ b/themes/classic/_plugins/blockquote.rb
@@ -0,0 +1,109 @@
+#
+# Author: Josediaz Gonzalez - https://github.com/josegonzalez
+# Source URL: https://github.com/josegonzalez/josediazgonzalez.com/blob/master/_plugins/blockquote.rb
+# Modified by Brandon Mathis
+#
+require './_plugins/titlecase.rb'
+module Jekyll
+
+ # Outputs a string with a given attribution as a quote
+ #
+ # {% blockquote John Paul Jones %}
+ # Monkeys!
+ # {% endblockquote %}
+ # ...
+ # <blockquote>
+ # Monkeys!
+ # <br />
+ # John Paul Jones
+ # </blockquote>
+ #
+ class Blockquote < Liquid::Block
+ FullCiteWithTitle = /([\w\s]+)(https?:\/\/)(\S+\s)([\w\s]+)/i
+ FullCite = /([\w\s]+)(https?:\/\/)(\S+)/i
+ Author = /([\w\s]+)/
+
+ def initialize(tag_name, markup, tokens)
+ @by = nil
+ @source = nil
+ @title = nil
+ if markup =~ FullCiteWithTitle
+ @by = $1
+ @source = $2 + $3
+ @title = $4.titlecase
+ elsif markup =~ FullCite
+ @by = $1
+ @source = $2 + $3
+ elsif markup =~ Author
+ @by = $1
+ end
+ super
+ end
+
+ def render(context)
+ output = super
+ if @by.nil?
+ '<blockquote><p>' + output.join + '</p></blockquote>'
+ elsif !@title.nil?
+ '<blockquote><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + '<a class="source" href="' + @source + '">' + @title + '</a></cite></p>'
+ elsif !@source.nil?
+ '<blockquote><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + '<a class="source" href="' + @source + '">source</a></cite></p>'
+ else
+ '<blockquote><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong></cite></p>'
+ end
+ end
+ end
+
+ # Outputs a string with a given attribution as a pullquote
+ #
+ # {% blockquote John Paul Jones %}
+ # Monkeys!
+ # {% endblockquote %}
+ # ...
+ # <blockquote class="pullquote">
+ # Monkeys!
+ # <br />
+ # John Paul Jones
+ # </blockquote>
+ #
+ class Pullquote < Liquid::Block
+ FullCiteWithTitle = /([\w\s]+)(http:\/\/|https:\/\/)(\S+)([\w\s]+)/i
+ FullCite = /([\w\s]+)(http:\/\/|https:\/\/)(\S+)/i
+ Author = /([\w\s]+)/
+
+ def initialize(tag_name, markup, tokens)
+ @by = nil
+ @source = nil
+ @title = nil
+ if markup =~ FullCiteWithTitle
+ @by = $1
+ @source = $2 + $3
+ @title = $4
+ elsif markup =~ FullCite
+ @by = $1
+ @source = $2 + $3
+ elsif markup =~ Author
+ @by = $1
+ end
+ super
+ end
+
+ def render(context)
+ output = super
+ if @by.nil?
+ '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>'
+ elsif @title
+ '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + ' <a class="source" href="' + @source + '">' + @title + '</a></cite></p>'
+ elsif @source
+ '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong>' + ' <a class="source" href="' + @source + '">source</a></cite></p>'
+ elsif @by
+ '<blockquote class="pullquote"><p>' + output.join + '</p></blockquote>' + '<p><cite><strong>' + @by + '</strong></cite></p>'
+ end
+ end
+ end
+end
+
+Liquid::Template.register_tag('blockquote', Jekyll::Blockquote)
+Liquid::Template.register_tag('pullquote', Jekyll::Pullquote)
+
+
diff --git a/themes/classic/_plugins/category.rb b/themes/classic/_plugins/category.rb
new file mode 100644
index 00000000..b9accdec
--- /dev/null
+++ b/themes/classic/_plugins/category.rb
@@ -0,0 +1,65 @@
+module Jekyll
+
+ class CategoryIndex < Page
+ def initialize(site, base, dir, category)
+ @site = site
+ @base = base
+ @dir = dir
+ @name = 'index.html'
+
+ self.process(@name)
+ self.read_yaml(File.join(base, '_layouts'), 'category_index.html')
+ self.data['category'] = category
+
+ category_title_prefix = site.config['category_title_prefix'] || 'Category: '
+ self.data['title'] = "#{category_title_prefix}#{category}"
+ end
+ end
+
+ class CategoryList < Page
+ def initialize(site, base, dir, categories)
+ @site = site
+ @base = base
+ @dir = dir
+ @name = 'index.html'
+
+ self.process(@name)
+ self.read_yaml(File.join(base, '_layouts'), 'category_list.html')
+ self.data['categories'] = categories
+ end
+ end
+
+ class CategoryGenerator < Generator
+ safe true
+
+ def generate(site)
+ if site.layouts.key? 'category_index'
+ dir = site.config['category_dir'] || 'categories'
+ site.categories.keys.each do |category|
+ write_category_index(site, File.join(dir, category.gsub(/\s/, "-").gsub(/[^\w-]/, '').downcase), category)
+ end
+ end
+
+ if site.layouts.key? 'category_list'
+ dir = site.config['category_dir'] || 'categories'
+ write_category_list(site, dir, site.categories.keys.sort)
+ end
+ end
+
+ def write_category_index(site, dir, category)
+ index = CategoryIndex.new(site, site.source, dir, category)
+ index.render(site.layouts, site.site_payload)
+ index.write(site.dest)
+ site.static_files << index
+ end
+
+ def write_category_list(site, dir, categories)
+ index = CategoryList.new(site, site.source, dir, categories)
+ index.render(site.layouts, site.site_payload)
+ index.write(site.dest)
+ site.static_files << index
+ end
+ end
+
+end
+
diff --git a/themes/classic/_plugins/compass_compiler.rb b/themes/classic/_plugins/compass_compiler.rb
new file mode 100644
index 00000000..dcec746a
--- /dev/null
+++ b/themes/classic/_plugins/compass_compiler.rb
@@ -0,0 +1 @@
+system "compass compile --css-dir source/stylesheets"
diff --git a/themes/classic/_plugins/custom_filters.rb b/themes/classic/_plugins/custom_filters.rb
new file mode 100644
index 00000000..158586af
--- /dev/null
+++ b/themes/classic/_plugins/custom_filters.rb
@@ -0,0 +1,59 @@
+#custom filters for Octopress
+
+module OctopressFilters
+ def exerpt(input, url, url_text="Reade more&hellip;", permalink_text=false)
+ if input.index(/<!--\s?more\s?-->/i)
+ input.split(/<!--\s?more\s?-->/i)[0] + "<p><a href='#{url}'>#{url_text}</a></p>"
+ elsif permalink_text
+ input + "<p><a href='#{url}'>#{permalink_text}</a></p>"
+ else
+ input
+ end
+ end
+ def full_urls(input, url='')
+ input.gsub /(\s+(href|src)\s*=\s*["|']{1})(\/[^\"'>]+)/ do
+ $1+url+$3
+ end
+ end
+ def search_url(input)
+ input.gsub /(http:\/\/)(\S+)/ do
+ $2
+ end
+ end
+ def smart_quotes(input)
+ require 'rubypants'
+ RubyPants.new(input).to_html
+ end
+ def titlecase(input)
+ input.titlecase
+ end
+ def datetime(date)
+ if date.class == String
+ date = Time.parse(date)
+ end
+ date
+ end
+ def ordinalize(date)
+ date = datetime(date)
+ "#{date.strftime('%B')} #{ordinal(date.strftime('%e').to_i)}, #{date.strftime('%Y')}"
+ end
+ def ordinal(number)
+ if (11..13).include?(number.to_i % 100)
+ "#{number}<span>th</span>"
+ else
+ case number.to_i % 10
+ when 1; "#{number}<span>st</span>"
+ when 2; "#{number}<span>nd<span>"
+ when 3; "#{number}<span>rd</span>"
+ else "#{number}<span>th</span>"
+ end
+ end
+ end
+ #YearlyPost = Struct.new('YearlyPost', :year, :posts)
+ def yearly_posts(site)
+ #site.posts.reverse.group_by { |p| p.date.strftime("%Y") }.map { |k,v| YearlyPost.new(k,v) }
+ site
+ end
+end
+Liquid::Template.register_filter OctopressFilters
+
diff --git a/themes/classic/_plugins/generate_sitemap.rb b/themes/classic/_plugins/generate_sitemap.rb
new file mode 100644
index 00000000..4d580c47
--- /dev/null
+++ b/themes/classic/_plugins/generate_sitemap.rb
@@ -0,0 +1,133 @@
+# Jekyll sitemap page generator.
+# http://recursive-design.com/projects/jekyll-plugins/
+#
+# Version: 0.1.3 (201101061053)
+#
+# Copyright (c) 2010 Dave Perrett, http://recursive-design.com/
+# Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
+#
+# A generator that creates a sitemap.xml page for jekyll sites, suitable for submission to
+# google etc.
+#
+# To use it, simply drop this script into the _plugins directory of your Jekyll site.
+#
+# When you compile your jekyll site, this plugin will loop through the list of pages in your
+# site, and generate an entry in sitemap.xml for each one.
+
+require 'pathname'
+
+module Jekyll
+
+
+ # Monkey-patch an accessor for a page's containing folder, since
+ # we need it to generate the sitemap.
+ class Page
+ def subfolder
+ @dir
+ end
+ end
+
+
+ # Sub-class Jekyll::StaticFile to allow recovery from unimportant exception
+ # when writing the sitemap file.
+ class StaticSitemapFile < StaticFile
+ def write(dest)
+ super(dest) rescue ArgumentError
+ true
+ end
+ end
+
+
+ # Generates a sitemap.xml file containing URLs of all pages and posts.
+ class SitemapGenerator < Generator
+ safe true
+ priority :low
+
+ # Domain that you are generating the sitemap for - update this to match your site.
+
+ # Generates the sitemap.xml file.
+ #
+ # +site+ is the global Site object.
+ def generate(site)
+ # Create the destination folder if necessary.
+ site_folder = site.config['destination']
+ unless File.directory?(site_folder)
+ p = Pathname.new(site_folder)
+ p.mkdir
+ end
+
+ # Write the contents of sitemap.xml.
+ File.open(File.join(site_folder, 'sitemap.xml'), 'w') do |f|
+ f.write(generate_header())
+ f.write(generate_content(site))
+ f.write(generate_footer())
+ f.close
+ end
+
+ # Add a static file entry for the zip file, otherwise Site::cleanup will remove it.
+ site.static_files << Jekyll::StaticSitemapFile.new(site, site.dest, '/', 'sitemap.xml')
+ end
+
+ private
+
+ # Returns the XML header.
+ def generate_header
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">"
+ end
+
+ # Returns a string containing the the XML entries.
+ #
+ # +site+ is the global Site object.
+ def generate_content(site)
+ result = ''
+
+ base_url = site.config['url']
+
+ # First, try to find any stand-alone pages.
+ site.pages.each{ |page|
+ path = page.subfolder + '/' + page.name
+ mod_date = File.mtime(site.source + path)
+
+ # Remove the trailing 'index.html' if there is one, and just output the folder name.
+ if path=~/index.html$/
+ path = path[0..-11]
+ end
+
+ unless path =~/error/
+ result += entry(base_url, path, mod_date)
+ end
+ }
+
+ # Next, find all the posts.
+ posts = site.site_payload['site']['posts']
+ for post in posts do
+ result += entry(base_url, post.id, post.date)
+ end
+
+ result
+ end
+
+ # Returns the XML footer.
+ def generate_footer
+ "\n</urlset>"
+ end
+
+ # Creates an XML entry from the given path and date.
+ #
+ # +path+ is the URL path to the page.
+ # +date+ is the date the file was modified (in the case of regular pages), or published (for blog posts).
+ def entry(base_url, path, date)
+ # Force extensions to .html from markdown, textile.
+ path = path.gsub(/\.(markdown|textile)$/i, '.html')
+ "
+ <url>
+ <loc>#{base_url}#{path}</loc>
+ <lastmod>#{date.strftime("%Y-%m-%d")}</lastmod>
+ </url>"
+ end
+
+ end
+
+end
+
+
diff --git a/themes/classic/_plugins/gist_tag.rb b/themes/classic/_plugins/gist_tag.rb
new file mode 100644
index 00000000..1f37416e
--- /dev/null
+++ b/themes/classic/_plugins/gist_tag.rb
@@ -0,0 +1,83 @@
+# Nicked from Brandon Tilly
+# Gist https://gist.github.com/803483
+# Post http://brandontilley.com/2011/01/31/gist-tag-for-jekyll.html
+#
+# Example usage: {% gist 803483 gist_tag.rb %} //embeds a gist for this plugin
+
+require 'digest/md5'
+require 'net/https'
+require 'uri'
+
+module Jekyll
+ class GistTag < Liquid::Tag
+ def initialize(tag_name, text, token)
+ super
+ system('mkdir -p .gist_cache')
+ @text = text
+ @cache = true
+ @cache_folder = File.expand_path "../.gist_cache", File.dirname(__FILE__)
+ end
+
+ def render(context)
+ return "" unless @text =~ /([\d]*) (.*)/
+
+ gist, file = $1.strip, $2.strip
+ script_url = "https://gist.github.com/#{gist}.js?file=#{file}"
+
+ code = get_cached_gist(gist, file) || get_gist_from_web(gist, file)
+ code = code.gsub "<", "&lt;"
+ string = "<script src='#{script_url}'></script>"
+ string += "<noscript><pre><code>#{code}</code></pre></noscript>"
+ return string
+ end
+
+ def get_gist_url_for(gist, file)
+ "https://gist.github.com/raw/#{gist}/#{file}"
+ end
+
+ def cache_gist(gist, file, data)
+ file = get_cache_file_for gist, file
+ File.open(file, "w+") do |f|
+ f.write(data)
+ end
+ end
+
+ def get_cached_gist(gist, file)
+ return nil if @cache == false
+ file = get_cache_file_for gist, file
+ return nil unless File.exist?(file)
+ return File.new(file).readlines.join
+ end
+
+ def get_cache_file_for(gist, file)
+ gist.gsub! /[^a-zA-Z0-9\-_\.]/, ''
+ file.gsub! /[^a-zA-Z0-9\-_\.]/, ''
+ md5 = Digest::MD5.hexdigest "#{gist}-#{file}"
+ File.join @cache_folder, "#{gist}-#{file}-#{md5}.cache"
+ end
+
+ def get_gist_from_web(gist, file)
+ gist_url = get_gist_url_for(gist, file)
+ raw_uri = URI.parse(gist_url)
+ https = Net::HTTP.new(raw_uri.host, raw_uri.port)
+ https.use_ssl = true
+ https.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ request = Net::HTTP::Get.new(raw_uri.request_uri)
+ data = https.request(request)
+ data = data.body
+ cache_gist(gist, file, data) unless @cache == false
+ data
+ end
+ end
+
+ class GistTagNoCache < GistTag
+ def initialize(tag_name, text, token)
+ super
+ @cache = false
+ end
+ end
+end
+
+Liquid::Template.register_tag('gist', Jekyll::GistTag)
+Liquid::Template.register_tag('gistnocache', Jekyll::GistTagNoCache)
+
diff --git a/themes/classic/_plugins/haml.rb b/themes/classic/_plugins/haml.rb
new file mode 100644
index 00000000..7e548dec
--- /dev/null
+++ b/themes/classic/_plugins/haml.rb
@@ -0,0 +1,24 @@
+module Jekyll
+ require 'haml'
+ class HamlConverter < Converter
+ safe true
+ priority :low
+
+ def matches(ext)
+ ext =~ /haml/i
+ end
+
+ def output_ext(ext)
+ ".html"
+ end
+
+ def convert(content)
+ begin
+ engine = Haml::Engine.new(content)
+ engine.render
+ rescue StandardError => e
+ puts "!!! HAML Error: " + e.message
+ end
+ end
+ end
+end
diff --git a/themes/classic/_plugins/iterator.rb b/themes/classic/_plugins/iterator.rb
new file mode 100644
index 00000000..da0b5f0a
--- /dev/null
+++ b/themes/classic/_plugins/iterator.rb
@@ -0,0 +1,49 @@
+##
+## Author: Jose Gonzalez - https://github.com/josegonzalez
+## Source URL: https://github.com/josegonzalez/josediazgonzalez.com/blob/master/_plugins/iterator.rb
+##
+
+#module Jekyll
+ #class Site
+ #alias_method :orig_site_payload, :site_payload
+
+ ## Constuct an array of hashes that will allow the user, using Liquid, to
+ ## iterate through the keys of _kv_hash_ and be able to iterate through the
+ ## elements under each key.
+ ##
+ ## Example:
+ ## categories = { 'Ruby' => [<Post>, <Post>] }
+ ## make_iterable(categories, :index => 'name', :items => 'posts')
+ ## Will allow the user to iterate through all categories and then iterate
+ ## though each post in the current category like so:
+ ## {% for category in site.categories %}
+ ## h1. {{ category.name }}
+ ## <ul>
+ ## {% for post in category.posts %}
+ ## <li>{{ post.title }}</li>
+ ## {% endfor %}
+ ## </ul>
+ ## {% endfor %}
+ ##
+ ## Returns [ {<index> => <kv_hash_key>, <items> => kv_hash[<kv_hash_key>]}, ... ]
+
+ #def make_iterable(kv_hash, options)
+ #options = {:index => 'name', :items => 'items'}.merge(options)
+ #result = []
+ #kv_hash.sort.each do |key, value|
+ #result << { options[:index] => key, options[:items] => value }
+ #end
+ #result
+ #end
+
+ #def site_payload
+ #payload = orig_site_payload
+ #payload['site']['iterable'].merge!({
+ #'categories' => make_iterable(self.categories, :index => 'name', :items => 'posts'),
+ #'tags' => make_iterable(self.tags, :index => 'name', :items => 'posts')
+ #})
+ #payload
+ #end
+
+ #end
+#end
diff --git a/themes/classic/_plugins/pygments_cache_patch.rb b/themes/classic/_plugins/pygments_cache_patch.rb
new file mode 100644
index 00000000..36c78d20
--- /dev/null
+++ b/themes/classic/_plugins/pygments_cache_patch.rb
@@ -0,0 +1,30 @@
+#
+# Author: Raimonds Simanovskis, http://blog.rayapps.com/
+# Source URL: https://github.com/rsim/blog.rayapps.com/blob/master/_plugins/pygments_cache_patch.rb
+#
+
+require 'fileutils'
+require 'digest/md5'
+
+PYGMENTS_CACHE_DIR = File.expand_path('../../_cache', __FILE__)
+FileUtils.mkdir_p(PYGMENTS_CACHE_DIR)
+
+Jekyll::HighlightBlock.class_eval do
+ def render_pygments(context, code)
+ if defined?(PYGMENTS_CACHE_DIR)
+ path = File.join(PYGMENTS_CACHE_DIR, "#{@lang}-#{Digest::MD5.hexdigest(code)}.html")
+ if File.exist?(path)
+ highlighted_code = File.read(path)
+ else
+ highlighted_code = Albino.new(code, @lang).to_s(@options)
+ File.open(path, 'w') {|f| f.print(highlighted_code) }
+ end
+ else
+ highlighted_code = Albino.new(code, @lang).to_s(@options)
+ end
+ output = add_code_tags(highlighted_code, @lang)
+ output = context["pygments_prefix"] + output if context["pygments_prefix"]
+ output = output + context["pygments_suffix"] if context["pygments_suffix"]
+ output
+ end
+end
diff --git a/themes/classic/_plugins/sitemap_generator.rb b/themes/classic/_plugins/sitemap_generator.rb
new file mode 100644
index 00000000..3d5530b7
--- /dev/null
+++ b/themes/classic/_plugins/sitemap_generator.rb
@@ -0,0 +1,309 @@
+# Sitemap.xml Generator is a Jekyll plugin that generates a sitemap.xml file by
+# traversing all of the available posts and pages.
+#
+# How To Use:
+# 1.) Copy source file into your _plugins folder within your Jekyll project.
+# 2.) Change MY_URL to reflect your domain name.
+# 3.) Change SITEMAP_FILE_NAME if you want your sitemap to be called something
+# other than sitemap.xml.
+# 4.) Change the PAGES_INCLUDE_POSTS list to include any pages that are looping
+# through your posts (e.g. "index.html", "archive.html", etc.). This will
+# ensure that right after you make a new post, the last modified date will
+# be updated to reflect the new post.
+# 5.) Run Jekyll: jekyll --server to re-generate your site.
+# 6.) A sitemap.xml should be included in your _site folder.
+#
+# Customizations:
+# 1.) If there are any files you don't want included in the sitemap, add them
+# to the EXCLUDED_FILES list. The name should match the name of the source
+# file.
+# 2.) If you want to include the optional changefreq and priority attributes,
+# simply include custom variables in the YAML Front Matter of that file.
+# The names of these custom variables are defined below in the
+# CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME and PRIORITY_CUSTOM_VARIABLE_NAME
+# constants.
+#
+# Notes:
+# 1.) The last modified date is determined by the latest from the following:
+# system modified date of the page or post, system modified date of
+# included layout, system modified date of included layout within that
+# layout, ...
+#
+# Author: Michael Levin
+# Site: http://www.kinnetica.com
+# Distributed Under A Creative Commons License
+# - http://creativecommons.org/licenses/by/3.0/
+
+require 'rexml/document'
+
+module Jekyll
+
+ # Change MY_URL to reflect the site you are using
+ MY_URL = "http://www.mysite.com"
+
+ # Change SITEMAP_FILE_NAME if you would like your sitemap file
+ # to be called something else
+ SITEMAP_FILE_NAME = "sitemap.xml"
+
+ # Any files to exclude from being included in the sitemap.xml
+ EXCLUDED_FILES = ["atom.xml"]
+
+ # Any files that include posts, so that when a new post is added, the last
+ # modified date of these pages should take that into account
+ PAGES_INCLUDE_POSTS = ["index.html"]
+
+ # Custom variable names for changefreq and priority elements
+ # These names are used within the YAML Front Matter of pages or posts
+ # for which you want to include these properties
+ CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME = "change_frequency"
+ PRIORITY_CUSTOM_VARIABLE_NAME = "priority"
+
+ class Post
+ attr_accessor :name
+
+ def full_path_to_source
+ File.join(@base, @name)
+ end
+
+ def location_on_server
+ "#{MY_URL}#{url}"
+ end
+ end
+
+ class Page
+ attr_accessor :name
+
+ def full_path_to_source
+ File.join(@base, @dir, @name)
+ end
+
+ def location_on_server
+ location = "#{MY_URL}#{@dir}#{url}"
+ location.gsub(/index.html$/, "")
+ end
+ end
+
+ class Layout
+ def full_path_to_source
+ File.join(@base, @name)
+ end
+ end
+
+ # Recover from strange exception when starting server without --auto
+ class SitemapFile < StaticFile
+ def write(dest)
+ begin
+ super(dest)
+ rescue
+ end
+
+ true
+ end
+ end
+
+ class SitemapGenerator < Generator
+
+ # Valid values allowed by sitemap.xml spec for change frequencies
+ VALID_CHANGE_FREQUENCY_VALUES = ["always", "hourly", "daily", "weekly",
+ "monthly", "yearly", "never"]
+
+ # Goes through pages and posts and generates sitemap.xml file
+ #
+ # Returns nothing
+ def generate(site)
+ sitemap = REXML::Document.new << REXML::XMLDecl.new("1.0", "UTF-8")
+
+ urlset = REXML::Element.new "urlset"
+ urlset.add_attribute("xmlns",
+ "http://www.sitemaps.org/schemas/sitemap/0.9")
+
+ @last_modified_post_date = fill_posts(site, urlset)
+ fill_pages(site, urlset)
+
+ sitemap.add_element(urlset)
+
+ # File I/O: create sitemap.xml file and write out pretty-printed XML
+ file = File.new(File.join(site.dest, SITEMAP_FILE_NAME), "w")
+ formatter = REXML::Formatters::Pretty.new(4)
+ formatter.compact = true
+ formatter.write(sitemap, file)
+ file.close
+
+ # Keep the sitemap.xml file from being cleaned by Jekyll
+ site.static_files << Jekyll::SitemapFile.new(site, site.dest, "/", SITEMAP_FILE_NAME)
+ end
+
+ # Create url elements for all the posts and find the date of the latest one
+ #
+ # Returns last_modified_date of latest post
+ def fill_posts(site, urlset)
+ last_modified_date = nil
+ site.posts.each do |post|
+ if !excluded?(post.name)
+ url = fill_url(site, post)
+ urlset.add_element(url)
+ end
+
+ path = post.full_path_to_source
+ date = File.mtime(path)
+ last_modified_date = date if last_modified_date == nil or date > last_modified_date
+ end
+
+ last_modified_date
+ end
+
+ # Create url elements for all the normal pages and find the date of the
+ # index to use with the pagination pages
+ #
+ # Returns last_modified_date of index page
+ def fill_pages(site, urlset)
+ site.pages.each do |page|
+ if !excluded?(page.name)
+ path = page.full_path_to_source
+ if File.exists?(path)
+ url = fill_url(site, page)
+ urlset.add_element(url)
+ end
+ end
+ end
+ end
+
+ # Fill data of each URL element: location, last modified,
+ # change frequency (optional), and priority.
+ #
+ # Returns url REXML::Element
+ def fill_url(site, page_or_post)
+ url = REXML::Element.new "url"
+
+ loc = fill_location(page_or_post)
+ url.add_element(loc)
+
+ lastmod = fill_last_modified(site, page_or_post)
+ url.add_element(lastmod) if lastmod
+
+ if (page_or_post.data[CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME])
+ change_frequency =
+ page_or_post.data[CHANGE_FREQUENCY_CUSTOM_VARIABLE_NAME].downcase
+
+ if (valid_change_frequency?(change_frequency))
+ changefreq = REXML::Element.new "changefreq"
+ changefreq.text = change_frequency
+ url.add_element(changefreq)
+ else
+ puts "ERROR: Invalid Change Frequency In #{page_or_post.name}"
+ end
+ end
+
+ if (page_or_post.data[PRIORITY_CUSTOM_VARIABLE_NAME])
+ priority_value = page_or_post.data[PRIORITY_CUSTOM_VARIABLE_NAME]
+ if valid_priority?(priority_value)
+ priority = REXML::Element.new "priority"
+ priority.text = page_or_post.data[PRIORITY_CUSTOM_VARIABLE_NAME]
+ url.add_element(priority)
+ else
+ puts "ERROR: Invalid Priority In #{page_or_post.name}"
+ end
+ end
+
+ url
+ end
+
+ # Get URL location of page or post
+ #
+ # Returns the location of the page or post
+ def fill_location(page_or_post)
+ loc = REXML::Element.new "loc"
+ loc.text = page_or_post.location_on_server
+
+ loc
+ end
+
+ # Fill lastmod XML element with the last modified date for the page or post.
+ #
+ # Returns lastmod REXML::Element or nil
+ def fill_last_modified(site, page_or_post)
+ path = page_or_post.full_path_to_source
+
+ lastmod = REXML::Element.new "lastmod"
+ date = File.mtime(path)
+ latest_date = find_latest_date(date, site, page_or_post)
+
+ if @last_modified_post_date == nil
+ # This is a post
+ lastmod.text = latest_date.iso8601
+ else
+ # This is a page
+ if posts_included?(page_or_post.name)
+ # We want to take into account the last post date
+ final_date = greater_date(latest_date, @last_modified_post_date)
+ lastmod.text = final_date.iso8601
+ else
+ lastmod.text = latest_date.iso8601
+ end
+ end
+ lastmod
+ end
+
+ # Go through the page/post and any implemented layouts and get the latest
+ # modified date
+ #
+ # Returns formatted output of latest date of page/post and any used layouts
+ def find_latest_date(latest_date, site, page_or_post)
+ layouts = site.layouts
+ layout = layouts[page_or_post.data["layout"]]
+ while layout
+ path = layout.full_path_to_source
+ date = File.mtime(path)
+
+ latest_date = date if (date > latest_date)
+
+ layout = layouts[layout.data["layout"]]
+ end
+
+ latest_date
+ end
+
+ # Which of the two dates is later
+ #
+ # Returns latest of two dates
+ def greater_date(date1, date2)
+ if (date1 >= date2)
+ date1
+ else
+ date2
+ end
+ end
+
+ # Is the page or post listed as something we want to exclude?
+ #
+ # Returns boolean
+ def excluded?(name)
+ EXCLUDED_FILES.include? name
+ end
+
+ def posts_included?(name)
+ PAGES_INCLUDE_POSTS.include? name
+ end
+
+ # Is the change frequency value provided valid according to the spec
+ #
+ # Returns boolean
+ def valid_change_frequency?(change_frequency)
+ VALID_CHANGE_FREQUENCY_VALUES.include? change_frequency
+ end
+
+ # Is the priority value provided valid according to the spec
+ #
+ # Returns boolean
+ def valid_priority?(priority)
+ begin
+ priority_val = Float(priority)
+ return true if priority_val >= 0.0 and priority_val <= 1.0
+ rescue ArgumentError
+ end
+
+ false
+ end
+ end
+end
+
diff --git a/themes/classic/_plugins/titlecase.rb b/themes/classic/_plugins/titlecase.rb
new file mode 100644
index 00000000..103bf702
--- /dev/null
+++ b/themes/classic/_plugins/titlecase.rb
@@ -0,0 +1,36 @@
+class String
+ def titlecase
+ small_words = %w(a an and as at but by en for if in of on or the to v v. via vs vs.)
+
+ x = split(" ").map do |word|
+ # note: word could contain non-word characters!
+ # downcase all small_words, capitalize the rest
+ small_words.include?(word.gsub(/\W/, "").downcase) ? word.downcase! : word.smart_capitalize!
+ word
+ end
+ # capitalize first and last words
+ x.first.to_s.smart_capitalize!
+ x.last.to_s.smart_capitalize!
+ # small words after colons are capitalized
+ x.join(" ").gsub(/:\s?(\W*#{small_words.join("|")}\W*)\s/) { ": #{$1.smart_capitalize} " }
+ end
+
+ def titlecase!
+ replace(titlecase)
+ end
+
+ def smart_capitalize
+ # ignore any leading crazy characters and capitalize the first real character
+ if self =~ /^['"\(\[']*([a-z])/
+ i = index($1)
+ x = self[i,self.length]
+ # word with capitals and periods mid-word are left alone
+ self[i,1] = self[i,1].upcase unless x =~ /[A-Z]/ or x =~ /\.\w+/
+ end
+ self
+ end
+
+ def smart_capitalize!
+ replace(smart_capitalize)
+ end
+end