cartoonist-blog 0.0.3.5 → 0.0.4
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.
- data/app/controllers/blog_admin_controller.rb +102 -0
- data/app/controllers/blog_controller.rb +58 -0
- data/app/helpers/blog_admin_helper.rb +21 -0
- data/app/helpers/blog_helper.rb +17 -0
- data/app/models/blog_feed.rb +21 -0
- data/app/models/blog_post.rb +187 -0
- data/app/views/blog/archives.html.erb +10 -0
- data/app/views/blog/feed.rss.erb +15 -0
- data/app/views/blog/show.html.erb +16 -0
- data/app/views/blog_admin/edit.html.erb +103 -0
- data/app/views/blog_admin/index.html.erb +23 -0
- data/app/views/blog_admin/new.html.erb +47 -0
- data/app/views/layouts/blog.html.erb +70 -0
- data/app/views/layouts/blog_admin.html.erb +10 -0
- data/cartoonist-blog.gemspec +3 -2
- data/config/locales/en.yml +32 -0
- data/db/migrate/20120308064117_create_blog_posts.rb +19 -0
- data/lib/cartoonist-blog/engine.rb +44 -0
- metadata +18 -2
@@ -0,0 +1,102 @@
|
|
1
|
+
class BlogAdminController < ApplicationController
|
2
|
+
helper :blog
|
3
|
+
before_filter :preview!, :only => [:preview]
|
4
|
+
before_filter :ensure_ssl!
|
5
|
+
before_filter :check_admin!
|
6
|
+
|
7
|
+
def preview
|
8
|
+
if params[:id].present?
|
9
|
+
begin
|
10
|
+
@post = BlogPost.preview_from_url_title params[:id]
|
11
|
+
rescue
|
12
|
+
redirect_to "/blog_admin/preview"
|
13
|
+
end
|
14
|
+
|
15
|
+
if @post.posted_at
|
16
|
+
@disabled_next = @post.newest_preview?
|
17
|
+
else
|
18
|
+
@disabled_next = true
|
19
|
+
end
|
20
|
+
else
|
21
|
+
@post = BlogPost.preview_current
|
22
|
+
@title = "Blog for #{Setting[:site_name]}"
|
23
|
+
@disabled_next = true
|
24
|
+
end
|
25
|
+
|
26
|
+
@disabled_prev = true if @post.oldest?
|
27
|
+
render "blog/show", :layout => "blog"
|
28
|
+
end
|
29
|
+
|
30
|
+
def preview_content
|
31
|
+
render :text => Markdown.render(params[:content]), :layout => false
|
32
|
+
end
|
33
|
+
|
34
|
+
def index
|
35
|
+
@unposted = BlogPost.unposted.chronological
|
36
|
+
@posted = BlogPost.posted.reversed
|
37
|
+
end
|
38
|
+
|
39
|
+
def create
|
40
|
+
url_title = BlogPost.url_titlize params[:title]
|
41
|
+
post = BlogPost.create :title => params[:title], :url_title => url_title, :content => params[:content], :author => session[:user], :tweet => tweet_message(url_title), :locked => true
|
42
|
+
redirect_to "/blog_admin/#{post.id}/edit"
|
43
|
+
end
|
44
|
+
|
45
|
+
def edit
|
46
|
+
@post = BlogPost.find params[:id].to_i
|
47
|
+
rescue ActiveRecord::RecordNotFound
|
48
|
+
redirect_to "/blog_admin/new"
|
49
|
+
end
|
50
|
+
|
51
|
+
def update
|
52
|
+
post = BlogPost.find params[:id].to_i
|
53
|
+
raise "Cannot update locked post!" if post.locked
|
54
|
+
original_tweet = post.tweet
|
55
|
+
original_url_title = post.url_title
|
56
|
+
post.title = params[:title]
|
57
|
+
post.url_title = BlogPost.url_titlize params[:title]
|
58
|
+
post.author = params[:author]
|
59
|
+
post.tweet = params[:tweet]
|
60
|
+
post.content = params[:content]
|
61
|
+
post.locked = true
|
62
|
+
|
63
|
+
if original_tweet == post.tweet && original_url_title != post.url_title && !post.tweeted?
|
64
|
+
post.tweet = tweet_message post.url_title
|
65
|
+
end
|
66
|
+
|
67
|
+
if params[:posted] && params[:posted_at_date].present?
|
68
|
+
time = "#{params[:posted_at_date]} #{params[:posted_at_hour]}:#{params[:posted_at_minute]} #{params[:posted_at_meridiem]}"
|
69
|
+
time = DateTime.parse time
|
70
|
+
time = Time.local time.year, time.month, time.day, time.hour, time.min
|
71
|
+
post.posted_at = time
|
72
|
+
elsif params[:posted]
|
73
|
+
post.posted_at = 1.hour.from_now
|
74
|
+
else
|
75
|
+
post.posted_at = nil
|
76
|
+
end
|
77
|
+
|
78
|
+
post.save!
|
79
|
+
redirect_to "/blog_admin/#{post.id}/edit"
|
80
|
+
end
|
81
|
+
|
82
|
+
def lock
|
83
|
+
post = BlogPost.find params[:id].to_i
|
84
|
+
post.locked = true
|
85
|
+
post.save!
|
86
|
+
redirect_to "/blog_admin/#{post.id}/edit"
|
87
|
+
end
|
88
|
+
|
89
|
+
def unlock
|
90
|
+
post = BlogPost.find params[:id].to_i
|
91
|
+
post.locked = false
|
92
|
+
post.save!
|
93
|
+
redirect_to "/blog_admin/#{post.id}/edit"
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
def tweet_message(url_title)
|
98
|
+
tweet = "New blog post: http://#{Setting[:domain]}/blog/#{url_title}"
|
99
|
+
tweet = "New blog post: http://#{Setting[:domain]}/blog" if tweet.length > 140
|
100
|
+
tweet
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class BlogController < ApplicationController
|
2
|
+
def archives
|
3
|
+
@posts = BlogPost.archives
|
4
|
+
render :layout => "page"
|
5
|
+
cache_page_as "blog/archives.#{cache_type}.tmp.html"
|
6
|
+
end
|
7
|
+
|
8
|
+
def show
|
9
|
+
@post = BlogPost.from_url_title params[:id]
|
10
|
+
@disabled_prev = @post.oldest?
|
11
|
+
@disabled_next = @post.newest?
|
12
|
+
render
|
13
|
+
cache_show_page
|
14
|
+
rescue
|
15
|
+
redirect_to "/blog"
|
16
|
+
end
|
17
|
+
|
18
|
+
def index
|
19
|
+
@post = BlogPost.current
|
20
|
+
@disabled_prev = true if @post.oldest?
|
21
|
+
@disabled_next = true
|
22
|
+
@title = "Blog for #{Setting[:site_name]}"
|
23
|
+
render :show
|
24
|
+
cache_page_as "blog.#{cache_type}.tmp.html"
|
25
|
+
end
|
26
|
+
|
27
|
+
def feed
|
28
|
+
respond_to do |format|
|
29
|
+
format.html { redirect_to "/blog/feed" }
|
30
|
+
|
31
|
+
format.rss do
|
32
|
+
@feed = feed_content
|
33
|
+
render :content_type => "application/xml"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def feed_content
|
40
|
+
result = blog_cache.read "blog-feed"
|
41
|
+
return result if result
|
42
|
+
result = BlogFeed.new BlogPost.feed
|
43
|
+
blog_cache.write "blog-feed", result
|
44
|
+
result
|
45
|
+
end
|
46
|
+
|
47
|
+
def blog_cache
|
48
|
+
@@blog_cache ||= ActiveSupport::Cache::MemoryStore.new(:expires_in => 2.hours)
|
49
|
+
end
|
50
|
+
|
51
|
+
def cache_show_page
|
52
|
+
if @disabled_next
|
53
|
+
cache_page_as "blog/#{@post.url_title}.#{cache_type}.tmp.html"
|
54
|
+
else
|
55
|
+
cache_page_as "blog/#{@post.url_title}.#{cache_type}.html"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module BlogAdminHelper
|
2
|
+
def lock_toggle_target
|
3
|
+
if @post.locked
|
4
|
+
"unlock"
|
5
|
+
else
|
6
|
+
"lock"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def lock_disabled
|
11
|
+
if @post.locked
|
12
|
+
'disabled="disabled"'.html_safe
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def format_posted_at(fmt)
|
17
|
+
if @post && @post.posted_at
|
18
|
+
@post.posted_at.localtime.strftime fmt
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module BlogHelper
|
2
|
+
def blog_current_url
|
3
|
+
if preview?
|
4
|
+
"/blog_admin/preview"
|
5
|
+
else
|
6
|
+
"/blog"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def blog_post_url(url_title)
|
11
|
+
if preview?
|
12
|
+
"/blog_admin/#{url_title}/preview"
|
13
|
+
else
|
14
|
+
"/blog/#{url_title}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class BlogFeed
|
2
|
+
attr_reader :pub_date, :items
|
3
|
+
|
4
|
+
def initialize(feed)
|
5
|
+
@pub_date = feed.first.posted_at.localtime.strftime "%a, %d %b %Y %H:%M:00 %z"
|
6
|
+
@items = feed.map do |item|
|
7
|
+
BlogFeed::Item.new item
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Item
|
12
|
+
attr_reader :title, :content, :url_title, :pub_date
|
13
|
+
|
14
|
+
def initialize(post)
|
15
|
+
@title = post.title
|
16
|
+
@content = Markdown.render post.content, false
|
17
|
+
@url_title = post.url_title
|
18
|
+
@pub_date = post.posted_at.localtime.strftime "%a, %d %b %Y %H:%M:00 %z"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
class BlogPost < ActiveRecord::Base
|
2
|
+
include Tweetable
|
3
|
+
attr_accessor :for_preview
|
4
|
+
|
5
|
+
def expected_tweet_time
|
6
|
+
posted_at
|
7
|
+
end
|
8
|
+
|
9
|
+
def formatted_posted_at(default_msg = "not yet posted")
|
10
|
+
if posted_at
|
11
|
+
posted_at.localtime.strftime "%-m/%-d/%Y at %-l:%M %P"
|
12
|
+
else
|
13
|
+
default_msg
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def first_post
|
18
|
+
return @first_post if @first_post_retrieved
|
19
|
+
@first_post_retrieved = true
|
20
|
+
@first_post ||= BlogPost.first_post
|
21
|
+
end
|
22
|
+
|
23
|
+
def first_url_title
|
24
|
+
first_post.url_title if first_post
|
25
|
+
end
|
26
|
+
|
27
|
+
def newest_post
|
28
|
+
return @newest_post if @newest_post_retrieved
|
29
|
+
@newest_post_retrieved = true
|
30
|
+
@newest_post ||= BlogPost.newest_post
|
31
|
+
end
|
32
|
+
|
33
|
+
def newest_preview_post
|
34
|
+
return @newest_preview_post if @newest_preview_post_retrieved
|
35
|
+
@newest_preview_post_retrieved = true
|
36
|
+
@newest_preview_post ||= BlogPost.newest_preview_post
|
37
|
+
end
|
38
|
+
|
39
|
+
def newest_id
|
40
|
+
newest_post.id if newest_post
|
41
|
+
end
|
42
|
+
|
43
|
+
def newest_preview_id
|
44
|
+
newest_preview_post.id if newest_preview_post
|
45
|
+
end
|
46
|
+
|
47
|
+
def oldest?
|
48
|
+
url_title == first_url_title
|
49
|
+
end
|
50
|
+
|
51
|
+
def newest?
|
52
|
+
id == newest_id
|
53
|
+
end
|
54
|
+
|
55
|
+
def newest_preview?
|
56
|
+
id == newest_preview_id
|
57
|
+
end
|
58
|
+
|
59
|
+
def previous_post
|
60
|
+
return @previous_post if @previous_post_retrieved
|
61
|
+
|
62
|
+
if posted_at
|
63
|
+
@previous_post_retrieved = true
|
64
|
+
@previous_post ||= BlogPost.previous_post(self)
|
65
|
+
elsif for_preview
|
66
|
+
@previous_post_retrieved = true
|
67
|
+
@previous_post ||= BlogPost.preview_current
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def next_post
|
72
|
+
return @next_post if @next_post_retrieved
|
73
|
+
|
74
|
+
if posted_at
|
75
|
+
@next_post_retrieved = true
|
76
|
+
@next_post ||= BlogPost.next_post(self)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def prev_url_title
|
81
|
+
previous_post.url_title if previous_post
|
82
|
+
end
|
83
|
+
|
84
|
+
def next_url_title
|
85
|
+
next_post.url_title if next_post
|
86
|
+
end
|
87
|
+
|
88
|
+
def real?
|
89
|
+
url_title
|
90
|
+
end
|
91
|
+
|
92
|
+
def absolute_url
|
93
|
+
"http://#{Setting[:domain]}/blog/#{url_title}"
|
94
|
+
end
|
95
|
+
|
96
|
+
class << self
|
97
|
+
def url_titlize(title)
|
98
|
+
title.downcase.gsub(" ", "-").gsub(/[^-_a-z0-9]/, "")
|
99
|
+
end
|
100
|
+
|
101
|
+
def newest_preview_post
|
102
|
+
reversed.first || new(:title => "No Posts Yet", :content => "There are no blog posts yet.")
|
103
|
+
end
|
104
|
+
|
105
|
+
def newest_post
|
106
|
+
posted.reversed.first || new(:title => "No Posts Yet", :content => "There are no blog posts yet.")
|
107
|
+
end
|
108
|
+
|
109
|
+
def first_post
|
110
|
+
posted.chronological.first || new(:title => "No Posts Yet", :content => "There are no blog posts yet.")
|
111
|
+
end
|
112
|
+
|
113
|
+
def posted
|
114
|
+
where "blog_posts.posted_at IS NOT NULL AND blog_posts.posted_at <= ?", Time.now
|
115
|
+
end
|
116
|
+
|
117
|
+
def unposted
|
118
|
+
where "blog_posts.posted_at IS NULL OR blog_posts.posted_at > ?", Time.now
|
119
|
+
end
|
120
|
+
|
121
|
+
def chronological
|
122
|
+
order "blog_posts.posted_at ASC"
|
123
|
+
end
|
124
|
+
|
125
|
+
def reversed
|
126
|
+
order "blog_posts.posted_at DESC"
|
127
|
+
end
|
128
|
+
|
129
|
+
def all_columns
|
130
|
+
select "blog_posts.*"
|
131
|
+
end
|
132
|
+
|
133
|
+
def current
|
134
|
+
post = posted.reversed.first
|
135
|
+
post = new :title => "No Posts Yet", :content => "There are no blog posts yet." unless post
|
136
|
+
post
|
137
|
+
end
|
138
|
+
|
139
|
+
def preview_current
|
140
|
+
post = reversed.first
|
141
|
+
post = new :title => "No Posts Yet", :content => "There are no blog posts yet." unless post
|
142
|
+
post.for_preview = true
|
143
|
+
post
|
144
|
+
end
|
145
|
+
|
146
|
+
def previous_post(post)
|
147
|
+
context = BlogPost
|
148
|
+
context = posted unless post.for_preview
|
149
|
+
context.where("blog_posts.posted_at < ?", post.posted_at).reversed.first
|
150
|
+
end
|
151
|
+
|
152
|
+
def next_post(post)
|
153
|
+
context = BlogPost
|
154
|
+
context = posted unless post.for_preview
|
155
|
+
context.where("blog_posts.posted_at > ?", post.posted_at).chronological.first
|
156
|
+
end
|
157
|
+
|
158
|
+
def from_url_title(url_title)
|
159
|
+
post = posted.where(:url_title => url_title).first
|
160
|
+
raise ActiveRecord::RecordNotFound.new("No records found!") unless post
|
161
|
+
post
|
162
|
+
end
|
163
|
+
|
164
|
+
def preview_from_url_title(url_title)
|
165
|
+
post = where(:url_title => url_title).first
|
166
|
+
raise ActiveRecord::RecordNotFound.new("No records found!") unless post
|
167
|
+
post.for_preview = true
|
168
|
+
post
|
169
|
+
end
|
170
|
+
|
171
|
+
def archives
|
172
|
+
posted.reversed.select([:url_title, :title, :posted_at]).all
|
173
|
+
end
|
174
|
+
|
175
|
+
def untweeted
|
176
|
+
posted.where(:tweeted_at => nil).all
|
177
|
+
end
|
178
|
+
|
179
|
+
def feed
|
180
|
+
posted.reversed.take 10
|
181
|
+
end
|
182
|
+
|
183
|
+
def sitemap
|
184
|
+
posted.reversed.all
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<% content_for(:title, "Blog Archives for #{Setting[:site_name]}") %>
|
2
|
+
|
3
|
+
<ul>
|
4
|
+
<% @posts.each do |post| %>
|
5
|
+
<li>
|
6
|
+
<%= post.posted_at.localtime.strftime "%m/%d/%Y" %>:
|
7
|
+
<a href="/blog/<%= post.url_title %>"><%= post.title %></a>
|
8
|
+
</li>
|
9
|
+
<% end %>
|
10
|
+
</ul>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% content_for :rss_title, "#{Setting[:site_name]} Blog" %>
|
2
|
+
<% content_for :pub_date, @feed.pub_date %>
|
3
|
+
|
4
|
+
<% @feed.items.each do |item| %>
|
5
|
+
<item>
|
6
|
+
<title><%= item.title %></title>
|
7
|
+
<description>
|
8
|
+
<%= "<h1>#{h item.title}</h1>" %>
|
9
|
+
<%= item.content %>
|
10
|
+
</description>
|
11
|
+
<link>http://<%= Setting[:domain] %>/blog/<%= item.url_title %></link>
|
12
|
+
<guid>http://<%= Setting[:domain] %>/blog/<%= item.url_title %></guid>
|
13
|
+
<pubDate><%= item.pub_date %></pubDate>
|
14
|
+
</item>
|
15
|
+
<% end %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<% content_for(:title, @title || @post.title) %>
|
2
|
+
<% content_for :post_date, @post.formatted_posted_at %>
|
3
|
+
<% content_for :first, @post.first_url_title %>
|
4
|
+
<% content_for :prev, @post.prev_url_title %>
|
5
|
+
<% content_for :next, @post.next_url_title %>
|
6
|
+
<% enable_disqus! :path => "blog/#{@post.url_title}", :title => "#{@post.title}", :category => Setting[:disqus_blog_post_category] %>
|
7
|
+
|
8
|
+
<div class="blog-post">
|
9
|
+
<h1 class="title"><a href="/blog/<%= @post.url_title %>"><%= @post.title %></a></h1>
|
10
|
+
<h2 class="posted-date">Posted on <%= @post.formatted_posted_at %></h2>
|
11
|
+
<h2 class="byline">by <%= @post.author %></h2>
|
12
|
+
|
13
|
+
<div class="blog-post-content">
|
14
|
+
<%= markdown @post.content %>
|
15
|
+
</div>
|
16
|
+
</div>
|
@@ -0,0 +1,103 @@
|
|
1
|
+
<p>
|
2
|
+
<a href="/blog_admin/<%= @post.url_title %>/preview">Preview this post</a>
|
3
|
+
</p>
|
4
|
+
|
5
|
+
<p>
|
6
|
+
<%= form_tag "/blog_admin/#{@post.id}/#{lock_toggle_target}", :method => :post do %>
|
7
|
+
<input type="submit" value="<%= lock_toggle_target %>" />
|
8
|
+
<% end %>
|
9
|
+
</p>
|
10
|
+
|
11
|
+
<%= form_tag "/blog_admin/#{@post.id}", :method => :put do %>
|
12
|
+
<p>
|
13
|
+
<label><input type="checkbox" name="posted" value="true" <%= checked="checked".html_safe if @post.posted_at %> <%= lock_disabled %> />Posted at</label>
|
14
|
+
<input type="text" name="posted_at_date" value="<%= format_posted_at "%Y-%m-%d" %>" <%= lock_disabled %> />
|
15
|
+
<select name="posted_at_hour" <%= lock_disabled %>>
|
16
|
+
<% 1.upto 12 do |h| %>
|
17
|
+
<option value="<%= h %>" <%= selected h, format_posted_at("%-l").to_i %>><%= h %></option>
|
18
|
+
<% end %>
|
19
|
+
</select>
|
20
|
+
<select name="posted_at_minute" <%= lock_disabled %>>
|
21
|
+
<% 0.upto 60 do |m| %>
|
22
|
+
<option value="<%= m %>" <%= selected m, format_posted_at("%-M").to_i %>><%= m %></option>
|
23
|
+
<% end %>
|
24
|
+
</select>
|
25
|
+
<select name="posted_at_meridiem" <%= lock_disabled %>>
|
26
|
+
<option value="am" <%= selected "am", format_posted_at("%P") %>>am</option>
|
27
|
+
<option value="pm" <%= selected "pm", format_posted_at("%P") %>>pm</option>
|
28
|
+
</select>
|
29
|
+
</p>
|
30
|
+
|
31
|
+
<p>
|
32
|
+
URL Title: <%= @post.url_title %>
|
33
|
+
</p>
|
34
|
+
|
35
|
+
<p>
|
36
|
+
Title:
|
37
|
+
<input type="text" name="title" size="100" value="<%= @post.title %>" <%= lock_disabled %> />
|
38
|
+
</p>
|
39
|
+
|
40
|
+
<p>
|
41
|
+
Author:
|
42
|
+
<input type="text" name="author" size="20" value="<%= @post.author %>" <%= lock_disabled %> />
|
43
|
+
</p>
|
44
|
+
|
45
|
+
<p>
|
46
|
+
Tweet:
|
47
|
+
<% if @post.tweeted_at %>
|
48
|
+
<em>(sent <%= @post.tweeted_at.strftime "%-m/%-d/%Y %-l:%M %P" %>)</em>
|
49
|
+
<% end %>
|
50
|
+
<br />
|
51
|
+
<textarea name="tweet" rows="2" cols="100" tabindex="5" <%= lock_disabled %>><%= @post.tweet %></textarea>
|
52
|
+
</p>
|
53
|
+
|
54
|
+
<p>
|
55
|
+
<input type="submit" value="Save" <%= lock_disabled %> />
|
56
|
+
<input type="button" value="Preview" class="preview-content" />
|
57
|
+
</p>
|
58
|
+
|
59
|
+
<p>
|
60
|
+
Content:<br />
|
61
|
+
<textarea name="content" rows="20" cols="100" <%= lock_disabled %>><%= @post.content %></textarea><br />
|
62
|
+
</p>
|
63
|
+
|
64
|
+
<p>
|
65
|
+
<input type="submit" value="Save" <%= lock_disabled %> />
|
66
|
+
<input type="button" value="Preview" class="preview-content" />
|
67
|
+
</p>
|
68
|
+
<% end %>
|
69
|
+
|
70
|
+
<hr />
|
71
|
+
|
72
|
+
<div class="preview-content">
|
73
|
+
</div>
|
74
|
+
|
75
|
+
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" %>
|
76
|
+
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js" %>
|
77
|
+
<%= stylesheet_link_tag "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.17/themes/base/jquery-ui.css" %>
|
78
|
+
<%= javascript_tag do %>
|
79
|
+
$(function() {
|
80
|
+
$("input[name='posted_at_date']").datepicker({ dateFormat: "yy-mm-dd" });
|
81
|
+
$(".preview-content").click(function() {
|
82
|
+
var $this = $(this).attr("disabled", "disabled");
|
83
|
+
$.ajax({
|
84
|
+
url: "/blog_admin/preview_content",
|
85
|
+
type: "post",
|
86
|
+
data: {
|
87
|
+
authenticity_token: $("form input[name='authenticity_token']").val(),
|
88
|
+
content: $("textarea[name='content']").val()
|
89
|
+
},
|
90
|
+
dataType: "text",
|
91
|
+
success: function(text) {
|
92
|
+
$(".preview-content").html(text);
|
93
|
+
$this.removeAttr("disabled");
|
94
|
+
},
|
95
|
+
error: function() {
|
96
|
+
$(".preview-content").html('<div style="color: red;">There was an error.</div>');
|
97
|
+
$this.removeAttr("disabled");
|
98
|
+
}
|
99
|
+
});
|
100
|
+
return false;
|
101
|
+
});
|
102
|
+
});
|
103
|
+
<% end %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<h2><%= t "admin.blog.index.not_posted" %></h2>
|
2
|
+
|
3
|
+
<ul>
|
4
|
+
<% @unposted.each do |post| %>
|
5
|
+
<li>
|
6
|
+
<%= post.formatted_posted_at "" %>
|
7
|
+
<a href="/blog_admin/<%= post.id %>/edit"><%= post.title %></a>
|
8
|
+
(<a href="/blog_admin/<%= post.url_title %>/preview"><%= t "admin.blog.index.preview" %></a>)
|
9
|
+
</li>
|
10
|
+
<% end %>
|
11
|
+
</ul>
|
12
|
+
|
13
|
+
<h2><%= t "admin.blog.index.posted" %></h2>
|
14
|
+
|
15
|
+
<ul>
|
16
|
+
<% @posted.each do |post| %>
|
17
|
+
<li>
|
18
|
+
<%= post.formatted_posted_at "" %>
|
19
|
+
<a href="/blog_admin/<%= post.id %>/edit"><%= post.title %></a>
|
20
|
+
(<a href="/blog_admin/<%= post.url_title %>/preview"><%= t "admin.blog.index.preview" %></a>)
|
21
|
+
</li>
|
22
|
+
<% end %>
|
23
|
+
</ul>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<%= form_tag "/blog_admin", :method => :post do %>
|
2
|
+
<p>
|
3
|
+
Title: <input type="text" name="title" autofocus="autofocus" size="100" /><br />
|
4
|
+
</p>
|
5
|
+
|
6
|
+
<p>
|
7
|
+
Content:<br />
|
8
|
+
<textarea name="content" rows="20" cols="100"></textarea><br />
|
9
|
+
</p>
|
10
|
+
|
11
|
+
<p>
|
12
|
+
<input type="submit" value="Save" />
|
13
|
+
<input type="button" value="Preview" class="preview-content" />
|
14
|
+
</p>
|
15
|
+
<% end %>
|
16
|
+
|
17
|
+
<hr />
|
18
|
+
|
19
|
+
<div class="preview-content">
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<%= javascript_include_tag "https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" %>
|
23
|
+
<%= javascript_tag do %>
|
24
|
+
$(function() {
|
25
|
+
$(".preview-content").click(function() {
|
26
|
+
var $this = $(this).attr("disabled", "disabled");
|
27
|
+
$.ajax({
|
28
|
+
url: "/blog_admin/preview_content",
|
29
|
+
type: "post",
|
30
|
+
data: {
|
31
|
+
authenticity_token: $("form input[name='authenticity_token']").val(),
|
32
|
+
content: $("textarea[name='content']").val()
|
33
|
+
},
|
34
|
+
dataType: "text",
|
35
|
+
success: function(text) {
|
36
|
+
$(".preview-content").html(text);
|
37
|
+
$this.removeAttr("disabled");
|
38
|
+
},
|
39
|
+
error: function() {
|
40
|
+
$(".preview-content").html('<div style="color: red;">There was an error.</div>');
|
41
|
+
$this.removeAttr("disabled");
|
42
|
+
}
|
43
|
+
});
|
44
|
+
return false;
|
45
|
+
});
|
46
|
+
});
|
47
|
+
<% end %>
|
@@ -0,0 +1,70 @@
|
|
1
|
+
<% content_for :content_class, "blog-content" %>
|
2
|
+
<% licensed! %>
|
3
|
+
<% rss! "/blog/feed", t("blog.layout.rss_title", :site_name => Setting[:site_name]) %>
|
4
|
+
|
5
|
+
<% content_for :small_buttons do %>
|
6
|
+
<% if @post.real? %>
|
7
|
+
<a class="facebook" href="https://www.facebook.com/sharer.php?u=<%= u @post.absolute_url %>&t=<%= u t("blog.layout.facebook_text_message", :title => @post.title) %>" title="<%= t "blog.layout.facebook_title" %>"><%= t "blog.layout.facebook" %></a>
|
8
|
+
<a class="twitter" href="https://twitter.com/intent/tweet?source=<%= u Setting[:domain] %>&text=<%= u t("blog.layout.twitter_text_message", :url => @post.absolute_url) %>" title="<%= t "blog.layout.twitter_title" %>"><%= t "blog.layout.twitter" %></a>
|
9
|
+
<a class="google-plus" href="https://plus.google.com/share?url=<%= u @post.absolute_url %>" title="<%= t "blog.layout.google_plus_title" %>"><%= t "blog.layout.google_plus" %></a>
|
10
|
+
<a class="rss" href="<%= rss_path %>" title="<%= rss_title %>"><%= t "blog.layout.rss" %></a>
|
11
|
+
<% end %>
|
12
|
+
<% end %>
|
13
|
+
|
14
|
+
<% content_for :content do %>
|
15
|
+
<div class="blog-page">
|
16
|
+
<div class="nav-container">
|
17
|
+
<div class="nav">
|
18
|
+
<% if @disabled_prev %>
|
19
|
+
<a class="first-disabled">first</a>
|
20
|
+
<a class="prev-disabled">prev</a>
|
21
|
+
<% else %>
|
22
|
+
<a class="first" href="<%= blog_post_url yield(:first) %>">first</a>
|
23
|
+
<a class="prev" href="<%= blog_post_url yield(:prev) %>">prev</a>
|
24
|
+
<% end %>
|
25
|
+
<a class="archives" href="/blog/archives">archives</a>
|
26
|
+
<% if @disabled_next %>
|
27
|
+
<a class="next-disabled">next</a>
|
28
|
+
<a class="last-disabled">last</a>
|
29
|
+
<% else %>
|
30
|
+
<a class="next" href="<%= blog_post_url yield(:next) %>">next</a>
|
31
|
+
<a class="last" href="<%= blog_current_url %>">last</a>
|
32
|
+
<% end %>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
|
36
|
+
<%= yield %>
|
37
|
+
|
38
|
+
<div class="nav-container">
|
39
|
+
<div class="nav">
|
40
|
+
<% if @disabled_prev %>
|
41
|
+
<a class="first-disabled">first</a>
|
42
|
+
<a class="prev-disabled">prev</a>
|
43
|
+
<% else %>
|
44
|
+
<a class="first" href="<%= blog_post_url yield(:first) %>">first</a>
|
45
|
+
<a class="prev" href="<%= blog_post_url yield(:prev) %>">prev</a>
|
46
|
+
<% end %>
|
47
|
+
<a class="archives" href="/blog/archives">archives</a>
|
48
|
+
<% if @disabled_next %>
|
49
|
+
<a class="next-disabled">next</a>
|
50
|
+
<a class="last-disabled">last</a>
|
51
|
+
<% else %>
|
52
|
+
<a class="next" href="<%= blog_post_url yield(:next) %>">next</a>
|
53
|
+
<a class="last" href="<%= blog_current_url %>">last</a>
|
54
|
+
<% end %>
|
55
|
+
</div>
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
<% end %>
|
59
|
+
|
60
|
+
<% content_for :post_date_content do %>
|
61
|
+
<p class="posted-date">Posted on <%= yield :post_date %></p>
|
62
|
+
<% end %>
|
63
|
+
|
64
|
+
<% content_for :admin_content do %>
|
65
|
+
<% if preview? %>
|
66
|
+
<p><a href="/admin/main">admin</a></p>
|
67
|
+
<% end %>
|
68
|
+
<% end %>
|
69
|
+
|
70
|
+
<%= render :template => "layouts/application" %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<% content_for :subtabs do %>
|
2
|
+
<a class="subtab" href="/blog"><%= t "admin.blog.layout.latest" %></a>
|
3
|
+
<a class="subtab" href="/blog_admin"><%= t "admin.blog.layout.list" %></a>
|
4
|
+
<a class="subtab" href="/blog_admin/new"><%= t "admin.blog.layout.new" %></a>
|
5
|
+
<a class="subtab" href="/blog_admin/preview"><%= t "admin.blog.layout.preview" %></a>
|
6
|
+
<% end %>
|
7
|
+
|
8
|
+
<% content_for :page_title, t("admin.blog.layout.section") %>
|
9
|
+
<% content_for(:content) { yield } %>
|
10
|
+
<%= render :template => "layouts/admin" %>
|
data/cartoonist-blog.gemspec
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "cartoonist-blog"
|
3
|
-
|
4
|
-
s.
|
3
|
+
raise "Cannot find version file!" unless File.exists?(File.join(File.dirname(__FILE__), "../CARTOONIST_VERSION"))
|
4
|
+
s.version = File.read File.join(File.dirname(__FILE__), "../CARTOONIST_VERSION")
|
5
|
+
s.date = Time.now.strftime "%Y-%m-%d"
|
5
6
|
s.summary = "Cartoonist Blog"
|
6
7
|
s.description = "This core plugin for Cartoonist adds a simple blog."
|
7
8
|
s.authors = ["Mike Virata-Stone"]
|
@@ -0,0 +1,32 @@
|
|
1
|
+
en:
|
2
|
+
admin:
|
3
|
+
blog:
|
4
|
+
index:
|
5
|
+
not_posted: Not yet posted
|
6
|
+
posted: Posted
|
7
|
+
preview: preview
|
8
|
+
layout:
|
9
|
+
latest: View Latest
|
10
|
+
list: List
|
11
|
+
new: New Post
|
12
|
+
preview: Preview
|
13
|
+
section: Blog
|
14
|
+
layout:
|
15
|
+
tab:
|
16
|
+
blog: Blog
|
17
|
+
application:
|
18
|
+
layout:
|
19
|
+
navigation:
|
20
|
+
blog: Blog
|
21
|
+
blog:
|
22
|
+
layout:
|
23
|
+
facebook: Facebook
|
24
|
+
facebook_text_message: "Check this out: %{title}"
|
25
|
+
facebook_title: Share this on Facebook
|
26
|
+
google_plus: Google Plus
|
27
|
+
google_plus_title: Post this to Google Plus
|
28
|
+
rss: RSS
|
29
|
+
rss_title: RSS Feed for the %{site_name} blog
|
30
|
+
twitter: Twitter
|
31
|
+
twitter_text_message: "Check this out: %{url}"
|
32
|
+
twitter_title: Tweet about this
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class CreateBlogPosts < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :blog_posts do |t|
|
4
|
+
t.string :title, :null => false
|
5
|
+
t.string :url_title, :null => false
|
6
|
+
t.string :author, :null => false
|
7
|
+
t.datetime :posted_at
|
8
|
+
t.text :content, :null => false
|
9
|
+
t.string :tweet, :null => false, :length => 140
|
10
|
+
t.datetime :tweeted_at
|
11
|
+
t.boolean :locked, :null => false, :default => false
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
|
15
|
+
add_index :blog_posts, :title, :unique => true
|
16
|
+
add_index :blog_posts, :url_title, :unique => true
|
17
|
+
add_index :blog_posts, :posted_at
|
18
|
+
end
|
19
|
+
end
|
@@ -1,4 +1,48 @@
|
|
1
1
|
module CartoonistBlog
|
2
2
|
class Engine < ::Rails::Engine
|
3
|
+
Cartoonist::Admin::Tab.add :blog, :url => "/blog_admin", :order => 1
|
4
|
+
Cartoonist::Navigation::Link.add :url => "/blog", :preview_url => "/blog_admin/preview", :class => "blog", :label => "application.layout.navigation.blog", :order => 1
|
5
|
+
Cartoonist::Migration.add_for self
|
6
|
+
|
7
|
+
Cartoonist::Backup.for :blog_posts do
|
8
|
+
BlogPost.order(:id).all
|
9
|
+
end
|
10
|
+
|
11
|
+
Cartoonist::Sitemap.add do
|
12
|
+
posts = BlogPost.sitemap
|
13
|
+
|
14
|
+
result = posts.map do |post|
|
15
|
+
SitemapEntry.new "/blog/#{post.url_title}", post.posted_at, :never
|
16
|
+
end
|
17
|
+
|
18
|
+
unless result.empty?
|
19
|
+
first = posts.first
|
20
|
+
result << SitemapEntry.new("/blog", first.posted_at, :weekly, "0.9")
|
21
|
+
end
|
22
|
+
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
Cartoonist::Routes.add do
|
27
|
+
resources :blog do
|
28
|
+
collection do
|
29
|
+
get "archives"
|
30
|
+
get "feed", :defaults => { :format => "rss" }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
resources :blog_admin do
|
35
|
+
member do
|
36
|
+
post "lock"
|
37
|
+
get "preview"
|
38
|
+
post "unlock"
|
39
|
+
end
|
40
|
+
|
41
|
+
collection do
|
42
|
+
get "preview"
|
43
|
+
post "preview_content"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
3
47
|
end
|
4
48
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cartoonist-blog
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-04-
|
12
|
+
date: 2012-04-16 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: This core plugin for Cartoonist adds a simple blog.
|
15
15
|
email: reasonnumber@gmail.com
|
@@ -18,7 +18,23 @@ extensions: []
|
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
20
|
- .gitignore
|
21
|
+
- app/controllers/blog_admin_controller.rb
|
22
|
+
- app/controllers/blog_controller.rb
|
23
|
+
- app/helpers/blog_admin_helper.rb
|
24
|
+
- app/helpers/blog_helper.rb
|
25
|
+
- app/models/blog_feed.rb
|
26
|
+
- app/models/blog_post.rb
|
27
|
+
- app/views/blog/archives.html.erb
|
28
|
+
- app/views/blog/feed.rss.erb
|
29
|
+
- app/views/blog/show.html.erb
|
30
|
+
- app/views/blog_admin/edit.html.erb
|
31
|
+
- app/views/blog_admin/index.html.erb
|
32
|
+
- app/views/blog_admin/new.html.erb
|
33
|
+
- app/views/layouts/blog.html.erb
|
34
|
+
- app/views/layouts/blog_admin.html.erb
|
21
35
|
- cartoonist-blog.gemspec
|
36
|
+
- config/locales/en.yml
|
37
|
+
- db/migrate/20120308064117_create_blog_posts.rb
|
22
38
|
- lib/cartoonist-blog.rb
|
23
39
|
- lib/cartoonist-blog/engine.rb
|
24
40
|
homepage: http://reasonnumber.com/cartoonist
|