middleman-blog 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.travis.yml +5 -7
  4. data/CHANGELOG.md +21 -0
  5. data/CONTRIBUTING.md +43 -0
  6. data/Gemfile +22 -14
  7. data/Gemfile-3.0 +27 -0
  8. data/{LICENSE → LICENSE.md} +2 -2
  9. data/README.md +33 -28
  10. data/Rakefile +17 -1
  11. data/features/blog_sources.feature +13 -0
  12. data/features/calendar_multiblog.feature +153 -0
  13. data/features/multiblog.feature +51 -0
  14. data/features/paginate_multiblog.feature +270 -0
  15. data/features/summary.feature +43 -0
  16. data/features/support/env.rb +6 -1
  17. data/features/tags_multiblog.feature +125 -0
  18. data/features/time_zone.feature +5 -0
  19. data/fixtures/blog-sources-app/source/blog/2013-08-08-slug-from-filename.html.markdown +7 -0
  20. data/fixtures/calendar-multiblog-app/config.rb +17 -0
  21. data/fixtures/calendar-multiblog-app/source/blog1/2011-01-01-new-article.html.markdown +7 -0
  22. data/fixtures/calendar-multiblog-app/source/blog1/2011-01-02-another-article.html.markdown +8 -0
  23. data/fixtures/calendar-multiblog-app/source/blog2/2011-01-01-new-article.html.markdown +7 -0
  24. data/fixtures/calendar-multiblog-app/source/blog2/2011-01-02-another-article.html.markdown +8 -0
  25. data/fixtures/calendar-multiblog-app/source/calendar1.html.erb +13 -0
  26. data/fixtures/calendar-multiblog-app/source/calendar2.html.erb +13 -0
  27. data/fixtures/calendar-multiblog-app/source/index.html.erb +15 -0
  28. data/fixtures/calendar-multiblog-app/source/layout.erb +15 -0
  29. data/fixtures/default-template-app/Gemfile +6 -0
  30. data/fixtures/default-template-app/config.rb +35 -0
  31. data/fixtures/default-template-app/source/2013-04-01-new-article.html.markdown +25 -0
  32. data/{features/encoding.feature → fixtures/default-template-app/source/about-me.html.erb} +0 -0
  33. data/fixtures/default-template-app/source/archives.html.erb +10 -0
  34. data/fixtures/default-template-app/source/index.html.erb +11 -0
  35. data/fixtures/default-template-app/source/javascripts/_zepto.pjax.js +744 -0
  36. data/fixtures/default-template-app/source/javascripts/app.js +11 -0
  37. data/fixtures/default-template-app/source/javascripts/modernizr.js +1 -0
  38. data/fixtures/default-template-app/source/layouts/layout.erb +62 -0
  39. data/fixtures/default-template-app/source/stylesheets/app.css.scss +109 -0
  40. data/fixtures/multiblog-app/config.rb +0 -0
  41. data/fixtures/multiblog-app/source/blog1/2012-12-12-other-article.html.markdown +5 -0
  42. data/fixtures/multiblog-app/source/blog2/2011/01/01/new-article.html.markdown +6 -0
  43. data/fixtures/multiblog-app/source/index.html.erb +7 -0
  44. data/fixtures/multiblog-app/source/layout.erb +30 -0
  45. data/fixtures/no-title-app/config.rb +3 -0
  46. data/fixtures/no-title-app/source/2013-08-07.html.markdown +6 -0
  47. data/fixtures/no-title-app/source/2013-08-08.html.markdown +7 -0
  48. data/fixtures/no-title-app/source/layout.erb +13 -0
  49. data/fixtures/paginate-multiblog-app/config.rb +31 -0
  50. data/fixtures/paginate-multiblog-app/source/blog1/2011-01-01-test-article.html.markdown +6 -0
  51. data/fixtures/paginate-multiblog-app/source/blog1/2011-01-02-test-article.html.markdown +6 -0
  52. data/fixtures/paginate-multiblog-app/source/blog1/2011-01-03-test-article.html.markdown +6 -0
  53. data/fixtures/paginate-multiblog-app/source/blog1/2011-01-04-test-article.html.markdown +6 -0
  54. data/fixtures/paginate-multiblog-app/source/blog1/2011-01-05-test-article.html.markdown +6 -0
  55. data/fixtures/paginate-multiblog-app/source/blog1/2011-02-01-test-article.html.markdown +6 -0
  56. data/fixtures/paginate-multiblog-app/source/blog1/index.html.erb +27 -0
  57. data/fixtures/paginate-multiblog-app/source/blog2/2011-01-01-test-article.html.markdown +6 -0
  58. data/fixtures/paginate-multiblog-app/source/blog2/2011-01-02-test-article.html.markdown +6 -0
  59. data/fixtures/paginate-multiblog-app/source/blog2/2011-01-03-test-article.html.markdown +6 -0
  60. data/fixtures/paginate-multiblog-app/source/blog2/2011-01-04-test-article.html.markdown +6 -0
  61. data/fixtures/paginate-multiblog-app/source/blog2/2011-01-05-test-article.html.markdown +6 -0
  62. data/fixtures/paginate-multiblog-app/source/blog2/index.html.erb +27 -0
  63. data/fixtures/paginate-multiblog-app/source/blog3/2011-01-01-test-article.html.markdown +6 -0
  64. data/fixtures/paginate-multiblog-app/source/blog3/2011-01-02-test-article.html.markdown +6 -0
  65. data/fixtures/paginate-multiblog-app/source/blog3/2011-01-03-test-article.html.markdown +6 -0
  66. data/fixtures/paginate-multiblog-app/source/blog3/2011-01-04-test-article.html.markdown +6 -0
  67. data/fixtures/paginate-multiblog-app/source/blog3/2011-01-05-test-article.html.markdown +6 -0
  68. data/fixtures/paginate-multiblog-app/source/blog3/2011-02-01-test-article.html.markdown +6 -0
  69. data/fixtures/paginate-multiblog-app/source/blog3/2011-02-02-test-article.html.markdown +6 -0
  70. data/fixtures/paginate-multiblog-app/source/blog3/index.html.erb +28 -0
  71. data/fixtures/paginate-multiblog-app/source/calendar1.html.erb +28 -0
  72. data/fixtures/paginate-multiblog-app/source/calendar2.html.erb +28 -0
  73. data/fixtures/paginate-multiblog-app/source/calendar3.html.erb +28 -0
  74. data/fixtures/paginate-multiblog-app/source/layout.erb +15 -0
  75. data/fixtures/paginate-multiblog-app/source/tag1.html.erb +23 -0
  76. data/fixtures/paginate-multiblog-app/source/tag2.html.erb +23 -0
  77. data/fixtures/paginate-multiblog-app/source/tag3.html.erb +19 -0
  78. data/fixtures/summary-app/config.rb +1 -0
  79. data/fixtures/summary-app/source/2011-01-01-article-with-no-summary-separator-and-comments-in-the-summary.html.erb +10 -0
  80. data/fixtures/summary-app/source/2011-01-01-article-with-standard-summary-separator.html.markdown +7 -0
  81. data/fixtures/summary-app/source/2012-06-19-article-with-no-summary-separator.html.markdown +9 -0
  82. data/fixtures/summary-app/source/2013-05-08-article-with-custom-separator.html.markdown +7 -0
  83. data/fixtures/summary-app/source/index.html.erb +5 -0
  84. data/fixtures/tags-multiblog-app/config.rb +15 -0
  85. data/fixtures/tags-multiblog-app/source/blog1/2011-01-01-new-article.html.markdown +7 -0
  86. data/fixtures/tags-multiblog-app/source/blog1/2011-01-02-another-article.html.markdown +9 -0
  87. data/fixtures/tags-multiblog-app/source/blog2/2011-01-01-new-article.html.markdown +7 -0
  88. data/fixtures/tags-multiblog-app/source/blog2/2011-01-02-another-article.html.markdown +9 -0
  89. data/fixtures/tags-multiblog-app/source/index.html.erb +8 -0
  90. data/fixtures/tags-multiblog-app/source/layout.erb +13 -0
  91. data/fixtures/tags-multiblog-app/source/tag1.html.erb +7 -0
  92. data/fixtures/tags-multiblog-app/source/tag2.html.erb +7 -0
  93. data/fixtures/time-zone-app/config.rb +5 -0
  94. data/fixtures/time-zone-app/source/blog/2013-06-24-hello.html.erb +5 -0
  95. data/lib/middleman-blog.rb +9 -4
  96. data/lib/middleman-blog/blog_article.rb +47 -21
  97. data/lib/middleman-blog/blog_data.rb +11 -4
  98. data/lib/middleman-blog/calendar_pages.rb +40 -25
  99. data/lib/middleman-blog/{extension.rb → extension_3_0.rb} +20 -16
  100. data/lib/middleman-blog/extension_3_1.rb +208 -0
  101. data/lib/middleman-blog/paginator.rb +33 -7
  102. data/lib/middleman-blog/tag_pages.rb +26 -9
  103. data/lib/middleman-blog/template/shared/Gemfile.tt +4 -2
  104. data/lib/middleman-blog/template/source/calendar.html.erb +1 -1
  105. data/lib/middleman-blog/template/source/feed.xml.builder +8 -7
  106. data/lib/middleman-blog/template/source/index.html.erb +1 -1
  107. data/lib/middleman-blog/template/source/tag.html.erb +1 -1
  108. data/lib/middleman-blog/truncate_html.rb +10 -1
  109. data/lib/middleman-blog/version.rb +1 -1
  110. data/middleman-blog.gemspec +12 -15
  111. metadata +180 -14
