contentment 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  How often do your clients want to manage / edit some piddly little portion of the site you're building for them?
6
6
  Every time? Yeah me too. If what you need is a way for your clients to manage the FAQ or Testimonials, contentment is for you.
7
- It's blindingly simple to use and it will save you time.
7
+ It's simple to use and will save you time.
8
8
 
9
9
  The primary advantage it offers over a roll-your-own CMS is consistency.
10
10
  Use Contentment whenever you need a basic CMS and you can stop re-inventing the wheel and start pumping code.
@@ -16,7 +16,7 @@ and run
16
16
  bundle install
17
17
 
18
18
  ==Use Contentment
19
- rails g contentment
19
+ rails generate contentment
20
20
  rake db:migrate
21
21
  This will create the Content model and a migration to add the contents table to your database, if it doesn't already exist.
22
22
  It will also create contents_controller.rb for you with all the CRUD already done.
@@ -26,24 +26,40 @@ This will create the views to manage your Content.
26
26
  Fire up the server and you're ready to go.
27
27
 
28
28
  ==Details
29
- title and body are pretty self explanatory, perfect for question and answer, or header and paragraph.
29
+ :title and :body are pretty self explanatory, perfect for question and answer, or header and paragraph.
30
30
 
31
- tipe is not type to get around rails polymorphic associations, and exists so you can
32
- do things like Content.for_faq or Content.for_navigation.
31
+ :tipe is not type to get around rails polymorphic associations, and exists to help you keep track of what
32
+ Content goes on what pages. Add your own values to the @tipes array
33
+ @tipes = [
34
+ # "Billboard",
35
+ # "What You Learn",
36
+ # "Tips",
37
+ # "Questions Copy",
38
+ # "FAQ",
39
+ # "Examples",
40
+ # "Testimonial",
41
+ # "Navigation",
42
+ ]
43
+ and you'll get things like Content.for_faq or Content.for_navigation. Be careful about changing tipes after you've
44
+ been up and running for a while or you might orphan Content.
33
45
 
34
- dom_id is rarely used, but sometimes you need to manipulate Content programmatically and this is there for that.
46
+ :dom_id is rarely used, but sometimes you need to manipulate Content on the page with JavaScript and this is there for that.
35
47
 
36
- position, because clients love ordering stuff around.
48
+ :position will help you control the order of things in lists.
37
49
 
38
- visible, because clients like to hide things from their users.
50
+ :visible will help you hide things without deleting them.
51
+
52
+ :link will allow you to have your navigation editable by your client. Put what you want to show up in the title,
53
+ and where you want to go in the link field and I'm sure you can fill in the rest.
39
54
 
40
55
  ==Live Preview of Content on Edit
41
56
 
57
+ If you're using jQuery
58
+
42
59
  Slap this in your application.js to get live preview of the title attribute of content
43
- $('.edit_content').keyup(function(){
44
- var bob = $('#content_title').val();
45
- $('.content_preview_title').html(bob);
46
- })
60
+ $(document).ready(function(){$('.edit_content').keyup(function(){$('.content_preview_title').html($('#content_title').val());});})
61
+
62
+
47
63
  I'm using TinyMCE Hammer to get TinyMCE in my projects, and if you install it too you can have live preview of the body of your content pretty easily.
