cartoonist-blog 0.0.3.5 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|