@@ -5,6 +5,26 @@ module Middleman
5
5
  module Blog
6
6
  # A module that adds blog-article methods to Resources.
7
7
  module BlogArticle
8
+ def self.extended(base)
9
+ base.class.send(:attr_accessor, :blog_controller)
10
+ end
11
+
12
+ def blog_data
13
+ if self.blog_controller
14
+ self.blog_controller.data
15
+ else
16
+ app.blog
17
+ end
18
+ end
19
+
20
+ def blog_options
21
+ if self.blog_controller
22
+ self.blog_controller.options
23
+ else
24
+ app.blog.options
25
+ end
26
+ end
27
+
8
28
  # Render this resource
9
29
  # @return [String]
10
30
  def render(opts={}, locs={}, &block)
@@ -12,15 +32,15 @@ module Middleman
12
32
  if metadata[:options] && !metadata[:options][:layout].nil?
13
33
  opts[:layout] = metadata[:options][:layout]
14
34
  end
15
- opts[:layout] = app.blog.options.layout if opts[:layout].nil?
35
+ opts[:layout] = blog_options.layout if opts[:layout].nil?
16
36
  opts[:layout] = opts[:layout].to_s if opts[:layout].is_a? Symbol
17
37
  end
18
38
 
19
39
  content = super(opts, locs, &block)