48
64
  (I'm working on getting TinyMCE included in this gem)
49
65
  TinyMCE is nice because your clients probably want the ability to add line breaks and other styling without having to learn HTML.
@@ -68,7 +84,7 @@ A thousand thanks to @modestrubyist from http://www.themodestrubyist.com/ , with
68
84
 
69
85
  Also thanks to the thoughtbot team and the clearance gem, which I looked at to learn more. https://github.com/thoughtbot/clearance
70
86
 
71
- And also finally thanks to https://github.com/elricstorm/baby_dove which is where I copied most of this from.
87
+ And also finally thanks to https://github.com/elricstorm/baby_dove which I used as a template for this whole engine.
72
88
 
73
89
  Read More about engines - http://edgeapi.rubyonrails.org/classes/Rails/Engine.html
74
90
 
@@ -0,0 +1,31 @@
1
+ <%= form_for(@content) do |f| %>
2
+ <p>
3
+ <%= f.text_field :title, :placeholder => "Content Title" %>
4
+ </p>
5
+ <p>
6
+ <%= f.label :body %>
7
+ <%= f.text_area :body %>
8
+ </p>
9
+ <p>
10
+ <%= f.label :type %>
11
+ <%= f.select :tipe, content_tipe_options %>
12
+ </p>
13
+ <p>
14
+ <%= f.label "DOM id" %>
15
+ <%= f.text_field :dom_id %>
16
+ </p>
17
+ <p>
18
+ <%= f.label :position %>
19
+ <%= f.text_field :position %>
20
+ </p>
21
+ <p>
22
+ <%= f.label :visible %>
23
+ <%= f.check_box :visible%>
24
+ </p>
25
+ <p>
26
+ <%= f.label :link %>
27
+ <%= f.text_field :link %>
28
+ </p>
29
+ <%= link_to 'Back', contents_path %>
30
+ <%= f.submit %>
31
+ <% end %>
@@ -1,9 +1,9 @@
1
- <div class="panel" id="preview">
2
- <h3>Preview</h3>
3
- <div class='content_preview_title'>
4
- <%= raw content.title %>
5
- </div>
6
- <div class='content_preview_body'>
7
- <%= raw content.body %>
8
- </div>
1
+ <div id="preview">
2
+ <h3>Preview</h3>
3
+ <div class='content_preview_title'>
4
+ <%= raw content.title %>
5
+ </div>
6
+ <div class='content_preview_body'>
7
+ <%= raw content.body %>
8
+ </div>
9
9
  </div>
@@ -1,34 +1,40 @@
1
+ <%= content_for :scripts do %>
2
+ <script src='/javascripts/tinymce_hammer.js' type='text/javascript'></script>
3
+ <script type='text/javascript'>
4
+ TinymceHammer = {
5
+ init : function() {
6
+ var init = { paste_convert_headers_to_strong : true,
7
+ paste_convert_middot_lists : true,
8
+ paste_remove_spans : true,
9
+ paste_remove_styles : true,
10
+ paste_strip_class_attributes : true,
11
+ theme : "advanced",
12
+ theme_advanced_buttons1 : "undo,redo,cut,copy,paste,|,bold,italic,strikethrough,blockquote,charmap,bullist,numlist,removeformat,|,link,unlink,|,cleanup,code",
13
+ theme_advanced_buttons2 : "",
14
+ theme_advanced_buttons3 : "",
15
+ theme_advanced_toolbar_align : "left",
16
+ theme_advanced_toolbar_location : "top",
17
+ valid_elements : "@[id|class|style|title|dir<ltr?rtl|lang|xml::lang|onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],a[rel|rev|charset|hreflang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur],strong/b,em/i,strike,u,#p,-ol[type|compact],-ul[type|compact],-li,br,img[longdesc|usemap|src|border|alt=|title|hspace|vspace|width|height|align],-sub,-sup,-blockquote,-table[border=0|cellspacing|cellpadding|width|frame|rules|height|align|summary|bgcolor|background|bordercolor],-tr[rowspan|width|height|align|valign|bgcolor|background|bordercolor],tbody,thead,tfoot,#td[colspan|rowspan|width|height|align|valign|bgcolor|background|bordercolor|scope],#th[colspan|rowspan|width|height|align|valign|scope],caption,-div,-span,-code,-pre,address,-h1,-h2,-h3,-h4,-h5,-h6,hr[size|noshade],-font[face|size|color],dd,dl,dt,cite,abbr,acronym,del[datetime|cite],ins[datetime|cite],object[classid|width|height|codebase|*],param[name|value|_value],embed[type|width|height|src|*],script[src|type],map[name],area[shape|coords|href|alt|target],bdo,button,col[align|char|charoff|span|valign|width],colgroup[align|char|charoff|span|valign|width],dfn,fieldset,form[action|accept|accept-charset|enctype|method],input[accept|alt|checked|disabled|maxlength|name|readonly|size|src|type|value],kbd,label[for],legend,noscript,optgroup[label|disabled],option[disabled|label|selected|value],q[cite],samp,select[disabled|multiple|name|size],small,textarea[cols|rows|disabled|name|readonly],tt,var,big",
18
+ setup : function(ed) { ed.onKeyUp.add(function(ed, evt) { var iframe = document.getElementById('content_body_ifr'); var paul = iframe.contentWindow.document.body.innerHTML; $('.content_preview_body').html(paul); }); } };
19
+ init.mode = 'specific_textareas';
20
+ init.editor_selector = 'tinymce';
21
+ init.plugins = 'paste';
22
+ init.language = 'en';
23
+
24
+ tinyMCE.init(init);
25
+ },
26
+ addEditor : function(dom_id) {
27
+ tinyMCE.execCommand('mceAddControl', true, dom_id);
28
+ }
29
+ }
30
+ DomReady.ready(TinymceHammer.init);
31
+ </script>
32
+ <% end %>
33
+
1
34
  <%= link_to 'New content', new_content_path, :class => 'button', :id => "add-content" %>
2
35
  <%= link_to "Back to Content List", contents_path, :class => 'button', :id => 'back-to-contents' %>
3
- <div class="panel clearfix">
36
+ <div>
4
37
  <h3>Edit content</h3>
5
- <% form_for(@content) do |f| %>
6
- <p>
7
- <%= f.text_field :title, :placeholder => "Content Title", :class => 'title' %>
8
- </p>
9
- <p>
10
- <%= f.label :body %>
11
- <%= f.text_area :body %>
12
- </p>
13
- <p>
14
- <%= f.label :type %>
15
- <%= f.select :tipe, content_tipe_options %>
16
- </p>
17
- <p>
18
- <%= f.label "DOM id" %>
19
- <%= f.text_field :dom_id %>
20
- </p>
21
- <p>
22
- <%= f.label :position %>
23
- <%= f.text_field :position %>
24
- </p>
25
- <p>
26
- <%= f.label :visible %>
27
- <%= f.check_box :visible%>
28
- </p>
29
- <%= link_to 'Back', contents_path %>
30
- <%= f.submit 'Update' %>
31
-
32
- <% end %>
38
+ <%= render :partial => "form" %>
33
39
  </div>
34
40
  <%= render :partial => "preview", :locals => { :form => '.edit_content', :content => @content } %>
@@ -1,15 +1,14 @@
1
- <div id="cms">
2
- <%= link_to 'New content', new_content_path, :class => 'button', :id => "add-content" %>
3
- <h1 class="intro">Content Management</h1>
4
- <table class="alternating admin admin-table" id="content-table">
5
- <tr>
6
- <th>Title</th>
7
- <th>Type</th>
8
- <th>DOM ID</th>
9
- <th>Position</th>
10
-
11
- <th></th>
12
- </tr>
1
+ <div>
2
+ <%= link_to 'New content', new_content_path, :class => 'button', :id => "add-content" %>
3
+ <h1>Content Management</h1>
4
+ <table>
5
+ <tr>
6
+ <th>Title</th>
7
+ <th>Type</th>
8
+ <th>DOM ID</th>
9
+ <th>Position</th>
10
+ <th></th>
11
+ </tr>
13
12
 
14
13
  <% @contents.each do |content| %>
15
14
  <tr class=<%= cycle("even", "odd")%>>
@@ -21,8 +20,8 @@
21
20
  <%= link_to 'Show', content %>
22
21
  <%= link_to 'Edit', edit_content_path(content) %>
23
22
  <%= link_to 'Destroy', content, :confirm => 'Are you sure?', :method => :delete %>
24
- </td>
23
+ </td>
25
24
  </tr>
26
25
  <% end %>
27
- </table>
26
+ </table>
28
27
  </div>
@@ -1,34 +1,5 @@
1
- <div class="panel clearfix">
2
-
3
-
1
+ <div>
4
2
  <h3>New content</h3>
5
- <% form_for(@content) do |f| %>
6
- <p>
7
- <%= f.text_field :title, :placeholder => "Content Title", :class => 'title' %>
8
- </p>
9
- <p>
10
- <%= f.label :body %>
11
- <%= f.text_area :body %>
12
- </p>
13
- <p>
14
- <%= f.label :type %>
15
- <%= f.select :tipe, content_tipe_options %>
16
- </p>
17
- <p>
18
- <%= f.label "DOM id" %>
19
- <%= f.text_field :dom_id %>
20
- </p>
21
- <p>
22
- <%= f.label :position %>
23
- <%= f.text_field :position %>
24
- </p>
25
- <p>
26
- <%= f.label :visible %>
27
- <%= f.check_box :visible%>
28
- </p>
29
- <%= link_to 'Cancel', contents_path %>
30
- <%= f.submit 'Create' %>
31
-
32
- <% end %>
3
+ <%= render :partial => "form" %>
33
4
  </div>
34
5
  <%= render :partial => "preview", :locals => { :form => '.new_content', :content => @content } %>
@@ -1,22 +1,17 @@
1
- <div class="clear">
2
- <p>
3
- <b>Title:</b>
4
- <%=h @content.title %>
5
- </p>
6
-
7
- <p>
8
- <b>Body:</b>
9
- <%=h @content.body %>
10
- </p>
11
-
12
- <p>
13
- <b>Type:</b>
14
- <%=h @content.tipe %>
15
- </p>
16
-
17
-
18
- <%= link_to 'Edit', edit_content_path(@content) %> |
19
- <%= link_to 'Back', contents_path %>
20
-
21
- <%= link_to "new", new_content_path %>
1
+ <div>
2
+ <p>
3
+ <b>Title:</b>
4
+ <%=h @content.title %>
5
+ </p>
6
+ <p>
7
+ <b>Body:</b>
8
+ <%=h @content.body %>
9
+ </p>
10
+ <p>
11
+ <b>Type:</b>
12
+ <%=h @content.tipe %>
13
+ </p>
14
+ <%= link_to 'Edit', edit_content_path(@content) %> |
15
+ <%= link_to 'Back', contents_path %> |
16
+ <%= link_to "new", new_content_path %>
22
17
  </div>
@@ -1,8 +1,9 @@
1
1
  module ContentsHelper
2
2
 
3
- # Is a helper really necessary? Apparently I thought so at some point. <%= f.select :tipe, content_tipe_options %>
4
- # When the helper is longer than what it replaces you've got a problem.
5
- def content_tipe_options
3
+ # Is a helper really necessary? Apparently I thought so at some point.
4
+ # <%#= f.select :tipe, content_tipe_options %>
5
+ # When the helper is longer than what it replaces you've got a problem. :P
6
+ def content_tipe_options
6
7
  Content.tipes
7
8
  end
8
9
  end
@@ -1,46 +1,46 @@
1
1
  class Content < ActiveRecord::Base
2
2
 
3
- before_save :adjust_positions
4
-
5
-
6
- class << self; attr_accessor :tipes; end
3
+ before_save :adjust_positions
7
4
 
8
- # Put all the different kinds of content you will have in here to get a select helper and some named scopes
9
- # generated for you.
5
+
6
+ class << self; attr_accessor :tipes; end
7
+
8
+ # Put all the different kinds of content you will have in here to get a select helper and some named scopes
9
+ # generated for you.
10
10
  @tipes = [
11
- # "Billboard",
12
- # "What You Learn",
13
- # "Tips",
14
- # "Questions Copy",
15
- # "FAQ",
16
- # "Examples",
17
- # "Testimonial",
18
- # "Navigation",
19
- ]
11
+ # "Billboard",
12
+ # "What You Learn",
13
+ # "Tips",
14
+ # "Questions Copy",
15
+ # "FAQ",
16
+ # "Examples",
17
+ # "Testimonial",
18
+ # "Navigation",
19
+ ]
20
20
 
