monologue 0.1.3 → 0.2.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. data/README.md +29 -21
  2. data/app/assets/javascripts/monologue/blog/twitter.js.coffee +32 -0
  3. data/app/assets/stylesheets/monologue/blog/application.css +3 -3
  4. data/app/assets/stylesheets/monologue/blog/monologue.css +150 -7
  5. data/app/controllers/monologue/admin/cache_controller.rb +27 -0
  6. data/app/controllers/monologue/admin/posts_controller.rb +28 -12
  7. data/app/controllers/monologue/admin/sessions_controller.rb +2 -2
  8. data/app/controllers/monologue/admin/users_controller.rb +13 -0
  9. data/app/controllers/monologue/application_controller.rb +22 -6
  10. data/app/controllers/monologue/posts_controller.rb +7 -7
  11. data/app/controllers/monologue/tags_controller.rb +12 -0
  12. data/app/helpers/monologue/application_helper.rb +76 -0
  13. data/app/helpers/monologue/tags_helper.rb +5 -0
  14. data/app/models/monologue/post.rb +43 -29
  15. data/app/models/monologue/posts_revision.rb +50 -52
  16. data/app/models/monologue/tag.rb +16 -0
  17. data/app/models/monologue/tagging.rb +4 -0
  18. data/app/models/monologue/user.rb +1 -0
  19. data/app/sweepers/monologue/posts_sweeper.rb +20 -4
  20. data/app/sweepers/monologue/total_sweeper.rb +5 -0
  21. data/app/views/layouts/monologue/admin/_nav_bar.html.erb +17 -6
  22. data/app/views/layouts/monologue/application.html.erb +15 -20
  23. data/app/views/layouts/monologue/application/_disqus.html.erb +18 -0
  24. data/app/views/layouts/monologue/application/_disqus_embed.html.erb +17 -0
  25. data/app/views/layouts/monologue/application/_fb_open_graph.html.erb +4 -1
  26. data/app/views/layouts/monologue/application/_gauge_analytics.html.erb +15 -0
  27. data/app/views/layouts/monologue/application/_google_analytics.html.erb +1 -1
  28. data/app/views/layouts/monologue/application/_head.html.erb +3 -2
  29. data/app/views/layouts/monologue/application/_sidebar.html.erb +5 -0
  30. data/app/views/layouts/monologue/application/_social_icons.html.erb +5 -0
  31. data/app/views/layouts/monologue/application/_twitter_cards.html.erb +7 -0
  32. data/app/views/monologue/admin/cache/_config.html.erb +18 -0
  33. data/app/views/monologue/admin/cache/how_to_enable.html.erb +6 -0
  34. data/app/views/monologue/admin/cache/show.html.erb +26 -0
  35. data/app/views/monologue/admin/posts/_form.html.erb +3 -2
  36. data/app/views/monologue/admin/posts/edit.html.erb +1 -1
  37. data/app/views/monologue/admin/posts/index.html.erb +1 -1
  38. data/app/views/monologue/admin/users/edit.html.erb +9 -0
  39. data/app/views/monologue/posts/_post.html.erb +14 -0
  40. data/app/views/monologue/posts/_revision_header.html.erb +9 -0
  41. data/app/views/monologue/posts/_social_sharing.html.erb +45 -36
  42. data/app/views/monologue/posts/index.html.erb +4 -17
  43. data/app/views/monologue/posts/show.html.erb +11 -24
  44. data/app/views/monologue/sidebar/_categories.html.erb +7 -0
  45. data/app/views/monologue/sidebar/_latest_posts.html.erb +7 -0
  46. data/app/views/monologue/sidebar/_latest_tweets.html.erb +8 -0
  47. data/app/views/monologue/sidebar/_tag_cloud.html.erb +5 -0
  48. data/app/views/monologue/tags/_tag.html.erb +1 -0
  49. data/app/views/monologue/tags/show.html.erb +4 -0
  50. data/config/locales/en.yml +54 -10
  51. data/config/locales/fr.yml +55 -11
  52. data/config/routes.rb +8 -2
  53. data/db/migrate/20120514164158_create_monologue_tags.rb +8 -0
  54. data/db/migrate/20120514194459_join_posts_and_tags.rb +7 -0
  55. data/db/migrate/20120604010152_rename_post_tags_table.rb +5 -0
  56. data/db/migrate/20120612013442_create_taggings.rb +11 -0
  57. data/db/migrate/20120612015727_delete_join_posts_tags.rb +11 -0
  58. data/db/migrate/20120612020023_add_index_to_tag_name.rb +5 -0
  59. data/deprecations.rb +10 -0
  60. data/lib/monologue.rb +20 -1
  61. data/lib/monologue/engine.rb +12 -1
  62. data/lib/monologue/version.rb +1 -1
  63. data/lib/tasks/monologue_cache.rake +26 -0
  64. data/vendor/assets/fonts/monologue/foundation_icons/social_foundicons.eot +0 -0
  65. data/vendor/assets/fonts/monologue/foundation_icons/social_foundicons.svg +15 -0
  66. data/vendor/assets/fonts/monologue/foundation_icons/social_foundicons.ttf +0 -0
  67. data/vendor/assets/fonts/monologue/foundation_icons/social_foundicons.woff +0 -0
  68. data/vendor/assets/javascripts/monologue/bootstrap/bootstrap.min.js +6 -1
  69. data/vendor/assets/stylesheets/monologue/bootstrap/bootstrap-responsive.min.css +9 -3
  70. data/vendor/assets/stylesheets/monologue/bootstrap/bootstrap.min.css +9 -610
  71. data/vendor/assets/stylesheets/monologue/foundation_icons/social_foundicons.css.erb +148 -0
  72. metadata +109 -10
  73. data/app/helpers/monologue/admin/admin_helper.rb +0 -4
  74. data/app/helpers/monologue/posts_helper.rb +0 -4
  75. data/app/helpers/monologue/sessions_helper.rb +0 -6
  76. data/lib/tasks/monologue_tasks.rake +0 -4