20
40
 
21
41
  unless opts[:keep_separator]
22
- if content.match(app.blog.options.summary_separator)
23
- content.sub!(app.blog.options.summary_separator, "")
42
+ if content.match(blog_options.summary_separator)
43
+ content.sub!(blog_options.summary_separator, "")
24
44
  end
25
45
  end
26
46
 
@@ -43,7 +63,7 @@ module Middleman
43
63
  # @return [Boolean]
44
64
  def published?
45
65
  (data["published"] != false) and
46
- (app.blog.options.publish_future_dated || date <= Time.current)
66
+ (blog_options.publish_future_dated || date <= Time.current)
47
67
  end
48
68
 
49
69
  # The body of this article, in HTML. This is for
@@ -66,15 +86,15 @@ module Middleman
66
86
  # desired length to trim the summary to, and the ellipsis string to use.
67
87
  #
68
88
  # @param [Number] length How many characters to trim the summary to.
69
- # @param [Number] length The ellipsis string to use when content is trimmed.
89
+ # @param [String] ellipsis The ellipsis string to use when content is trimmed.
70
90
  # @return [String]
71
- def summary(length=app.blog.options.summary_length, ellipsis='...')
91
+ def summary(length=blog_options.summary_length, ellipsis='...')
72
92
  rendered = render(:layout => false, :keep_separator => true)
73
93
 
74
- if app.blog.options.summary_separator && rendered.match(app.blog.options.summary_separator)
75
- rendered.split(app.blog.options.summary_separator).first
76
- elsif app.blog.options.summary_generator
77
- app.blog.options.summary_generator.call(self, rendered, length, ellipsis)
94
+ if blog_options.summary_separator && rendered.match(blog_options.summary_separator)
95
+ rendered.split(blog_options.summary_separator).first
96
+ elsif blog_options.summary_generator
97
+ blog_options.summary_generator.call(self, rendered, length, ellipsis)
78
98
  else
79
99
  default_summary_generator(rendered, length, ellipsis)
80
100
  end
@@ -83,8 +103,8 @@ module Middleman
83
103
  def default_summary_generator(rendered, length, ellipsis)
84
104
  require 'middleman-blog/truncate_html'
85
105
 
86
- if rendered =~ app.blog.options.summary_separator
87
- rendered.split(app.blog.options.summary_separator).first
106
+ if rendered =~ blog_options.summary_separator
107
+ rendered.split(blog_options.summary_separator).first
88
108
  elsif length
89
109
  TruncateHTML.truncate_html(rendered, length, ellipsis)
90
110
  else
@@ -108,9 +128,9 @@ module Middleman
108
128
  # @param [String] The part of the path, e.g. "year", "month", "day", "title"