21
- # Pretty much always want to only find content of one tipe at a time, so generate scopes for all tipes.
21
+ # Pretty much always want to only find content of one tipe at a time, so generate scopes for all tipes.
22
22
  @tipes.each do |thing|
23
23
  scope "for_#{thing.downcase.gsub(' ', '_')}".intern, where("tipe = ?", thing)
24
24
  end
25
25
 
26
- # It's pretty common to want the ability to hide some content. Use the visible scope liberally.
27
- scope :visible, lambda {|x| where(:visible => x)}
26
+ # It's pretty common to want the ability to hide some content. Use the visible scope liberally.
27
+ scope :visible, lambda {|x| where(:visible => x)}
28
28
 
29
- # Returns all Content with like tipe.
30
- def brothers
31
- Content.where("tipe = ?", self.tipe).where("id NOT in (#{self.id})")
32
- end
29
+ # Returns all Content with like tipe.
30
+ def brothers
31
+ Content.where("tipe = ?", self.tipe).where("id NOT in (#{self.id})")
32
+ end
33
33
 
34
- private
35
- # It's a pain with ordered content to have to manually update each piece of content when rearranging them.
36
- # adjust_positions will make sure when you change the position of one content, all other content of that tipe
37
- # has position changed to keep a reasonable order.
38
- def adjust_positions
39
- return true unless changed.include?('position')
40
- return true unless brothers.map{|x| x.position}.include?(self.position)
41
-
42
- brothers.where("position >= ?", self.position).update_all("position = (position + 1)")
43
- end
44
-
45
-
34
+ private
35
+ # It's a pain with ordered content to have to manually update each piece of content when rearranging them.
36
+ # adjust_positions will make sure when you change the position of one content, all other content of that tipe
37
+ # has position changed to keep a reasonable order.
38
+ def adjust_positions
39
+ return true unless changed.include?('position')
40
+ return true unless brothers.map{|x| x.position}.include?(self.position)
41
+
42
+ brothers.where("position >= ?", self.position).update_all("position = (position + 1)")
43
+ end
44
+
45
+
46
46
  end
