mirror of
https://github.com/kremalicious/blog.git
synced 2024-11-13 16:45:14 +01:00
titlecase, rubypants for post content, more stuff from octopress
This commit is contained in:
parent
1c522f648f
commit
82e9d7e45b
4
Gemfile
4
Gemfile
@ -4,4 +4,6 @@ source "https://rubygems.org"
|
||||
# gem "rails"
|
||||
gem 'jekyll', '~>1.3.0'
|
||||
gem 'mini_magick', '~>3.6.0'
|
||||
gem 'fileutils', '~>0.7'
|
||||
gem 'fileutils', '~>0.7'
|
||||
gem 'rubypants', '~> 0.2.0'
|
||||
gem 'gsl', '~> 1.15.3'
|
@ -10,6 +10,8 @@ GEM
|
||||
ffi (1.9.3)
|
||||
fileutils (0.7)
|
||||
rmagick (>= 2.13.1)
|
||||
gsl (1.15.3)
|
||||
narray (>= 0.5.9)
|
||||
highline (1.6.20)
|
||||
jekyll (1.3.1)
|
||||
classifier (~> 1.3)
|
||||
@ -30,6 +32,7 @@ GEM
|
||||
syntax (>= 1.0.0)
|
||||
mini_magick (3.6.0)
|
||||
subexec (~> 0.2.1)
|
||||
narray (0.6.0.8)
|
||||
posix-spawn (0.3.6)
|
||||
pygments.rb (0.5.4)
|
||||
posix-spawn (~> 0.3.6)
|
||||
@ -41,6 +44,7 @@ GEM
|
||||
ffi (>= 0.5.0)
|
||||
redcarpet (2.3.0)
|
||||
rmagick (2.13.2)
|
||||
rubypants (0.2.0)
|
||||
safe_yaml (0.9.7)
|
||||
subexec (0.2.3)
|
||||
syntax (1.0.0)
|
||||
@ -51,5 +55,7 @@ PLATFORMS
|
||||
|
||||
DEPENDENCIES
|
||||
fileutils (~> 0.7)
|
||||
gsl (~> 1.15.3)
|
||||
jekyll (~> 1.3.0)
|
||||
mini_magick (~> 3.6.0)
|
||||
rubypants (~> 0.2.0)
|
||||
|
@ -5,7 +5,7 @@
|
||||
<header>
|
||||
<h1 class="entry-title">
|
||||
<a href="{{ post.linkurl }}" title="Go to source: {{ post.linkurl | remove:'http://' | remove:'https://' | remove:'www.' }}">
|
||||
{{ post.title }} <i class="icon-forward"></i>
|
||||
{{ post.title | titlecase }} <i class="icon-forward"></i>
|
||||
<span class="linkurl">{{ post.linkurl | remove:'http://' | remove:'https://' | remove:'www.' | split:'/' | first }}</span>
|
||||
</a>
|
||||
</h1>
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
{% picture {{ post.image }} %}
|
||||
|
||||
<figcaption class="entry-title fn">{{ post.title }}</figcaption>
|
||||
<figcaption class="entry-title fn">{{ post.title | titlecase }}</figcaption>
|
||||
</figure>
|
||||
</a>
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
|
||||
<article class="hentry format-post">
|
||||
<header>
|
||||
<h1 class="entry-title"><a href="{{ post.url }}">{{ post.title }}</a></h1>
|
||||
<h1 class="entry-title"><a href="{{ post.url }}">{{ post.title | titlecase }}</a></h1>
|
||||
</header>
|
||||
|
||||
<section class="entry-content">
|
||||
|
@ -17,7 +17,7 @@ layout: base
|
||||
|
||||
<article class="hentry goodie">
|
||||
<header>
|
||||
<h1 class="entry-title"><a href="{{ post.url }}">{{ post.title }}</a></h1>
|
||||
<h1 class="entry-title"><a href="{{ post.url }}">{{ post.title | titlecase }}</a></h1>
|
||||
</header>
|
||||
|
||||
<section class="entry-content">
|
||||
@ -35,7 +35,7 @@ layout: base
|
||||
<p class="info col3">
|
||||
<a class="btn icon-info" href="{{ post.url }}">Release Post</a>
|
||||
</p>
|
||||
|
||||
|
||||
{% if post.download %}
|
||||
<p class="download col3">
|
||||
<a class="btn icon-arrow-down" href="/media/{{ post.download }}">Download <span>zip</span></a>
|
||||
@ -57,4 +57,6 @@ layout: base
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
{% include paginator.html %}
|
@ -8,7 +8,7 @@ layout: base
|
||||
<header>
|
||||
<h1 class="entry-title">
|
||||
<a href="{{ post.linkurl }}" title="Go to source: {{ page.linkurl | remove:'http://' | remove:'https://' | remove:'www.' }}">
|
||||
{{ page.title }} <i class="icon-forward"></i>
|
||||
{{ page.title | titlecase }} <i class="icon-forward"></i>
|
||||
<span class="linkurl">{{ page.linkurl | remove:'http://' | remove:'https://' | remove:'www.' | split:'/' | first }}</span>
|
||||
</a>
|
||||
</h1>
|
||||
|
@ -10,7 +10,7 @@ layout: base
|
||||
|
||||
{% picture {{ page.image }} %}
|
||||
|
||||
<figcaption class="entry-title fn">{{ page.title }}</figcaption>
|
||||
<figcaption class="entry-title fn">{{ page.title | titlecase }}</figcaption>
|
||||
|
||||
</figure>
|
||||
|
||||
|
@ -6,7 +6,7 @@ layout: base
|
||||
|
||||
<article class="hentry format-post">
|
||||
<header>
|
||||
<h1 class="entry-title">{{ page.title }}</h1>
|
||||
<h1 class="entry-title">{{ page.title | titlecase }}</h1>
|
||||
</header>
|
||||
|
||||
<section class="entry-content">
|
||||
@ -14,7 +14,7 @@ layout: base
|
||||
{% picture {{ page.image }} class="teaser" %}
|
||||
{% endif %}
|
||||
|
||||
{{ content }}
|
||||
{{ content | condense_spaces }}
|
||||
</section>
|
||||
|
||||
{% include entry_meta.html %}
|
||||
|
@ -1,32 +1,127 @@
|
||||
# Filters taken from the Octopress project by Brandon Mathis.
|
||||
# https://github.com/imathis/octopress/blob/master/plugins/octopress_filters.rb
|
||||
#custom filters for Octopress
|
||||
require './_src/_plugins/post_filters.rb'
|
||||
require './_src/_plugins/raw.rb'
|
||||
require 'rubypants'
|
||||
|
||||
module OctopressFilters
|
||||
include TemplateWrapper
|
||||
def pre_filter(input)
|
||||
input = input
|
||||
end
|
||||
def post_filter(input)
|
||||
input = unwrap(input)
|
||||
RubyPants.new(input).to_html
|
||||
end
|
||||
end
|
||||
|
||||
module Jekyll
|
||||
|
||||
module Filters
|
||||
|
||||
# Used on the blog index to split posts on the <!--more--> marker
|
||||
def excerpt(input)
|
||||
if input.index(/<!--\s*more\s*-->/i)
|
||||
input.split(/<!--\s*more\s*-->/i)[0]
|
||||
else
|
||||
input
|
||||
class ContentFilters < PostFilter
|
||||
include OctopressFilters
|
||||
def pre_render(post)
|
||||
if post.ext.match('html|textile|markdown|md|haml|slim|xml')
|
||||
post.content = pre_filter(post.content)
|
||||
end
|
||||
end
|
||||
|
||||
# Checks for excerpts (helpful for template conditionals)
|
||||
def has_more(input)
|
||||
input =~ /<!--\s*more\s*-->/i ? true : false
|
||||
end
|
||||
|
||||
# Replaces relative urls with full urls
|
||||
def expand_urls(input, url='')
|
||||
url ||= '/'
|
||||
input.gsub /(\s+(href|src)\s*=\s*["|']{1})(\/[^\"'>]*)/ do
|
||||
$1+url+$3
|
||||
def post_render(post)
|
||||
if post.ext.match('html|textile|markdown|md|haml|slim|xml')
|
||||
post.content = post_filter(post.content)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module OctopressLiquidFilters
|
||||
|
||||
# Used on the blog index to split posts on the <!--more--> marker
|
||||
def excerpt(input)
|
||||
if input.index(/<!--\s*more\s*-->/i)
|
||||
input.split(/<!--\s*more\s*-->/i)[0]
|
||||
else
|
||||
input
|
||||
end
|
||||
end
|
||||
|
||||
# Checks for excerpts (helpful for template conditionals)
|
||||
def has_excerpt(input)
|
||||
input =~ /<!--\s*more\s*-->/i ? true : false
|
||||
end
|
||||
|
||||
# Summary is used on the Archive pages to return the first block of content from a post.
|
||||
def summary(input)
|
||||
if input.index(/\n\n/)
|
||||
input.split(/\n\n/)[0]
|
||||
else
|
||||
input
|
||||
end
|
||||
end
|
||||
|
||||
# Extracts raw content DIV from template, used for page description as {{ content }}
|
||||
# contains complete sub-template code on main page level
|
||||
def raw_content(input)
|
||||
/<div class="entry-content">(?<content>[\s\S]*?)<\/div>\s*<(footer|\/article)>/ =~ input
|
||||
return (content.nil?) ? input : content
|
||||
end
|
||||
|
||||
# Escapes CDATA sections in post content
|
||||
def cdata_escape(input)
|
||||
input.gsub(/<!\[CDATA\[/, '<![CDATA[').gsub(/\]\]>/, ']]>')
|
||||
end
|
||||
|
||||
# Replaces relative urls with full urls
|
||||
def expand_urls(input, url='')
|
||||
url ||= '/'
|
||||
input.gsub /(\s+(href|src)\s*=\s*["|']{1})(\/[^\"'>]*)/ do
|
||||
$1+url+$3
|
||||
end
|
||||
end
|
||||
|
||||
# Improved version of Liquid's truncate:
|
||||
# - Doesn't cut in the middle of a word.
|
||||
# - Uses typographically correct ellipsis (…) insted of '...'
|
||||
def truncate(input, length)
|
||||
if input.length > length && input[0..(length-1)] =~ /(.+)\b.+$/im
|
||||
$1.strip + ' …'
|
||||
else
|
||||
input
|
||||
end
|
||||
end
|
||||
|
||||
# Improved version of Liquid's truncatewords:
|
||||
# - Uses typographically correct ellipsis (…) insted of '...'
|
||||
def truncatewords(input, length)
|
||||
truncate = input.split(' ')
|
||||
if truncate.length > length
|
||||
truncate[0..length-1].join(' ').strip + ' …'
|
||||
else
|
||||
input
|
||||
end
|
||||
end
|
||||
|
||||
# Condenses multiple spaces and tabs into a single space
|
||||
def condense_spaces(input)
|
||||
input.gsub(/\s{2,}/, ' ')
|
||||
end
|
||||
|
||||
# Removes trailing forward slash from a string for easily appending url segments
|
||||
def strip_slash(input)
|
||||
if input =~ /(.+)\/$|^\/$/
|
||||
input = $1
|
||||
end
|
||||
input
|
||||
end
|
||||
|
||||
# Returns a url without the protocol (http://)
|
||||
def shorthand_url(input)
|
||||
input.gsub /(https?:\/\/)(\S+)/ do
|
||||
$2
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a title cased string based on John Gruber's title case http://daringfireball.net/2008/08/title_case_update
|
||||
def titlecase(input)
|
||||
input.titlecase
|
||||
end
|
||||
|
||||
end
|
||||
Liquid::Template.register_filter(Jekyll::Filters)
|
||||
Liquid::Template.register_filter OctopressLiquidFilters
|
176
_src/_plugins/post_filters.rb
Normal file
176
_src/_plugins/post_filters.rb
Normal file
@ -0,0 +1,176 @@
|
||||
module Jekyll
|
||||
|
||||
# Extended plugin type that allows the plugin
|
||||
# to be called on varous callback methods.
|
||||
#
|
||||
# Examples:
|
||||
# https://github.com/tedkulp/octopress/blob/master/plugins/post_metaweblog.rb
|
||||
# https://github.com/tedkulp/octopress/blob/master/plugins/post_twitter.rb
|
||||
class PostFilter < Plugin
|
||||
|
||||
#Called before post is sent to the converter. Allows
|
||||
#you to modify the post object before the converter
|
||||
#does it's thing
|
||||
def pre_render(post)
|
||||
end
|
||||
|
||||
#Called after the post is rendered with the converter.
|
||||
#Use the post object to modify it's contents before the
|
||||
#post is inserted into the template.
|
||||
def post_render(post)
|
||||
end
|
||||
|
||||
#Called after the post is written to the disk.
|
||||
#Use the post object to read it's contents to do something
|
||||
#after the post is safely written.
|
||||
def post_write(post)
|
||||
end
|
||||
end
|
||||
|
||||
# Monkey patch for the Jekyll Site class. For the original class,
|
||||
# see: https://github.com/mojombo/jekyll/blob/master/lib/jekyll/site.rb
|
||||
class Site
|
||||
|
||||
# Instance variable to store the various post_filter
|
||||
# plugins that are loaded.
|
||||
attr_accessor :post_filters
|
||||
|
||||
# Instantiates all of the post_filter plugins. This is basically
|
||||
# a duplication of the other loaders in Site#setup.
|
||||
def load_post_filters
|
||||
self.post_filters = Jekyll::PostFilter.subclasses.select do |c|
|
||||
!self.safe || c.safe
|
||||
end.map do |c|
|
||||
c.new(self.config)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Monkey patch for the Jekyll Post class. For the original class,
|
||||
# see: https://github.com/mojombo/jekyll/blob/master/lib/jekyll/post.rb
|
||||
class Post
|
||||
|
||||
# Copy the #write method to #old_write, so we can redefine #write
|
||||
# method.
|
||||
alias_method :old_write, :write
|
||||
|
||||
# Write the generated post file to the destination directory. It
|
||||
# then calls any post_write methods that may exist.
|
||||
# +dest+ is the String path to the destination dir
|
||||
#
|
||||
# Returns nothing
|
||||
def write(dest)
|
||||
old_write(dest)
|
||||
post_write if respond_to?(:post_write)
|
||||
end
|
||||
end
|
||||
|
||||
# Monkey patch for the Jekyll Page class. For the original class,
|
||||
# see: https://github.com/mojombo/jekyll/blob/master/lib/jekyll/page.rb
|
||||
class Page
|
||||
|
||||
# Copy the #write method to #old_write, so we can redefine #write
|
||||
# method.
|
||||
alias_method :old_write, :write
|
||||
|
||||
# Write the generated post file to the destination directory. It
|
||||
# then calls any post_write methods that may exist.
|
||||
# +dest+ is the String path to the destination dir
|
||||
#
|
||||
# Returns nothing
|
||||
def write(dest)
|
||||
old_write(dest)
|
||||
post_write if respond_to?(:post_write)
|
||||
end
|
||||
end
|
||||
|
||||
# Monkey patch for the Jekyll Convertible module. For the original class,
|
||||
# see: https://github.com/mojombo/jekyll/blob/master/lib/jekyll/convertible.rb
|
||||
module Convertible
|
||||
|
||||
def is_post?
|
||||
self.class.to_s == 'Jekyll::Post'
|
||||
end
|
||||
|
||||
def is_page?
|
||||
self.class.to_s == 'Jekyll::Page'
|
||||
end
|
||||
|
||||
def is_filterable?
|
||||
is_post? or is_page?
|
||||
end
|
||||
|
||||
# Call the #pre_render methods on all of the loaded
|
||||
# post_filter plugins.
|
||||
#
|
||||
# Returns nothing
|
||||
def pre_render
|
||||
self.site.load_post_filters unless self.site.post_filters
|
||||
|
||||
if self.site.post_filters and is_filterable?
|
||||
self.site.post_filters.each do |filter|
|
||||
filter.pre_render(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Call the #post_render methods on all of the loaded
|
||||
# post_filter plugins.
|
||||
#
|
||||
# Returns nothing
|
||||
def post_render
|
||||
if self.site.post_filters and is_filterable?
|
||||
self.site.post_filters.each do |filter|
|
||||
filter.post_render(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Call the #post_write methods on all of the loaded
|
||||
# post_filter plugins.
|
||||
#
|
||||
# Returns nothing
|
||||
def post_write
|
||||
if self.site.post_filters and is_filterable?
|
||||
self.site.post_filters.each do |filter|
|
||||
filter.post_write(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Copy the #transform method to #old_transform, so we can
|
||||
# redefine #transform method.
|
||||
alias_method :old_transform, :transform
|
||||
|
||||
# Transform the contents based on the content type. Then calls the
|
||||
# #post_render method if it exists
|
||||
#
|
||||
# Returns nothing.
|
||||
def transform
|
||||
old_transform
|
||||
post_render if respond_to?(:post_render)
|
||||
end
|
||||
|
||||
# Copy the #do_layout method to #old_do_layout, so we can
|
||||
# redefine #do_layout method.
|
||||
alias_method :old_do_layout, :do_layout
|
||||
|
||||
# Calls the pre_render method if it exists and then adds any necessary
|
||||
# layouts to this convertible document.
|
||||
#
|
||||
# payload - The site payload Hash.
|
||||
# layouts - A Hash of {"name" => "layout"}.
|
||||
#
|
||||
# Returns nothing.
|
||||
def do_layout(payload, layouts)
|
||||
pre_render if respond_to?(:pre_render)
|
||||
old_do_layout(payload, layouts)
|
||||
end
|
||||
|
||||
# Returns the full url of the post, including the
|
||||
# configured url
|
||||
def full_url
|
||||
self.site.config['url'] + self.url
|
||||
end
|
||||
end
|
||||
end
|
40
_src/_plugins/raw.rb
Normal file
40
_src/_plugins/raw.rb
Normal file
@ -0,0 +1,40 @@
|
||||
# Author: Brandon Mathis
|
||||
# Description: Provides plugins with a method for wrapping and unwrapping input to prevent Markdown and Textile from parsing it.
|
||||
# Purpose: This is useful for preventing Markdown and Textile from being too aggressive and incorrectly parsing in-line HTML.
|
||||
module TemplateWrapper
|
||||
# Wrap input with a <div>
|
||||
def safe_wrap(input)
|
||||
"<div class='bogus-wrapper'><notextile>#{input}</notextile></div>"
|
||||
end
|
||||
# This must be applied after the
|
||||
def unwrap(input)
|
||||
input.gsub /<div class='bogus-wrapper'><notextile>(.+?)<\/notextile><\/div>/m do
|
||||
$1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Author: phaer, https://github.com/phaer
|
||||
# Source: https://gist.github.com/1020852
|
||||
# Description: Raw tag for jekyll. Keeps liquid from parsing text betweeen {% raw %} and {% endraw %}
|
||||
|
||||
module Jekyll
|
||||
class RawTag < Liquid::Block
|
||||
def parse(tokens)
|
||||
@nodelist ||= []
|
||||
@nodelist.clear
|
||||
|
||||
while token = tokens.shift
|
||||
if token =~ FullToken
|
||||
if block_delimiter == $1
|
||||
end_tag
|
||||
return
|
||||
end
|
||||
end
|
||||
@nodelist << token if not token.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Liquid::Template.register_tag('raw', Jekyll::RawTag)
|
36
_src/_plugins/titlecase.rb
Normal file
36
_src/_plugins/titlecase.rb
Normal file
@ -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. ezeep)
|
||||
|
||||
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 are capitalized after colon, period, exclamation mark, question mark
|
||||
x.join(" ").gsub(/(:|\.|!|\?)\s?(\W*#{small_words.join("|")}\W*)\s/) { "#{$1} #{$2.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
|
@ -3,7 +3,7 @@
|
||||
[
|
||||
{% for post in site.posts %}
|
||||
{
|
||||
"title" : "{{ post.title | escape }}",
|
||||
"title" : "{{ post.title | escape | titlecase }}",
|
||||
"category" : "{{ post.categories }}",
|
||||
"url" : "{{ post.url }}",
|
||||
"date" : "{{ post.date }}",
|
||||
|
Loading…
Reference in New Issue
Block a user