109
129
  # @return [String]
110
130
  def path_part(part)
111
- @_path_parts ||= app.blog.path_matcher.match(path).captures
131
+ @_path_parts ||= blog_data.path_matcher.match(path).captures
112
132
 
113
- @_path_parts[app.blog.matcher_indexes[part]]
133
+ @_path_parts[blog_data.matcher_indexes[part]]
114
134
  end
115
135
 
116
136
  # Attempt to figure out the date of the post. The date should be
@@ -132,9 +152,9 @@ module Middleman
132
152
  end
133
153
 
134
154
  # Next figure out the date from the filename
135
- if app.blog.options.sources.include?(":year") &&
136
- app.blog.options.sources.include?(":month") &&
137
- app.blog.options.sources.include?(":day")
155
+ if blog_options.sources.include?(":year") &&
156
+ blog_options.sources.include?(":month") &&
157
+ blog_options.sources.include?(":day")
138
158
 
139
159
  filename_date = Time.zone.local(path_part("year").to_i, path_part("month").to_i, path_part("day").to_i)
140
160
  if @_date
@@ -152,21 +172,27 @@ module Middleman
152
172
  # The "slug" of the article that shows up in its URL.
153
173
  # @return [String]
154
174
  def slug
155
- @_slug ||= path_part("title")
175
+ @_slug ||= data["slug"]
176
+
177
+ @_slug ||= if blog_options.sources.include?(":title")
178
+ path_part("title")
179
+ else
180
+ title.parameterize
181
+ end
156
182
  end
157
183
 
158
184
  # The previous (chronologically earlier) article before this one
159
185
  # or nil if this is the first article.
160
186
  # @return [Middleman::Sitemap::Resource]
161
187
  def previous_article
162
- app.blog.articles.find {|a| a.date < self.date }
188
+ blog_data.articles.find {|a| a.date < self.date }
163
189
  end
164
-
190
+
165
191
  # The next (chronologically later) article after this one
166
192
  # or nil if this is the most recent article.
167
193
  # @return [Middleman::Sitemap::Resource]
168
194
  def next_article
169
- app.blog.articles.reverse.find {|a| a.date > self.date }
195
+ blog_data.articles.reverse.find {|a| a.date > self.date }
170
196
  end
171
197
  end
172
198
  end
@@ -16,19 +16,22 @@ module Middleman
16
16
  # @return [Thor::CoreExt::HashWithIndifferentAccess]
17
17
  attr_reader :options
18
18
 
19
+ attr_reader :controller
20
+
19
21
  # @private
20
- def initialize(app, options={})
22
+ def initialize(app, options={}, controller=nil)
21
23
  @app = app
22
24
  @options = options
25
+ @controller = controller
23
26
 
24
27
  # A list of resources corresponding to blog articles
25
28
  @_articles = []
26
29
 
27
30
  matcher = Regexp.escape(options.sources).