@@ -1,34 +1,34 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class ContentTest < ActiveSupport::TestCase
4
-
5
- def setup
4
+
5
+ def setup
6
6
  @a = Content.create(:app_id => 1, :position => 1, :title => 'a', :tipe => 'test')
7
7
  @b = Content.create(:app_id => 1, :position => 2, :title => 'b', :tipe => 'test')
8
8
  @c = Content.create(:app_id => 1, :position => 3, :title => 'c', :tipe => 'test')
9
- end
9
+ end
10
10
  # Replace this with your real tests.
11
11
  test "content should fix position of other content with similar tipe on save" do
12
- @c.position = 1
13
- @c.save
14
-
15
- assert(@c.reload.position == 1)
16
- assert(@a.reload.position == 2)
17
- assert(@b.reload.position == 3)
12
+ @c.position = 1
13
+ @c.save
14
+
15
+ assert(@c.reload.position == 1)
16
+ assert(@a.reload.position == 2)
17
+ assert(@b.reload.position == 3)
18
18
  end
19
19
 
20
- test "saving multiple pieces of content things kind of escalate out of control ... " do
21
- @a.position = 3
22
- @a.save
23
- assert(3 == @a.reload.position)
24
- assert(2 == @b.reload.position)
25
- assert(4 == @c.reload.position)
26
- @b.position = 3
27
- @b.save
28
- assert(3 == @b.reload.position)
29
- assert(5 == @c.reload.position)
30
- assert(4 == @a.reload.position)
20
+ test "saving multiple pieces of content things kind of escalate out of control ... " do
21
+ @a.position = 3
22
+ @a.save
23
+ assert(3 == @a.reload.position)
24
+ assert(2 == @b.reload.position)
25
+ assert(4 == @c.reload.position)
26
+ @b.position = 3
27
+ @b.save
28
+ assert(3 == @b.reload.position)
29
+ assert(5 == @c.reload.position)
30
+ assert(4 == @a.reload.position)
31
31
 
