middleman-blog 3.4.1 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +0 -6
- data/CHANGELOG.md +32 -1
- data/Gemfile +5 -9
- data/README.md +3 -2
- data/features/article_cli.feature +10 -1
- data/features/custom_collections.feature +11 -0
- data/features/language.feature +82 -0
- data/features/multiblog.feature +4 -2
- data/features/permalink-data.feature +12 -0
- data/features/summary.feature +13 -0
- data/features/support/env.rb +3 -0
- data/features/tags.feature +18 -1
- data/features/time_zone.feature +1 -1
- data/fixtures/custom-article-template-app/config.rb +3 -0
- data/fixtures/custom-article-template-app/my_custom_article.tt +7 -0
- data/fixtures/custom-article-template-app/source/index.html.erb +9 -0
- data/fixtures/custom-article-template-app/source/layout.erb +30 -0
- data/fixtures/custom-collections-sources-app/config.rb +11 -0
- data/fixtures/custom-collections-sources-app/source/articles/2011-01-02-another-article.html.markdown +8 -0
- data/fixtures/custom-collections-sources-app/source/category.html.erb +7 -0
- data/fixtures/custom-collections-sources-app/source/index.html.erb +5 -0
- data/fixtures/custom-collections-sources-app/source/layout.erb +13 -0
- data/fixtures/custom-collections-sources-app/source/news/2011-01-01-new-article.html.markdown +7 -0
- data/fixtures/language-app/config.rb +2 -0
- data/fixtures/language-app/locales/en.yml +4 -0
- data/fixtures/language-app/locales/ru.yml +4 -0
- data/fixtures/language-app/source/2013-09-07-english-article-with-lang-in-frontmatter.html.erb +6 -0
- data/fixtures/language-app/source/2013-09-07-russian-article-with-lang-in-frontmatter.html.erb +6 -0
- data/fixtures/language-app/source/en/2013-09-07-english-article-with-lang-in-path.html.erb +5 -0
- data/fixtures/language-app/source/layouts/layout.erb +8 -0
- data/fixtures/language-app/source/localizable/index.html.erb +5 -0
- data/fixtures/language-app/source/ru/2013-09-07-russian-article-with-lang-in-path.html.erb +5 -0
- data/fixtures/multiblog-app/source/blog1/index.html.erb +7 -0
- data/fixtures/permalink-data-app/config.rb +5 -0
- data/fixtures/permalink-data-app/source/index.html.erb +3 -0
- data/fixtures/permalink-data-app/source/layout.erb +14 -0
- data/fixtures/permalink-data-app/source/news/2011-01-01-new-article.html.markdown +7 -0
- data/fixtures/time-zone-app/source/blog/2013-06-24-hello.html.erb +1 -0
- data/lib/middleman-blog.rb +3 -8
- data/lib/middleman-blog/blog_article.rb +96 -60
- data/lib/middleman-blog/blog_data.rb +78 -76
- data/lib/middleman-blog/calendar_pages.rb +87 -119
- data/lib/middleman-blog/commands/article.rb +20 -14
- data/lib/middleman-blog/custom_pages.rb +30 -64
- data/lib/middleman-blog/extension.rb +175 -0
- data/lib/middleman-blog/helpers.rb +152 -0
- data/lib/middleman-blog/paginator.rb +127 -123
- data/lib/middleman-blog/tag_pages.rb +27 -45
- data/lib/middleman-blog/template.rb +17 -15
- data/lib/middleman-blog/template/config.tt +30 -33
- data/lib/middleman-blog/template/source/layout.erb +1 -0
- data/lib/middleman-blog/uri_templates.rb +58 -0
- data/lib/middleman-blog/version.rb +1 -1
- data/middleman-blog.gemspec +4 -1
- metadata +75 -9
- data/Gemfile-3.0 +0 -27
- data/lib/middleman-blog/extension_3_0.rb +0 -248
- data/lib/middleman-blog/extension_3_1.rb +0 -278
@@ -0,0 +1,14 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
</head>
|
5
|
+
<body>
|
6
|
+
<% if is_blog_article? %>
|
7
|
+
URL: <%= current_article.url %>
|
8
|
+
Category: <%= current_article.metadata[:page]['category'] %>
|
9
|
+
<%= yield %>
|
10
|
+
<% else %>
|
11
|
+
<%= yield %>
|
12
|
+
<% end %>
|
13
|
+
</body>
|
14
|
+
</html>
|
data/lib/middleman-blog.rb
CHANGED
@@ -5,11 +5,6 @@ require "middleman-blog/template"
|
|
5
5
|
require "middleman-blog/commands/article"
|
6
6
|
|
7
7
|
::Middleman::Extensions.register(:blog) do
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
else
|
12
|
-
require "middleman-blog/extension_3_0"
|
13
|
-
::Middleman::Blog
|
14
|
-
end
|
15
|
-
end
|
8
|
+
require "middleman-blog/extension"
|
9
|
+
::Middleman::BlogExtension
|
10
|
+
end
|
@@ -1,95 +1,93 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'active_support/time_with_zone'
|
2
3
|
require 'active_support/core_ext/time/calculations'
|
3
4
|
|
4
5
|
module Middleman
|
5
6
|
module Blog
|
6
|
-
# A module that adds blog-article methods to Resources.
|
7
|
+
# A module that adds blog-article-specific methods to Resources.
|
8
|
+
# A {BlogArticle} can be retrieved via {Blog::Helpers#current_article} or
|
9
|
+
# methods on {BlogData} (like {BlogData#articles}).
|
10
|
+
# @see http://rdoc.info/github/middleman/middleman/Middleman/Sitemap/Resource Middleman::Sitemap::Resource
|
7
11
|
module BlogArticle
|
8
12
|
def self.extended(base)
|
9
13
|
base.class.send(:attr_accessor, :blog_controller)
|
10
14
|
end
|
11
15
|
|
16
|
+
# A reference to the {BlogData} for this article's blog.
|
17
|
+
# @return [BlogData]
|
12
18
|
def blog_data
|
13
|
-
|
14
|
-
self.blog_controller.data
|
15
|
-
else
|
16
|
-
app.blog
|
17
|
-
end
|
19
|
+
blog_controller.data
|
18
20
|
end
|
19
21
|
|
22
|
+
# The options for this article's blog.
|
23
|
+
# @return [ConfigurationManager]
|
20
24
|
def blog_options
|
21
|
-
|
22
|
-
self.blog_controller.options
|
23
|
-
else
|
24
|
-
app.blog.options
|
25
|
-
end
|
25
|
+
blog_controller.options
|
26
26
|
end
|
27
27
|
|
28
|
-
# Render this resource
|
28
|
+
# Render this resource to a string with the appropriate layout.
|
29
|
+
# Called automatically by Middleman.
|
29
30
|
# @return [String]
|
30
31
|
def render(opts={}, locs={}, &block)
|
31
32
|
if opts[:layout].nil?
|
32
|
-
|
33
|
-
opts[:layout] = metadata[:options][:layout]
|
34
|
-
end
|
33
|
+
opts[:layout] = metadata[:options][:layout]
|
35
34
|
opts[:layout] = blog_options.layout if opts[:layout].nil?
|
35
|
+
# Convert to a string unless it's a boolean
|
36
36
|
opts[:layout] = opts[:layout].to_s if opts[:layout].is_a? Symbol
|
37
37
|
end
|
38
38
|
|
39
39
|
content = super(opts, locs, &block)
|
40
40
|
|
41
41
|
unless opts[:keep_separator]
|
42
|
-
|
43
|
-
content.sub!(blog_options.summary_separator, "")
|
44
|
-
end
|
42
|
+
content.sub!(blog_options.summary_separator, "")
|
45
43
|
end
|
46
44
|
|
47
45
|
content
|
48
46
|
end
|
49
47
|
|
50
|
-
# The title of the article, set from frontmatter
|
48
|
+
# The title of the article, set from frontmatter.
|
51
49
|
# @return [String]
|
52
50
|
def title
|
53
51
|
data["title"]
|
54
52
|
end
|
55
53
|
|
56
|
-
# Whether or not this article has been published
|
54
|
+
# Whether or not this article has been published.
|
57
55
|
#
|
58
56
|
# An article is considered published in the following scenarios:
|
59
57
|
#
|
60
|
-
# 1.
|
61
|
-
# 2. published_future_dated is true or
|
62
|
-
# 3. article date is after the current time
|
58
|
+
# 1. Frontmatter does not set +published+ to false and either
|
59
|
+
# 2. The blog option +published_future_dated+ is true or
|
60
|
+
# 3. The article's date is after the current time
|
63
61
|
# @return [Boolean]
|
64
62
|
def published?
|
65
|
-
|
66
|
-
(blog_options.publish_future_dated || date <= Time.current)
|
63
|
+
data["published"] != false && (blog_options.publish_future_dated || date <= Time.current)
|
67
64
|
end
|
68
65
|
|
69
|
-
# The body of this article, in HTML. This is for
|
66
|
+
# The body of this article, in HTML (no layout). This is for
|
70
67
|
# things like RSS feeds or lists of articles - individual
|
71
68
|
# articles will automatically be rendered from their
|
72
69
|
# template.
|
73
70
|
# @return [String]
|
74
71
|
def body
|
75
|
-
render
|
72
|
+
render layout: false
|
76
73
|
end
|
77
74
|
|
78
75
|
# The summary for this article, in HTML. The summary is either
|
79
|
-
# everything before the summary separator (set via
|
80
|
-
# and defaulting to "READMORE") or the first
|
81
|
-
# characters of the post.
|
76
|
+
# everything before the summary separator (set via the blog option
|
77
|
+
# +summary_separator+ and defaulting to "READMORE") or the first
|
78
|
+
# +summary_length+ characters of the post.
|
82
79
|
#
|
83
|
-
#
|
84
|
-
# custom summary generation. The Proc is provided
|
85
|
-
#
|
80
|
+
# The blog option +summary_generator+ can be set to a +Proc+ in order to provide
|
81
|
+
# custom summary generation. The +Proc+ is provided
|
82
|
+
# the rendered content of the article (without layout), the
|
86
83
|
# desired length to trim the summary to, and the ellipsis string to use.
|
84
|
+
# Otherwise the {#default_summary_generator} will be used.
|
87
85
|
#
|
88
86
|
# @param [Number] length How many characters to trim the summary to.
|
89
87
|
# @param [String] ellipsis The ellipsis string to use when content is trimmed.
|
90
88
|
# @return [String]
|
91
89
|
def summary(length=blog_options.summary_length, ellipsis='...')
|
92
|
-
rendered = render
|
90
|
+
rendered = render layout: false, keep_separator: true
|
93
91
|
|
94
92
|
if blog_options.summary_separator && rendered.match(blog_options.summary_separator)
|
95
93
|
rendered.split(blog_options.summary_separator).first
|
@@ -100,12 +98,18 @@ module Middleman
|
|
100
98
|
end
|
101
99
|
end
|
102
100
|
|
101
|
+
# The default summary generator first tries to find the +summary_separator+ and
|
102
|
+
# take the text before it. If that doesn't work, it will truncate text without splitting
|
103
|
+
# the middle of an HTML tag, using a Nokogiri-based {TruncateHTML} utility.
|
104
|
+
#
|
105
|
+
# @param [String] rendered The rendered blog article
|
106
|
+
# @param [Integer] length The length in characters to truncate to.
|
107
|
+
# -1 or +nil+ will return the whole article.
|
103
108
|
def default_summary_generator(rendered, length, ellipsis)
|
104
|
-
|
105
|
-
|
106
|
-
if rendered =~ blog_options.summary_separator
|
109
|
+
if blog_options.summary_separator && rendered =~ blog_options.summary_separator
|
107
110
|
rendered.split(blog_options.summary_separator).first
|
108
|
-
elsif length
|
111
|
+
elsif length && length >= 0
|
112
|
+
require 'middleman-blog/truncate_html'
|
109
113
|
TruncateHTML.truncate_html(rendered, length, ellipsis)
|
110
114
|
else
|
111
115
|
rendered
|
@@ -113,23 +117,39 @@ module Middleman
|
|
113
117
|
end
|
114
118
|
|
115
119
|
# A list of tags for this article, set from frontmatter.
|
116
|
-
# @return [Array<String>] (never nil)
|
120
|
+
# @return [Array<String>] (never +nil+)
|
117
121
|
def tags
|
118
122
|
article_tags = data["tags"]
|
119
123
|
|
120
124
|
if article_tags.is_a? String
|
121
125
|
article_tags.split(',').map(&:strip)
|
122
126
|
else
|
123
|
-
article_tags
|
127
|
+
Array(article_tags)
|
124
128
|
end
|
125
129
|
end
|
126
130
|
|
127
|
-
#
|
128
|
-
#
|
129
|
-
#
|
130
|
-
|
131
|
-
|
132
|
-
|
131
|
+
# The language of the article. The language can be present in the
|
132
|
+
# frontmatter or in the source path. If both are present, they
|
133
|
+
# must match. If neither specifies a lang, I18n's default_locale will
|
134
|
+
# be used. If +lang+ is set to nil, or the +:i18n+ extension is not
|
135
|
+
# activated at all, +nil+ will be returned.
|
136
|
+
#
|
137
|
+
# @return [Symbol] Language code (for example, +:en+ or +:de+)
|
138
|
+
def lang
|
139
|
+
frontmatter_lang = data["lang"]
|
140
|
+
|
141
|
+
if blog_options.sources.include? ":lang"
|
142
|
+
filename_lang = path_part("lang")
|
143
|
+
end
|
144
|
+
|
145
|
+
if frontmatter_lang && filename_lang && frontmatter_lang != filename_lang
|
146
|
+
raise "The lang in #{path}'s filename (#{filename_lang.inspect}) doesn't match the lang in its frontmatter (#{frontmatter_lang.inspect})"
|
147
|
+
end
|
148
|
+
|
149
|
+
locale_lang = I18n.default_locale if defined? I18n
|
150
|
+
|
151
|
+
lang = frontmatter_lang || filename_lang || locale_lang
|
152
|
+
lang && lang.to_sym
|
133
153
|
end
|
134
154
|
|
135
155
|
# Attempt to figure out the date of the post. The date should be
|
@@ -141,7 +161,7 @@ module Middleman
|
|
141
161
|
def date
|
142
162
|
return @_date if @_date
|
143
163
|
|
144
|
-
frontmatter_date = data[
|
164
|
+
frontmatter_date = data['date']
|
145
165
|
|
146
166
|
# First get the date from frontmatter
|
147
167
|
if frontmatter_date.is_a? Time
|
@@ -151,11 +171,12 @@ module Middleman
|
|
151
171
|
end
|
152
172
|
|
153
173
|
# Next figure out the date from the filename
|
154
|
-
|
155
|
-
|
156
|
-
|
174
|
+
source_vars = blog_data.source_template.variables
|
175
|
+
if source_vars.include?('year') &&
|
176
|
+
source_vars.include?('month') &&
|
177
|
+
source_vars.include?('day')
|
157
178
|
|
158
|
-
filename_date = Time.zone.local(path_part(
|
179
|
+
filename_date = Time.zone.local(path_part('year').to_i, path_part('month').to_i, path_part('day').to_i)
|
159
180
|
if @_date
|
160
181
|
raise "The date in #{path}'s filename doesn't match the date in its frontmatter" unless @_date.to_date == filename_date.to_date
|
161
182
|
else
|
@@ -168,37 +189,52 @@ module Middleman
|
|
168
189
|
@_date
|
169
190
|
end
|
170
191
|
|
171
|
-
# The "slug" of the article that shows up in its URL.
|
192
|
+
# The "slug" of the article that shows up in its URL. The article slug
|
193
|
+
# is a parameterized version of the {#title} (lowercase, spaces replaced
|
194
|
+
# with dashes, etc) and can be used in the blog +permalink+ as +:title+.
|
195
|
+
#
|
172
196
|
# @return [String]
|
173
197
|
def slug
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
path_part(
|
198
|
+
if data['slug']
|
199
|
+
data['slug']
|
200
|
+
elsif blog_data.source_template.variables.include?('title')
|
201
|
+
path_part('title')
|
178
202
|
elsif title
|
179
|
-
title
|
203
|
+
Blog::UriTemplates.safe_parameterize(title)
|
180
204
|
else
|
181
205
|
raise "Can't generate a slug for #{path} because it has no :title in its path pattern or title/slug in its frontmatter."
|
182
206
|
end
|
183
207
|
end
|
184
208
|
|
185
209
|
# The previous (chronologically earlier) article before this one
|
186
|
-
# or nil if this is the first article.
|
187
|
-
# @return [
|
210
|
+
# or +nil+ if this is the first article.
|
211
|
+
# @return [BlogArticle]
|
188
212
|
def previous_article
|
189
213
|
blog_data.articles.find {|a| a.date < self.date }
|
190
214
|
end
|
191
215
|
|
192
216
|
# The next (chronologically later) article after this one
|
193
|
-
# or nil if this is the most recent article.
|
217
|
+
# or +nil+ if this is the most recent article.
|
194
218
|
# @return [Middleman::Sitemap::Resource]
|
195
219
|
def next_article
|
196
220
|
blog_data.articles.reverse.find {|a| a.date > self.date }
|
197
221
|
end
|
198
222
|
|
223
|
+
# This is here to prevent out-of-memory on exceptions.
|
224
|
+
# @private
|
199
225
|
def inspect
|
200
226
|
"#<Middleman::Blog::BlogArticle: #{data.inspect}>"
|
201
227
|
end
|
228
|
+
|
229
|
+
private
|
230
|
+
|
231
|
+
# Retrieve a section of the source path template.
|
232
|
+
# @param [String] part The part of the path, e.g. "lang", "year", "month", "day", "title"
|
233
|
+
# @return [String]
|
234
|
+
def path_part(part)
|
235
|
+
@_path_parts ||= blog_data.source_template.extract(path)
|
236
|
+
@_path_parts[part.to_s]
|
237
|
+
end
|
202
238
|
end
|
203
239
|
end
|
204
240
|
end
|
@@ -1,16 +1,16 @@
|
|
1
|
+
require 'middleman-blog/uri_templates'
|
2
|
+
|
1
3
|
module Middleman
|
2
4
|
module Blog
|
3
5
|
# A store of all the blog articles in the site, with accessors
|
4
6
|
# for the articles by various dimensions. Accessed via "blog" in
|
5
7
|
# templates.
|
6
8
|
class BlogData
|
7
|
-
|
8
|
-
# @return [Regex]
|
9
|
-
attr_reader :path_matcher
|
9
|
+
include UriTemplates
|
10
10
|
|
11
|
-
# A
|
12
|
-
# @return [
|
13
|
-
attr_reader :
|
11
|
+
# A URITemplate for the source file path relative to :source_dir
|
12
|
+
# @return [URITemplate]
|
13
|
+
attr_reader :source_template
|
14
14
|
|
15
15
|
# The configured options for this blog
|
16
16
|
# @return [Thor::CoreExt::HashWithIndifferentAccess]
|
@@ -18,10 +18,8 @@ module Middleman
|
|
18
18
|
|
19
19
|
attr_reader :controller
|
20
20
|
|
21
|
-
DEFAULT_PERMALINK_COMPONENTS = [:year, :month, :day, :title]
|
22
|
-
|
23
21
|
# @private
|
24
|
-
def initialize(app,
|
22
|
+
def initialize(app, controller, options)
|
25
23
|
@app = app
|
26
24
|
@options = options
|
27
25
|
@controller = controller
|
@@ -29,26 +27,10 @@ module Middleman
|
|
29
27
|
# A list of resources corresponding to blog articles
|
30
28
|
@_articles = []
|
31
29
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
gsub(":day", "(\\d{2})").
|
37
|
-
sub(":title", "([^/]+)")
|
38
|
-
|
39
|
-
subdir_matcher = matcher.sub(/\\\.[^.]+$/, "(/.*)$")
|
40
|
-
|
41
|
-
@path_matcher = /^#{matcher}/
|
42
|
-
@subdir_matcher = /^#{subdir_matcher}/
|
43
|
-
|
44
|
-
# Build a hash of part name to capture index, e.g. {"year" => 0}
|
45
|
-
@matcher_indexes = {}
|
46
|
-
options.sources.scan(/:year|:month|:day|:title/).
|
47
|
-
each_with_index do |key, i|
|
48
|
-
@matcher_indexes[key[1..-1]] = i
|
49
|
-
end
|
50
|
-
# The path always appears at the end.
|
51
|
-
@matcher_indexes["path"] = @matcher_indexes.size
|
30
|
+
@source_template = uri_template options.sources
|
31
|
+
@permalink_template = uri_template options.permalink
|
32
|
+
@subdir_template = uri_template options.sources.sub(/\.[^.]+$/, "/{+path}")
|
33
|
+
@subdir_permalink_template = uri_template options.permalink.sub(/\.[^.]+$/, "/{+path}")
|
52
34
|
end
|
53
35
|
|
54
36
|
# A list of all blog articles, sorted by descending date
|
@@ -57,15 +39,15 @@ module Middleman
|
|
57
39
|
@_articles.sort_by(&:date).reverse
|
58
40
|
end
|
59
41
|
|
60
|
-
#
|
61
|
-
#
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
42
|
+
# A list of all blog articles with the given language,
|
43
|
+
# sorted by descending date
|
44
|
+
#
|
45
|
+
# @param [Symbol] lang Language to match (optional, defaults to I18n.locale).
|
46
|
+
# @return [Array<Middleman::Sitemap::Resource>]
|
47
|
+
def local_articles(lang=nil)
|
48
|
+
lang ||= I18n.locale
|
49
|
+
lang = lang.to_sym if lang.kind_of? String
|
50
|
+
articles.select {|article| article.lang == lang }
|
69
51
|
end
|
70
52
|
|
71
53
|
# Returns a map from tag name to an array
|
@@ -80,6 +62,7 @@ module Middleman
|
|
80
62
|
end
|
81
63
|
end
|
82
64
|
|
65
|
+
# Sort each tag's list of articles
|
83
66
|
tags.each do |tag, articles|
|
84
67
|
tags[tag] = articles.sort_by(&:date).reverse
|
85
68
|
end
|
@@ -95,43 +78,40 @@ module Middleman
|
|
95
78
|
used_resources = []
|
96
79
|
|
97
80
|
resources.each do |resource|
|
98
|
-
if resource.path
|
99
|
-
resource
|
81
|
+
if (params = @source_template.extract(resource.path))
|
82
|
+
article = convert_to_article(resource)
|
83
|
+
next unless publishable?(article)
|
100
84
|
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
# Skip articles that are not published (in non-development environments)
|
106
|
-
next unless @app.environment == :development || resource.published?
|
85
|
+
# Add extra parameters from the URL to the page metadata
|
86
|
+
extra_data = params.except *%w(year month day title lang)
|
87
|
+
article.add_metadata page: extra_data unless extra_data.empty?
|
107
88
|
|
108
89
|
# compute output path:
|
109
90
|
# substitute date parts to path pattern
|
110
|
-
|
91
|
+
article.destination_path = template_path @permalink_template, article
|
111
92
|
|
112
|
-
@_articles <<
|
93
|
+
@_articles << article
|
113
94
|
|
114
|
-
elsif resource.path
|
115
|
-
|
95
|
+
elsif (params = @subdir_template.extract(resource.path))
|
96
|
+
# It's not an article, but it's thhe companion files for an article
|
97
|
+
# (in a subdirectory named after the article)
|
98
|
+
# figure out the matching article for this subdirectory file
|
116
99
|
|
117
|
-
article_path =
|
118
|
-
%w(year month day title).each do |token|
|
119
|
-
article_path = article_path.sub(":#{token}", match[@matcher_indexes[token]]) if @matcher_indexes[token]
|
120
|
-
end
|
100
|
+
article_path = @source_template.expand(params).to_s
|
121
101
|
|
122
102
|
article = @app.sitemap.find_resource_by_path(article_path)
|
123
103
|
raise "Article for #{resource.path} not found" if article.nil?
|
124
|
-
article.extend BlogArticle
|
125
104
|
|
126
|
-
#
|
127
|
-
|
105
|
+
# The article may not yet have been processed, so convert it here.
|
106
|
+
article = convert_to_article(article)
|
107
|
+
next unless publishable?(article)
|
128
108
|
|
129
109
|
# The subdir path is the article path with the index file name
|
130
110
|
# or file extension stripped off.
|
131
|
-
|
132
|
-
|
111
|
+
path = params.fetch('path')
|
112
|
+
new_destination_path = template_path @subdir_permalink_template, article, path: path
|
133
113
|
|
134
|
-
resource.destination_path = Middleman::Util.normalize_path(
|
114
|
+
resource.destination_path = Middleman::Util.normalize_path(new_destination_path)
|
135
115
|
end
|
136
116
|
|
137
117
|
used_resources << resource
|
@@ -140,30 +120,52 @@ module Middleman
|
|
140
120
|
used_resources
|
141
121
|
end
|
142
122
|
|
143
|
-
def
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
123
|
+
def inspect
|
124
|
+
"#<Middleman::Blog::BlogData: #{articles.inspect}>"
|
125
|
+
end
|
126
|
+
|
127
|
+
# Whether or not a given article should be included in the sitemap.
|
128
|
+
# Skip articles that are not published unless the environment is +:development+.
|
129
|
+
# @param [BlogArticle] article A blog article
|
130
|
+
# @return [Boolean] whether it should be published
|
131
|
+
def publishable?(article)
|
132
|
+
@app.environment == :development || article.published?
|
133
|
+
end
|
149
134
|
|
150
|
-
|
151
|
-
|
135
|
+
private
|
136
|
+
|
137
|
+
# Generate a hash of options for substituting into the permalink URL template.
|
138
|
+
# @param [Sitemap::Resource] resource The resource to generate options for.
|
139
|
+
# @param [Hash] extra More options to be merged in on top.
|
140
|
+
# @return [Hash] options
|
141
|
+
def permalink_options(resource, extra={})
|
142
|
+
# Allow any frontmatter data to be substituted into the permalink URL
|
143
|
+
params = resource.metadata[:page].slice *@permalink_template.variables
|
144
|
+
params.each do |k, v|
|
145
|
+
params[k] = safe_parameterize(v)
|
152
146
|
end
|
153
147
|
|
154
|
-
|
148
|
+
params.
|
149
|
+
merge(date_to_params(resource.date)).
|
150
|
+
merge(lang: resource.lang.to_s, title: resource.slug).
|
151
|
+
merge(extra)
|
155
152
|
end
|
156
153
|
|
157
|
-
def
|
158
|
-
|
159
|
-
end
|
154
|
+
def convert_to_article(resource)
|
155
|
+
return resource if resource.is_a?(BlogArticle)
|
160
156
|
|
161
|
-
|
162
|
-
|
157
|
+
resource.extend BlogArticle
|
158
|
+
resource.blog_controller = controller
|
159
|
+
|
160
|
+
if !options.preserve_locale && (lang = resource.lang)
|
161
|
+
resource.add_metadata options: { lang: lang }, locals: { lang: lang }
|
162
|
+
end
|
163
|
+
|
164
|
+
resource
|
163
165
|
end
|
164
166
|
|
165
|
-
def
|
166
|
-
|
167
|
+
def template_path(template, article, extras={})
|
168
|
+
apply_uri_template template, permalink_options(article, extras)
|
167
169
|
end
|
168
170
|
end
|
169
171
|
end
|