28
31
  sub(/^\//, "").
29
- sub(":year", "(\\d{4})").
30
- sub(":month", "(\\d{2})").
31
- sub(":day", "(\\d{2})").
32
+ gsub(":year", "(\\d{4})").
33
+ gsub(":month", "(\\d{2})").
34
+ gsub(":day", "(\\d{2})").
32
35
  sub(":title", "([^/]+)")
33
36
 
34
37
  subdir_matcher = matcher.sub(/\\\.[^.]+$/, "(/.*)$")
@@ -93,6 +96,10 @@ module Middleman
93
96
  if resource.path =~ path_matcher
94
97
  resource.extend BlogArticle
95
98
 
99
+ if @controller
100
+ resource.blog_controller = controller
101
+ end
102
+
96
103
  # Skip articles that are not published (in non-development environments)
97
104
  next unless @app.environment == :development || resource.published?
98
105
 
@@ -6,56 +6,73 @@ module Middleman
6
6
  class CalendarPages
7
7
  class << self
8
8
  # Get a path to the given calendar page, based on the :year_link, :month_link or :day_link setting.
9
- # @param [Middleman::Application] app
9
+ # @param [Hash] blog_options
10
10
  # @param [Number] year
11
11
  # @param [Number] month
12
12
  # @param [Number] day
13
13
  # @return [String]
14
- def link(app, year, month=nil, day=nil)
14
+ def link(blog_options, year, month=nil, day=nil)
15
15
  path = if day
16
- app.blog.options.day_link.
16
+ blog_options.day_link.
17
17
  sub(':year', year.to_s).
18
18
  sub(':month', month.to_s.rjust(2,'0')).
19
19
  sub(':day', day.to_s.rjust(2,'0'))
20
20
  elsif month
21
- app.blog.options.month_link.
21
+ blog_options.month_link.
22
22
  sub(':year', year.to_s).
23
23
  sub(':month', month.to_s.rjust(2,'0'))
24
24
  else
25
- app.blog.options.year_link.
25
+ blog_options.year_link.
26
26
  sub(':year', year.to_s)
27
27
  end
28
28
  ::Middleman::Util.normalize_path(path)
29
29
  end
30
30
  end
31
31
 
32
- def initialize(app)
32
+ def initialize(app, controller=nil)
33
33
  @app = app
34
+ @blog_controller = controller
35
+ end
36
+
37
+ def blog_data
38
+ if @blog_controller
39
+ @blog_controller.data
40
+ else
41
+ @app.blog
42
+ end
43
+ end
44
+
45
+ def blog_options
46
+ if @blog_controller
47
+ @blog_controller.options
48
+ else
49
+ @app.blog.options
50
+ end
34
51
  end
35
52
 
36
53
  # Update the main sitemap resource list
37
54
  # @return [void]
38
55
  def manipulate_resource_list(resources)
39
56
  new_resources = []
40
- # Set up date pages if the appropriate templates have been specified
41
- @app.blog.articles.group_by {|a| a.date.year }.each do |year, year_articles|
42
- if @app.blog.options.year_template
43
- @app.ignore @app.blog.options.year_template
44
57
 
45
- path = CalendarPages.link(@app, year)
58
+ # Set up date pages if the appropriate templates have been specified
59
+ self.blog_data.articles.group_by {|a| a.date.year }.each do |year, year_articles|
60
+ if self.blog_options.year_template
61
+ path = CalendarPages.link(self.blog_options, year)
46
62
 
47
63
  p = ::Middleman::Sitemap::Resource.new(
48
64
  @app.sitemap,
49
65
  path
50
66
  )
51
- p.proxy_to(@app.blog.options.year_template)
67
+ p.proxy_to(self.blog_options.year_template)
52
68
 
53
69
  # Add metadata in local variables so it's accessible to
54
70
  # later extensions
55
71
  p.add_metadata :locals => {
56
72
  'page_type' => 'year',
57
73
  'year' => year,
58
- 'articles' => year_articles
74
+ 'articles' => year_articles,
75
+ 'blog_controller' => @blog_controller
59
76
  }
60
77
  # Add metadata in instance variables for backwards compatibility
61
78
  p.add_metadata do
@@ -67,22 +84,21 @@ module Middleman
67
84
  end
68
85
 
69
86
  year_articles.group_by {|a| a.date.month }.each do |month, month_articles|
70
- if @app.blog.options.month_template
71
- @app.ignore @app.blog.options.month_template
72
-
73
- path = CalendarPages.link(@app, year, month)
87
+ if self.blog_options.month_template
88
+ path = CalendarPages.link(self.blog_options, year, month)
74
89
 
75
90
  p = ::Middleman::Sitemap::Resource.new(
76
91
  @app.sitemap,
77
92
  path
78
93
  )
79
- p.proxy_to(@app.blog.options.month_template)
94
+ p.proxy_to(self.blog_options.month_template)
80
95
 
81
96
  p.add_metadata :locals => {
82
97
  'page_type' => 'month',
83
98
  'year' => year,
84
99
  'month' => month,
85
- 'articles' => month_articles
100
+ 'articles' => month_articles,
101
+ 'blog_controller' => @blog_controller
86
102
  }
87
103
  p.add_metadata do
88
104
  @year = year
@@ -94,23 +110,22 @@ module Middleman
94
110
  end
95
111
 
96
112
  month_articles.group_by {|a| a.date.day }.each do |day, day_articles|
97
- if @app.blog.options.day_template
98
- @app.ignore @app.blog.options.day_template
99
-
100
- path = CalendarPages.link(@app, year, month, day)
113
+ if self.blog_options.day_template
114
+ path = CalendarPages.link(self.blog_options, year, month, day)
101
115
 
102
116
  p = ::Middleman::Sitemap::Resource.new(
103
117
  @app.sitemap,
104
118
  path
105
119
  )
106
- p.proxy_to(@app.blog.options.day_template)
120
+ p.proxy_to(self.blog_options.day_template)
107
121
 
108
122
  p.add_metadata :locals => {
109
123
  'page_type' => 'day',
110
124
  'year' => year,
111
125
  'month' => month,
112
126
  'day' => day,
113
- 'articles' => day_articles
127
+ 'articles' => day_articles,
128
+ 'blog_controller' => @blog_controller
114
129
  }
115
130
  p.add_metadata do
116
131
  @year = year
@@ -24,31 +24,29 @@ module Middleman
24
24
  :page_link,
25
25
  :publish_future_dated
26
26
  ]