32
- end
32
+ end
33
33
 
34
34
  end
@@ -38,6 +38,7 @@ class ContentsController < ApplicationController
38
38
 
39
39
  def update
40
40
  @content = Content.find(params[:id])
41
+ @content.update_attributes(params[:content])
41
42
  respond_to do |format|
42
43
  if @content.save
43
44
  format.html { redirect_to edit_content_path(@content.id), :notice => 'Content was successfully updated.' }
@@ -6,12 +6,12 @@ class CreateContents < ActiveRecord::Migration
6
6
  # Birds Table
7
7
  create_table :contents do |t|
8
8
  t.string :title
9
- t.text :body
10
- t.string :tipe
11
- t.string :dom_id
12
- t.integer :position
13
- t.boolean :visible
14
-
9
+ t.text :body
10
+ t.string :tipe
11
+ t.string :dom_id
12
+ t.integer :position
13
+ t.boolean :visible
14
+ t.string :link
15
15
  t.timestamps
16
16
  end
17
17
 
@@ -1,16 +1,16 @@
1
1
  require 'rails/generators'
2
2
 
3
3
  class ContentmentViewsGenerator < Rails::Generators::Base
4
- desc "This generator creates the views for Contentment"
4
+ desc "This generator creates the views for Contentment"
5
5
 