data/README.md CHANGED
@@ -4,20 +4,30 @@ Monologue is a basic mountable blogging engine in Rails built to be easily mount
4
4
  [![Build Status](https://secure.travis-ci.org/jipiboily/monologue.png)](http://travis-ci.org/jipiboily/monologue)
5
5
 
6
6
 
7
- ## Features
8
- - Rails mountable engine (fully named spaced)
7
+ ## Questions? Problems? Documentation?
8
+
9
+ [Questions here please](http://groups.google.com/forum/#!forum/monologue-rb)
10
+ [Issues and bugs](http://github.com/jipiboily/monologue/issues)
11
+ [Wiki](https://github.com/jipiboily/monologue/wiki/_pages)
12
+
13
+ ## Here are a few features
14
+ - Rails mountable engine (fully named spaced and mountable in an already existing app)
9
15
  - tested
10
16
  - back to basics: few features
11
17
  - it has post revisions (no UI to choose published revision yet, but it keeps your modification history)
18
+ - tags (or categories)
19
+ - RSS
20
+ - support for Google Analytics and Gaug.es tags
12
21
  - few external dependencies (no Devise or Sorcery, etc…) so we don't face problem integrating with existing Rails app.([Rails mountable engines: dependency nightmare?](http://jipiboily.com/2012/rails-mountable-engines-dependency-nightmare))
13
- - comments handled by disqus
14
- - enforcing [Rails cache](http://edgeguides.rubyonrails.org/caching_with_rails.html) for better performance (only support file store for now)
15
- - runs on Heroku
22
+ - comments are handled by [disqus](http://disqus.com/)
23
+ - enforcing [Rails cache](http://edgeguides.rubyonrails.org/caching_with_rails.html) for better performance (only support file store for now). [Read this to enable it](https://github.com/jipiboily/monologue/wiki/Configure-Monologue's-cache).
24
+ - more in the [CHANGELOG](https://github.com/jipiboily/monologue/blob/master/CHANGELOG.md)
25
+
26
+ - bonus: there is a `[monologue-markdown](https://github.com/jipiboily/monologue-markdown)` extension
16
27
 
17
28
  ### missing features
18
- - categories
19
29
  - UI for posts revisions and to manage user
20
- - much more…see issues!
30
+ - see [roadmap](https://github.com/jipiboily/monologue/wiki/Roadmap)!
21
31
 
22
32
 
23
33
  ## Installation
@@ -46,36 +56,27 @@ Run these commands:
46
56
  2. $`bundle exec rake db:create` (only if this is a new project)
47
57
  3. $`bundle exec rake db:migrate`
48
58
 
49
-
59
+
50
60
  ### 4. Create a user
51
61
  Open your development console with `rails c`, then:
52
62
  ```ruby
53
63
  Monologue::User.create(name: "monologue", email:"monologue@example.com", password:"my-password", password_confirmation: "my-password")
54
64
  ```
55
65
 
56
- ### 5. Configure Monologue.
66
+ ### 5. Configure Monologue.
57
67
  This is all done in an initializer file, say `config/initializers/monologue.rb`. More on this in the [Wiki - Configuration](https://github.com/jipiboily/monologue/wiki/Configuration).
58
68
 
59
69
  ### 6. Ready
60
70
  Start your server and head on [http://localhost:3000/monologue](http://localhost:3000/monologue) to log in the admin section.
61
71
 
62
- ### Note to Heroku users
72
+ ### Note to Heroku users
63
73
  Additionnal step: turn caching off in `config/environments/production.rb`:
64
74
  ```ruby
65
75
  config.action_controller.perform_caching = false
66
76
  ```
67
77
 
68
78
  ## Enable caching
69
- Just turn perform_caching to true in your environment config file (`config/environment/{environment}.rb):
70
- ```ruby
71
- config.action_controller.perform_caching = true
72
- ```
73
-
74
- **IMPORTANT**: if monologue is mounted at root ("/"), you must also add that in your `routes.rb` file, before the monologue mount:
75
-
76
- ```ruby
77
- root to: 'monologue/posts#index'
78
- ```
79
+ [See full caching doc here.](https://github.com/jipiboily/monologue/wiki/Configure-Monologue's-cache)
79
80
 
80
81
  ## Customization
81
82
  See the [Wiki - Customizations](https://github.com/jipiboily/monologue/wiki/Customizations).
@@ -85,4 +86,11 @@ See the [Wiki - Customizations](https://github.com/jipiboily/monologue/wiki/Cust
85
86
  - Database: MySQL & Postgres are supported but other databases might work too.
86
87
 
87
88
  ## Contribute
88
- Fork it, then pull request. Please add tests for your feature or bug fix.
89
+ Fork it, then pull request. Please add tests for your feature or bug fix.
90
+
91
+ You will need to install this before running the test suite:
92
+ - [https://github.com/thoughtbot/capybara-webkit/wiki/Installing-Qt-and-compiling-capybara-webkit](https://github.com/thoughtbot/capybara-webkit/wiki/Installing-Qt-and-compiling-capybara-webkit)
93
+
94
+ ## Thanks to
95
+
96
+ Zurb for the "social foundicons".
@@ -0,0 +1,32 @@
1
+ class window.TwitterWidget
2
+ @dom_cache: ->
3
+ @template = $("#tweet_template")
4
+ @latest_tweets = $("#latest_tweets")
5
+ @callback: (data) ->
6
+ @dom_cache()
7
+ for tweet in data
8
+ @add_tweet(tweet)
9
+ @add_tweet: (tweet) ->
10
+ tweet.text = tweet.text.parseTwitter()
11
+ @print(tweet)
12
+ @print: (tweet) ->
13
+ el = @template.clone().attr("id","")
14
+ el.html(el.html().replace("{{text}}", tweet.text)).show()
15
+ @latest_tweets.append(el)
16
+
17
+ String::parseUsername = ->
18
+ @replace /[@]+[A-Za-z0-9-_]+/g, (u) ->
19
+ username = u.replace("@", "")
20
+ u.link "http://twitter.com/" + username
21
+
22
+ String::parseHashtag = ->
23
+ @replace /[#]+[A-Za-z0-9-_]+/g, (t) ->
24
+ tag = t.replace("#", "%23")
25
+ t.link "http://search.twitter.com/search?q=" + tag
26
+
27
+ String::parseURL = ->
28
+ @replace /[A-Za-z]+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&~\?\/.=]+/g, (url) ->
29
+ url.link url
30
+
31
+ String::parseTwitter =->
32
+ @.parseURL().parseHashtag().parseUsername()
@@ -6,8 +6,8 @@
6
6
  *= require monologue/blog/skeleton/base
7
7
  *= require monologue/blog/skeleton/skeleton
8
8
  *= require monologue/blog/skeleton/layout
9
- *= require monologue/blog/custom
9
+ *= require monologue/foundation_icons/social_foundicons
10
+ *= require_tree .
10
11
  *= require monologue/blog/fonts
11
- *= require_tree .
12
- *= require_self
12
+ *= require monologue/blog/custom
13
13
  */
@@ -1,7 +1,41 @@
1
+ /* general */
2
+ a:hover {
3
+ color: #05C5FF;
4
+ }
5
+
6
+ ul {
7
+ list-style: square;
8
+ margin-left: 30px;
9
+ }
10
+
11
+ /* header */
1
12
  .main-header{
2
- margin: 20px 0 30px 0;
13
+ margin: 20px 0 0 0;
14
+ }
15
+
16
+ .main-header .social:first-of-type i {
17
+ float:right;
18
+ padding: 20px 0 0 0;
19
+ font-size: 50px;
20
+ text-decoration: none;
21
+ }
22
+
23
+ .main-header .social {
24
+ float: right;
25
+ margin: 0 2px 0 2px;
26
+ }
27
+
28
+ a.social {
29
+ text-decoration: none;
30
+ }
31
+
32
+ .social i {
33
+ font-size: 30px;
3
34
  }
4
35
 
36
+
37
+ /* pagination */
38
+
5
39
  #pagination {
6
40
  margin: 20px 0 0 0;
7
41
  border-top: 3px solid #000;
@@ -16,7 +50,10 @@
16
50
  float: right;
17
51
  }
18
52
 
19
- .content article h2, .content article h3, .content article h4, .content article h5, .content article h6 {
53
+ /* content */
54
+
55
+ .content article h2, .content article h3, .content article h4, .content article h5, .content article h6,
56
+ .content section h2, .content section h3, .content section h4, .content section h5, .content section h6 {
20
57
  font-size: 16px;
21
58
  text-transform: uppercase;
22
59
  font-weight: bold;
@@ -27,16 +64,122 @@
27
64
  font-weight: bold;
28
65
  }
29
66
 
30
- section header {
67
+ .content header {
68
+ border-bottom: solid black 1px;
69
+ border-top: solid black 1px;
70
+ }
71
+
72
+ .content header h1 {
73
+ margin: 0 0 0 10px;
74
+ }
75
+
76
+ .content header {
31
77
  margin: 0 0 5px 0;
32
78
  font-size: 12px;
79
+ text-align: center;
33
80
  }
34
81
 
35
- section header h1 {
82
+ .content header h1 {
36
83
  margin: 0 0 0 0;
37
84
  }
38
85
 
39
- ul {
40
- list-style: square;
41
- margin-left: 30px;
86
+ .content header .posted {
87
+ font-size: 12;
88
+ text-transform: uppercase;
89
+ font-weight: bold;
90
+ margin-bottom: 10px
91
+ }
92
+
93
+ /* tags */
94
+ #tags {
95
+ margin-top: 20px;
96
+ margin-bottom: 20px;
97
+ }
98
+
99
+ .tag {
100
+ background: #eeeeee;
101
+ -moz-border-radius: 4px;
102
+ -webkit-border-radius: 4px;
103
+ border:1px solid #d4d4d4;
104
+ border-radius:4px;
105
+ padding: 4px;
106
+ margin-right: 2px;
107
+ }
108
+
109
+ .tag-search,
110
+ .flash-notice {
111
+ padding:8px 35px 8px 14px;
112
+ margin-bottom:18px;
113
+ text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);
114
+ background-color:#eeeeee;
115
+ border:1px solid #d4d4d4;
116
+ -webkit-border-radius:4px;
117
+ -moz-border-radius:4px;
118
+ border-radius:4px;
119
+ }
120
+
121
+ .label-size-1 {
122
+ font-size: 80%;
123
+ opacity: .8;
124
+ }
125
+
126
+ .label-size-2 {
127
+ font-size: 90%;
128
+ opacity: .9;
129
+ }
130
+ .label-size-3 {
131
+ font-size: 100%;
132
+ }
133
+ .label-size-4 {
134
+ font-size: 130%;
135
+ }
136
+ .label-size-5 {
137
+ font-size: 160%;
138
+ }
139
+
140
+ /* sidebar */
141
+ .widget header {
142
+ padding: 8px 35px 0 14px;
143
+ margin: 10px 0 10px 0;
144
+ text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);
145
+ background-color:#eeeeee;
146
+ border:1px solid #d4d4d4;
147
+ -webkit-border-radius:4px;
148
+ -moz-border-radius:4px;
149
+ border-radius:4px;
150
+ }
151
+
152
+ .widget header:first-child {
153
+ margin-top: 0;
154
+ }
155
+
156
+ .widget header h1 {
157
+ font-size: 24px;
158
+ line-height: 32px;
159
+ margin-bottom: 4px;
160
+ }
161
+ none
162
+ /* footer */
163
+
164
+ .content article footer h1 {
165
+ margin-bottom: 10px;
166
+ font-size: 16px;
167
+ text-transform: uppercase;
168
+ text-align: center;
169
+ }
170
+
171
+ .monologue-social-sharing {
172
+ padding: 0 0 0 0;
173
+ border-top: solid black 1px;
174
+ }
175
+
176
+ #social-share {
177
+ /*text-align: center;*/
178
+ width: 100%;
179
+ }
180
+
181
+ #facebook, #twitter, #google-plus {
182
+ display: inline;
183
+ /*margin: 0 40px 0 40px;*/
184
+ /*padding: 0 0 0 0;*/
42
185
  }
@@ -0,0 +1,27 @@
1
+ class Monologue::Admin::CacheController < Monologue::Admin::BaseController
2
+ before_filter :prepare_file_list
3
+
4
+ def show
5
+ if ActionController::Base.perform_caching && Monologue::PageCache.enabled && Monologue::PageCache.wipe_enabled && ActionController::Base.page_cache_directory != Rails.public_path
6
+ render :show
7
+ else
8
+ render :how_to_enable
9
+ end
10
+ end
11
+
12
+ def destroy
13
+ Monologue::TotalSweeper.wipe_all
14
+ flash.notice = I18n.t("monologue.admin.cache.show.cache_wiped")
15
+ render :show
16
+ end
17
+
18
+ private
19
+ def prepare_file_list
20
+ @files = []
21
+ Dir.glob("#{ActionController::Base.page_cache_directory}/**/*").each do |file|
22
+ next if File.directory?(file)
23
+ @files << file.gsub(ActionController::Base.page_cache_directory,"")
24
+ end
25
+ @files
26
+ end
27
+ end
@@ -1,26 +1,27 @@
1
1
  class Monologue::Admin::PostsController < Monologue::Admin::BaseController
2
2
  respond_to :html
3
3
  cache_sweeper Monologue::PostsSweeper, :only => [:create, :update, :destroy]
4
-
4
+ before_filter :load_post_and_revisions, :only => [:edit, :update]
5
+
5
6
  def index
6
7
  @posts = Monologue::Post.default
7
8
  end
8
-
9
+
9
10
  def new
10
11
  @post = Monologue::Post.new
11
12
  @revision = @post.posts_revisions.build
12
13
  end
13
-
14
+
14
15
  def create
15
16
  params[:post][:posts_revisions_attributes] = {}
16
17
  params[:post][:posts_revisions_attributes][0] = params[:post][:posts_revision]
17
18
  params[:post].delete("posts_revision")
19
+ tags = params[:post].delete(:tag_list)
18
20
  @post = Monologue::Post.new(params[:post])
19
21
  @revision = @post.posts_revisions.first
20
22
  @revision.user_id = current_user.id
21
-
23
+ save_tags(tags)
22
24
  if @post.save
23
-
24
25
  if @revision.published_at > DateTime.now && @post.published && ActionController::Base.perform_caching
25
26
  flash[:warning] = I18n.t("monologue.admin.posts.create.created_with_future_date_and_cache")
26
27
  else
@@ -28,20 +29,19 @@ class Monologue::Admin::PostsController < Monologue::Admin::BaseController
28
29
  end
29
30
  redirect_to edit_admin_post_path(@post)
30
31
  else
31
- render :action => "new"
32
+ render :new
32
33
  end
33
34
  end
34
-
35
+
35
36
  def edit
36
- @post = Monologue::Post.includes(:posts_revisions).find(params[:id])
37
- @revision = @post.posts_revisions.last
37
+ @revision = @post.active_revision
38
38
  end
39
-
39
+
40
40
  def update
41
- @post = Monologue::Post.includes(:posts_revisions).find(params[:id])
42
41
  @post.published = params[:post][:published]
43
42
  @revision = @post.posts_revisions.build(params[:post][:posts_revision])
44
43
  @revision.user_id = current_user.id
44
+ save_tags(params[:post][:tag_list])
45
45
  if @post.save
46
46
  if @revision.published_at > DateTime.now && @post.published && ActionController::Base.perform_caching
47
47
  flash[:warning] = I18n.t("monologue.admin.posts.update.saved_with_future_date_and_cache")
@@ -53,7 +53,7 @@ class Monologue::Admin::PostsController < Monologue::Admin::BaseController
53
53
  render :edit
54
54
  end
55
55
  end
56
-
56
+
57
57
  def destroy
58
58
  post = Monologue::Post.find(params[:id])
59
59
  if post.destroy
@@ -62,4 +62,20 @@ class Monologue::Admin::PostsController < Monologue::Admin::BaseController
62
62
  redirect_to admin_posts_path, :alert => I18n.t("monologue.admin.posts.delete.failed")
63
63
  end
64
64
  end
65
+
66
+ private
67
+ def save_tags(tags)
68
+ @post.tag!(tags.split(","))
69
+ end
70
+
71
+ def load_post_and_revisions
72
+ @post = Monologue::Post.includes(:posts_revisions).find(params[:id])
73
+ end
74
+
75
+ helper_method :tag_list_for
76
+
77
+ def tag_list_for(tags)
78
+ tags.map { |tag| tag.name }.join(", ") if tags
79
+ end
80
+
65
81
  end
@@ -7,7 +7,7 @@ class Monologue::Admin::SessionsController < Monologue::Admin::BaseController
7
7
  def create
8
8
  user = Monologue::User.find_by_email(params[:email])
9
9
  if user && user.authenticate(params[:password])
10
- session[:user_id] = user.id
10
+ session[:monologue_user_id] = user.id
11
11
  redirect_to admin_url, :notice => t("monologue.admin.sessions.messages.logged_in")
12
12
  else
13
13
  flash.now.alert = t("monologue.admin.sessions.messages.invalid")
@@ -16,7 +16,7 @@ class Monologue::Admin::SessionsController < Monologue::Admin::BaseController
16
16
  end
17
17
 
18
18
  def destroy
19
- session[:user_id] = nil
19
+ session[:monologue_user_id] = nil
20
20
  redirect_to admin_url, :notice => t("monologue.admin.sessions.messages.logged_out")
21
21
  end
22
22
  end