27
-
27
+
28
28
  KEYS.each do |name|
29
29
  attr_accessor name
30
30
  end
31
-
31
+
32
32
  def initialize(options={})
33
33
  options.each do |k,v|
34
34
  self.send(:"#{k}=", v)
35
35
  end
36
36
  end
37
37
  end
38
-
38
+
39
39
  class << self
40
40
  def registered(app, options_hash={}, &block)
41
41
  require 'middleman-blog/blog_data'
42
42
  require 'middleman-blog/blog_article'
43
43
  require 'active_support/core_ext/time/zones'
44
44
 
45
- app.set :time_zone, 'UTC'
46
-
47
45
  app.send :include, Helpers
48
-
46
+
49
47
  options = Options.new(options_hash)
50
48
  yield options if block_given?
51
-
49
+
52
50
  options.permalink ||= "/:year/:month/:day/:title.html"
53
51
  options.sources ||= ":year-:month-:day-:title.html"
54
52
  options.taglink ||= "tags/:tag.html"
@@ -90,6 +88,7 @@ module Middleman
90
88
  # Make sure ActiveSupport's TimeZone stuff has something to work with,
91
89
  # allowing people to set their desired time zone via Time.zone or
92
90
  # set :time_zone
91
+ Time.zone = self.time_zone if self.respond_to?(:time_zone)
93
92
  time_zone = Time.zone if Time.zone
94
93
  zone_default = Time.find_zone!(time_zone || 'UTC')
95
94
  unless zone_default
@@ -97,9 +96,14 @@ module Middleman
97
96
  end
98
97
  Time.zone_default = zone_default
99
98
 
99
+ ignore(options.calendar_template) if options.calendar_template
100
+ ignore(options.year_template) if options.year_template
101
+ ignore(options.month_template) if options.month_template
102
+ ignore(options.day_template) if options.day_template
103
+
100
104
  # Initialize blog with options
101
105
  blog(options)
102
-
106
+
103
107
  sitemap.register_resource_list_manipulator(
104
108
  :blog_articles,
105
109
  blog,
@@ -117,8 +121,8 @@ module Middleman
117
121
  )
118
122
  end
119
123
 
120
- if options.year_template ||
121
- options.month_template ||
124
+ if options.year_template ||
125
+ options.month_template ||
122
126
  options.day_template
123
127
 
124
128
  require 'middleman-blog/calendar_pages'
@@ -167,31 +171,31 @@ module Middleman
167
171
  # @param [String] tag
168
172
  # @return [String]
169
173
  def tag_path(tag)
170
- sitemap.find_resource_by_path(TagPages.link(self, tag)).try(:url)
174
+ sitemap.find_resource_by_path(TagPages.link(self.blog.options, tag)).try(:url)
171
175
  end
172
176
 
173
177
  # Get a path to the given year-based calendar page, based on the :year_link setting.
174
178
  # @param [Number] year
175
179
  # @return [String]
176
180
  def blog_year_path(year)
177
- sitemap.find_resource_by_path(CalendarPages.link(self, year)).try(:url)
181
+ sitemap.find_resource_by_path(CalendarPages.link(self.blog.options, year)).try(:url)
178
182
  end
179
183
 
180
184
  # Get a path to the given month-based calendar page, based on the :month_link setting.
181
- # @param [Number] year
185
+ # @param [Number] year
182
186
  # @param [Number] month
183
187
  # @return [String]
184
188
  def blog_month_path(year, month)
185
- sitemap.find_resource_by_path(CalendarPages.link(self, year, month)).try(:url)
189
+ sitemap.find_resource_by_path(CalendarPages.link(self.blog.options, year, month)).try(:url)
186
190
  end
187
191
 
188
192
  # Get a path to the given day-based calendar page, based on the :day_link setting.
189
- # @param [Number] year
193
+ # @param [Number] year
190
194
  # @param [Number] month
191
195
  # @param [Number] day
192
196
  # @return [String]
193
197
  def blog_day_path(year, month, day)
194
- sitemap.find_resource_by_path(CalendarPages.link(self, year, month, day)).try(:url)
198
+ sitemap.find_resource_by_path(CalendarPages.link(self.blog.options, year, month, day)).try(:url)
195
199
  end
196
200
 
197
201
 