6
6
  def self.source_root
7
7
  File.join(File.dirname(__FILE__), 'contentment/contentment_views_templates')
8
8
  end
9
9
 
10
- def install
11
- puts "Installing Views"
12
- template 'contents_helper.rb', 'app/helpers/contents_helper.rb'
13
- directory 'contents', 'app/views/contents'
14
- end
10
+ def install
11
+ puts "Installing Views"
12
+ template 'contents_helper.rb', 'app/helpers/contents_helper.rb'
13
+ directory 'contents', 'app/views/contents'
14
+ end
15
15
 
16
16
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 5
8
- - 1
9
- version: 0.5.1
7
+ - 6
8
+ - 0
9
+ version: 0.6.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Bob Larrick
@@ -14,11 +14,11 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-17 00:00:00 -05:00
17
+ date: 2011-02-23 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies: []
20
20
 
21
- description: "Rails Engine for dead simple content management. "
21
+ description: Rails Engine for simple content management. See readme on github for details.
22
22
  email: larrick@gmail.com
23
23
  executables: []
24
24
 
@@ -31,6 +31,7 @@ files:
31
31
  - lib/contentment.rb
32
32
  - lib/contentment/engine.rb
33
33
  - lib/extensions/action_controller/base.rb
34
+ - lib/generators/contentment/contentment_views_templates/contents/_form.html.erb
34
35
  - lib/generators/contentment/contentment_views_templates/contents/_preview.html.erb
35
36
  - lib/generators/contentment/contentment_views_templates/contents/edit.html.erb
36
37
  - lib/generators/contentment/contentment_views_templates/contents/index.html.erb
@@ -75,6 +76,6 @@ rubyforge_project: contentment
75
76
  rubygems_version: 1.3.7
76
77
  signing_key:
77
78
  specification_version: 3
78
- summary: Dead simple content management.
79
+ summary: Rails Engine for simple content management.
79
80
  test_files: []
80
81