@@ -0,0 +1,208 @@
1
+ module Middleman
2
+ class BlogExtension < Extension
3
+ self.supports_multiple_instances = true
4
+
5
+ option :name, nil, 'Unique ID for telling multiple blogs apart'
6
+ option :prefix, nil, 'Prefix to mount the blog at'
7
+ option :permalink, "/:year/:month/:day/:title.html", 'HTTP path to host articles at'
8
+ option :sources, ":year-:month-:day-:title.html", 'How to extract metadata from on-disk files'
9
+ option :taglink, "tags/:tag.html", 'HTTP path to host tag pages at'
10
+ option :layout, "layout", 'Article-specific layout'
11
+ option :summary_separator, /(READMORE)/, 'How to split article summaries around a delimeter'
12
+ option :summary_length, 250, 'Length of words in automatic summaries'
13
+ option :summary_generator, nil, 'Block to definte how summaries are extracted'
14
+ option :year_link, "/:year.html", 'HTTP path for yearly archives'
15
+ option :month_link, "/:year/:month.html", 'HTTP path for monthly archives'
16
+ option :day_link, "/:year/:month/:day.html", 'HTTP path for daily archives'
17
+ option :default_extension, ".markdown", 'Default article extension'
18
+ option :calendar_template, nil, 'Template for calendar pages'
19
+ option :year_template, nil, 'Template for yearly archive pages'
20
+ option :month_template, nil, 'Template for monthyl archive pages'
21
+ option :day_template, nil, 'Template for daily archive pages'
22
+ option :tag_template, nil, 'Template for tag archive pages'
23
+ option :paginate, false, 'Whether to paginate pages'
24
+ option :per_page, 10, 'Articles per page when paginating'
25
+ option :page_link, "page/:num", 'HTTP path for paging'
26
+ option :publish_future_dated, false, 'Whether to pubish articles dated in the future'
27
+
28
+ attr_accessor :data, :uid
29
+
30
+ def initialize(app, options_hash={}, &block)
31
+ super
32
+
33
+ @uid = options.name
34
+
35
+ require 'middleman-blog/blog_data'
36
+ require 'middleman-blog/blog_article'
37
+ require 'active_support/core_ext/time/zones'
38
+
39
+ # app.set :time_zone, 'UTC'
40
+
41
+ # optional: :tag_template
42
+ # optional: :year_template
43
+ # optional: :month_template
44
+ # optional: :day_template
45
+ # Allow one setting to set all the calendar templates
46
+ if options.calendar_template
47
+ options.year_template ||= options.calendar_template
48
+ options.month_template ||= options.calendar_template
49
+ options.day_template ||= options.calendar_template
50
+ end
51
+
52
+ # If "prefix" option is specified, all other paths are relative to it.
53
+ if options.prefix
54
+ options.prefix = "/#{options.prefix}" unless options.prefix.start_with? '/'
55
+ options.permalink = File.join(options.prefix, options.permalink)
56
+ options.sources = File.join(options.prefix, options.sources)
57
+ options.taglink = File.join(options.prefix, options.taglink)
58
+ options.year_link = File.join(options.prefix, options.year_link)
59
+ options.month_link = File.join(options.prefix, options.month_link)
60
+ options.day_link = File.join(options.prefix, options.day_link)
61
+ end
62
+ end
63
+
64
+ def after_configuration
65
+ @uid ||= "blog#{@app.blog_instances.keys.length}"
66
+
67
+ @app.ignore(options.calendar_template) if options.calendar_template
68
+ @app.ignore(options.year_template) if options.year_template
69
+ @app.ignore(options.month_template) if options.month_template
70
+ @app.ignore(options.day_template) if options.day_template
71
+
72
+ @app.blog_instances[@uid.to_sym] = self
73
+
74
+ # Make sure ActiveSupport's TimeZone stuff has something to work with,
75
+ # allowing people to set their desired time zone via Time.zone or
76
+ # set :time_zone
77
+ Time.zone = app.config[:time_zone] if app.config[:time_zone]
78
+ time_zone = Time.zone if Time.zone
79
+ zone_default = Time.find_zone!(time_zone || 'UTC')
80
+ unless zone_default
81
+ raise 'Value assigned to time_zone not recognized.'
82
+ end
83
+ Time.zone_default = zone_default
84
+
85
+ # Initialize blog with options
86
+
87
+ @data = ::Middleman::Blog::BlogData.new(@app, options, self)
88
+
89
+ @app.sitemap.register_resource_list_manipulator(
90
+ :"blog_#{uid}_articles",
91
+ @data,
92
+ false
93
+ )
94
+
95
+ if options.tag_template
96
+ @app.ignore options.tag_template
97
+
98
+ require 'middleman-blog/tag_pages'
99
+ @app.sitemap.register_resource_list_manipulator(
100
+ :"blog_#{uid}_tags",
101
+ ::Middleman::Blog::TagPages.new(@app, self),
102
+ false
103
+ )
104
+ end
105
+
106
+ if options.year_template || options.month_template || options.day_template
107
+ require 'middleman-blog/calendar_pages'
108
+ @app.sitemap.register_resource_list_manipulator(
109
+ :"blog_#{uid}_calendar",
110
+ ::Middleman::Blog::CalendarPages.new(@app, self),
111
+ false
112
+ )
113
+ end
114
+
115
+ if options.paginate
116
+ require 'middleman-blog/paginator'
117
+ @app.sitemap.register_resource_list_manipulator(
118
+ :"blog_#{uid}_paginate",
119
+ ::Middleman::Blog::Paginator.new(@app, self),
120
+ false
121
+ )
122
+ end
123
+ end
124
+
125
+ # Helpers for use within templates and layouts.
126
+ helpers do
127
+ def blog_instances
128
+ @blog_instances ||= {}
129
+ end
130
+
131
+ def blog_controller(key=nil)
132
+ key ||= (current_resource && current_resource.metadata[:page]["blog"]) || blog_instances.keys.first
133
+ blog_instances[key.to_sym]
134
+ end
135
+
136
+ def blog(key=nil)
137
+ blog_controller(key).data
138
+ end
139
+
140
+ # Determine whether the currently rendering template is a blog article.
141
+ # This can be useful in layouts.
142
+ # @return [Boolean]
143
+ def is_blog_article?
144
+ !current_article.nil?
145
+ end
146
+
147
+ # Get a {Resource} with mixed in {BlogArticle} methods representing the current article.
148
+ # @return [Middleman::Sitemap::Resource]
149
+ def current_article
150
+ blog_instances.each do |key, blog|
151
+ found = blog.data.article(current_resource.path)
152
+ return found if found
153
+ end
154
+
155
+ nil
156
+ end
157
+
158
+ # Get a path to the given tag, based on the :taglink setting.
159
+ # @param [String] tag
160
+ # @return [String]
161
+ def tag_path(tag, key=nil)
162
+ sitemap.find_resource_by_path(::Middleman::Blog::TagPages.link(blog_controller(key).options, tag)).try(:url)
163
+ end
164
+
165
+ # Get a path to the given year-based calendar page, based on the :year_link setting.
166
+ # @param [Number] year
167
+ # @return [String]
168
+ def blog_year_path(year, key=nil)
169
+ sitemap.find_resource_by_path(::Middleman::Blog::CalendarPages.link(blog_controller(key).options, year)).try(:url)
170
+ end
171
+
172
+ # Get a path to the given month-based calendar page, based on the :month_link setting.
173
+ # @param [Number] year
174
+ # @param [Number] month
175
+ # @return [String]
176
+ def blog_month_path(year, month, key=nil)
177
+ sitemap.find_resource_by_path(::Middleman::Blog::CalendarPages.link(blog_controller(key).options, year, month)).try(:url)
178
+ end
179
+
180
+ # Get a path to the given day-based calendar page, based on the :day_link setting.
181
+ # @param [Number] year
182
+ # @param [Number] month
183
+ # @param [Number] day
184
+ # @return [String]
185
+ def blog_day_path(year, month, day, key=nil)
186
+ sitemap.find_resource_by_path(::Middleman::Blog::CalendarPages.link(blog_controller(key).options, year, month, day)).try(:url)
187
+ end
188
+
189
+ # Pagination Helpers
190
+ # These are used by the template if pagination is off, to allow a single template to work
191
+ # in both modes. They get overridden by the local variables if the paginator is active.
192
+
193
+ # Returns true if pagination is turned on for this template; false otherwise.
194
+ # @return [Boolean]
195
+ def paginate; false; end
196
+
197
+ # Returns the list of articles to display on this page.
198
+ # @return [Array<Middleman::Sitemap::Resource>]
199
+ def page_articles(key=nil)
200
+ limit = (current_resource.metadata[:page]["per_page"] || 0) - 1
201
+
202
+ # "articles" local variable is populated by Calendar and Tag page generators
203
+ # If it's not set then use the complete list of articles
204
+ d = (current_resource.metadata[:locals]["articles"] || blog(key).articles)[0..limit]
205
+ end
206
+ end
207
+ end
208
+ end