common-content 0.0.1

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.
Files changed (39) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.textile +55 -0
  3. data/Rakefile +29 -0
  4. data/app/assets/javascripts/application.js +15 -0
  5. data/app/assets/javascripts/bootstrap.js.coffee +0 -0
  6. data/app/assets/javascripts/contents.js.coffee +16 -0
  7. data/app/assets/javascripts/jquery-ui-1.8.21.custom.min.js +125 -0
  8. data/app/assets/stylesheets/application.css +7 -0
  9. data/app/assets/stylesheets/bootstrap_and_overrides.css.less +29 -0
  10. data/app/assets/stylesheets/contents.css.less +11 -0
  11. data/app/assets/stylesheets/scaffolds.css.less +62 -0
  12. data/app/controllers/contents_controller.rb +99 -0
  13. data/app/helpers/contents_helper.rb +29 -0
  14. data/app/models/content.rb +49 -0
  15. data/app/models/resource.rb +10 -0
  16. data/app/models/seo.rb +11 -0
  17. data/app/models/textile.rb +16 -0
  18. data/app/views/contents/_array_form.html.erb +14 -0
  19. data/app/views/contents/_child_content_fields.html.erb +14 -0
  20. data/app/views/contents/_content.xml.builder +4 -0
  21. data/app/views/contents/_fields_edit.html.erb +7 -0
  22. data/app/views/contents/_fields_new.html.erb +14 -0
  23. data/app/views/contents/_resource_fields.html.erb +21 -0
  24. data/app/views/contents/_seo_fields.html.erb +21 -0
  25. data/app/views/contents/_show_children.html.erb +10 -0
  26. data/app/views/contents/_textile_form.html.erb +1 -0
  27. data/app/views/contents/edit.html.erb +44 -0
  28. data/app/views/contents/index.html.erb +34 -0
  29. data/app/views/contents/index.xml.builder +5 -0
  30. data/app/views/contents/new.html.erb +13 -0
  31. data/app/views/contents/show.html.erb +25 -0
  32. data/app/views/contents/show.xml.builder +1 -0
  33. data/app/views/layouts/application.html.erb +64 -0
  34. data/config/routes.rb +9 -0
  35. data/lib/common-content.rb +4 -0
  36. data/lib/common-content/engine.rb +7 -0
  37. data/lib/common-content/version.rb +3 -0
  38. data/lib/tasks/common-content_tasks.rake +4 -0
  39. metadata +180 -0
@@ -0,0 +1,29 @@
1
+ module ContentsHelper
2
+ def hateoas_uri_options(source, entity)
3
+ # open the source url
4
+ # parse out the entities
5
+ # look for <name> and <link rel='self'> and parse into [[link, name]]
6
+ end
7
+
8
+
9
+ # from http://railscasts.com/episodes/196-nested-model-form-revised?view=asciicast
10
+ # def link_to_add_fields(name, f, association)
11
+ # new_object = f.object.send(association).klass.new
12
+ # id = new_object.object_id
13
+ # fields = f.fields_for(association, new_object, child_index: id) do |builder|
14
+ # render(association.to_s.singularize + "_fields", f: builder)
15
+ # end
16
+ # link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
17
+ # end
18
+
19
+ def link_to_add_fields(name, f, association)
20
+ new_object = f.object.send(association).klass.new
21
+ id = new_object.object_id
22
+ fields = f.fields_for(association, new_object, child_index: id) do |builder|
23
+ render(partial: association.to_s.singularize + "_fields", locals: { f: builder })
24
+ end
25
+ link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
26
+ end
27
+
28
+
29
+ end
@@ -0,0 +1,49 @@
1
+ class Content
2
+ include Mongoid::Document
3
+ include Mongoid::Timestamps
4
+
5
+ field :slug, type: String
6
+ validates :slug, presence: true, uniqueness: true
7
+ key :slug
8
+
9
+ field :title, type: String
10
+ validates :title, presence: true
11
+
12
+ field :body, type: Textile # optional html block of text for this content
13
+
14
+ embeds_one :seo # optional SEO fields
15
+ accepts_nested_attributes_for :seo # mongoid BUG see http://stackoverflow.com/questions/9392315/mongoid-and-nested-form-for-embeds-one-document
16
+
17
+ embeds_many :resources # optional 1-n resources like images, videos, REST urls, etc
18
+ accepts_nested_attributes_for :resources # mongoid BUG see http://stackoverflow.com/questions/9392315/mongoid-and-nested-form-for-embeds-one-document
19
+
20
+ recursively_embeds_many # optionaal 1-n embedded child Content objects, the editable field controls if user can change
21
+ accepts_nested_attributes_for :child_contents # mongoid BUG see http://stackoverflow.com/questions/9392315/mongoid-and-nested-form-for-embeds-one-document
22
+
23
+ # embeds_one :constraint # the constraints of what fields are required, what child objects can be defined and how many, etc.
24
+
25
+ def ancestry
26
+ parent_content ? parent_content.ancestry << id : [id]
27
+ end
28
+
29
+ def self.find_by_ancestry(ancestry = nil, id)
30
+ return self.find(id) unless ancestry
31
+ parent = Content.find(ancestry.shift)
32
+ while(parent_slug = ancestry.shift and parent_slug != id) do
33
+ parent = parent.child_contents.find(parent_slug)
34
+ end if parent
35
+ parent.child_contents.find(id)
36
+ end
37
+
38
+ def child_order=(order)
39
+ return unless order
40
+ order = order.split(',')
41
+ order.each {|e| e.strip!}
42
+ self.child_contents = self.child_contents.sort_by {|kid| order.find_index(kid.id) }
43
+ end
44
+
45
+ def to_param
46
+ parent_content ? parent_content.to_param + '/' + id : id
47
+ end
48
+
49
+ end
@@ -0,0 +1,10 @@
1
+ class Resource
2
+ include Mongoid::Document
3
+
4
+ embedded_in :content
5
+
6
+ field :slug, type: String
7
+ field :uri, type: String # the URI of the entity we're linking to
8
+ field :content_type, type: String # mime type if there is one
9
+
10
+ end
data/app/models/seo.rb ADDED
@@ -0,0 +1,11 @@
1
+ class Seo
2
+ include Mongoid::Document
3
+
4
+ embedded_in :content
5
+
6
+ field :description, type: String
7
+ field :keywords, type: String
8
+ field :metatitle, type: String
9
+
10
+ # validates :description, :keywords, :metatitle, presence: true
11
+ end
@@ -0,0 +1,16 @@
1
+ require 'RedCloth'
2
+
3
+ class Textile < RedCloth::TextileDoc
4
+ include Mongoid::Fields::Serializable
5
+
6
+ attr_accessor :max
7
+
8
+ def serialize(object)
9
+ object.to_s
10
+ end
11
+ def deserialize(object)
12
+ object = '' unless object
13
+ RedCloth.new(object)
14
+ end
15
+
16
+ end
@@ -0,0 +1,14 @@
1
+ <% f.object.send(fk).each_with_index do |ar, idx| %>
2
+ <div class="control-group">
3
+ <%= f.fields_for fk do |ar_form| %>
4
+ <div class="controls">
5
+ <!-- do some stuff to see if this type has a specific view partial -->
6
+ <% if File.file?(File.expand_path("_#{ar.type.to_s.downcase}_form.html.erb", File.dirname(__FILE__))) %>
7
+ <%= render :partial => "#{ar.type.to_s.downcase}_form", :locals => {f: f, fk: fk} %>
8
+ <% else %>
9
+ <%= ar_form.text_field "", :class => 'text_field', :value => ar %>
10
+ <% end %>
11
+ </div>
12
+ <% end %>
13
+ </div>
14
+ <% end %>
@@ -0,0 +1,14 @@
1
+ <fieldset>
2
+ <div class="control-group">
3
+ <%= f.label :slug, :class => 'control-label' %>
4
+ <div class="controls">
5
+ <%= f.text_field :slug, :class => 'text_field' %>
6
+ </div>
7
+ </div>
8
+ <div class="control-group">
9
+ <%= f.label :title, :class => 'control-label' %>
10
+ <div class="controls">
11
+ <%= f.text_field :title, :class => 'text_field' %>
12
+ </div>
13
+ </div>
14
+ </fieldset>
@@ -0,0 +1,4 @@
1
+ xml.content do
2
+ xml.name(content.slug)
3
+ xml.link('rel' => 'self', 'uri' => content_path(content))
4
+ end
@@ -0,0 +1,7 @@
1
+ <div class="control-group">
2
+ <%= f.label :body, :class => 'control-label' %>
3
+ <div class="controls">
4
+ <%= f.text_area :body, :class => 'text_area' %>
5
+ </div>
6
+ </div>
7
+
@@ -0,0 +1,14 @@
1
+ <fieldset>
2
+ <div class="control-group">
3
+ <%= f.label :slug, :class => 'control-label' %>
4
+ <div class="controls">
5
+ <%= f.text_field :slug, :class => 'text_field', disabled: !@content.new? %>
6
+ </div>
7
+ </div>
8
+ <div class="control-group">
9
+ <%= f.label 'title', :class => 'control-label' %>
10
+ <div class="controls">
11
+ <%= f.text_field :title, :class => 'text_field' %>
12
+ </div>
13
+ </div>
14
+ </fieldset>
@@ -0,0 +1,21 @@
1
+ <fieldset>
2
+ <div class="control-group">
3
+ <%= f.label :slug, :class => 'control-label' %>
4
+ <div class="controls">
5
+ <%= f.text_field :slug, :class => 'text_field' %>
6
+ </div>
7
+ </div>
8
+ <div class="control-group">
9
+ <%= f.label :uri, :class => 'control-label' %>
10
+ <div class="controls">
11
+ <%= f.text_field :uri, :class => 'text_field' %>
12
+ </div>
13
+ </div>
14
+ <div class="control-group">
15
+ <%= f.label :type, :class => 'control-label' %>
16
+ <div class="controls">
17
+ <%= f.text_field :content_type, :class => 'text_field' %>
18
+ </div>
19
+ </div>
20
+ <hr/>
21
+ </fieldset>
@@ -0,0 +1,21 @@
1
+ <fieldset>
2
+ <div class="control-group">
3
+ <%= f.label :title, :class => 'control-label' %>
4
+ <div class="controls">
5
+ <%= f.text_field :metatitle, :class => 'text_field' %>
6
+ </div>
7
+ </div>
8
+ <div class="control-group">
9
+ <%= f.label :description, :class => 'control-label' %>
10
+ <div class="controls">
11
+ <%= f.text_area :description, :class => 'text_area meta_description', rows: '3' %>
12
+ </div>
13
+ </div>
14
+ <div class="control-group">
15
+ <%= f.label :keywords, :class => 'control-label' %>
16
+ <div class="controls">
17
+ <%= f.text_field :keywords, :class => 'text_field' %>
18
+ </div>
19
+ </div>
20
+ <hr/>
21
+ </fieldset>
@@ -0,0 +1,10 @@
1
+ <% # http://stackoverflow.com/questions/187073/jquery-sortables %>
2
+ <div class="">
3
+ <!-- <input type='hidden' name='content[child_order]' id='child_order' /> -->
4
+ <div id="children">
5
+ <% show_children.try :each do |child| %>
6
+ <%= content_tag :div, id: child.id do %>
7
+ <p><%= link_to child.title, contents_path + '/' + child.ancestry.join('/') + '/edit' %></p>
8
+ <% end; end -%>
9
+ </div>
10
+ </div>
@@ -0,0 +1 @@
1
+ <%= f.text_area fk.intern, :class => 'text_area' %>
@@ -0,0 +1,44 @@
1
+ <%- model_class = @content.class -%>
2
+ <div class="page-header">
3
+ <h3><%=t '.title', :default => t('helpers.titles.define', :model => model_class.model_name.human,
4
+ :default => "Edit #{@content.slug or model_class.model_name.human}") %></h3>
5
+ </div>
6
+ <%= form_for @content, :html => { :class => 'form-horizontal' } do |f| %>
7
+ <% if @content.errors.any? %>
8
+ <div class="errors">
9
+ <h3>ERROR!</h3>
10
+ <ul>
11
+ <% @content.errors.full_messages.each do |msg| %>
12
+ <%= content_tag :li, msg %>
13
+ <% end %>
14
+ </ul>
15
+ </div>
16
+ <% end %>
17
+ <%= render :partial => 'fields_new', :locals => {f: f} %>
18
+ <%= render :partial => 'fields_edit', :locals => {f: f} %>
19
+ <hr/>
20
+ <h4>Seo</h4>
21
+ <%= f.fields_for :seo do |seo| %>
22
+ <%= render :partial => 'seo_fields', :locals => {f: seo} %>
23
+ <% end %>
24
+ <h4>Resources</h4>
25
+ <%= link_to_add_fields "Add Resource", f, :resources %>
26
+
27
+ <%= f.fields_for :resources do |res| %>
28
+ <%= render :partial => 'resource_fields', :locals => {f: res} %>
29
+ <% end %>
30
+ <h4>Children</h4>
31
+ <%= link_to_add_fields "Add Child", f, :child_contents %>
32
+ <%= render :partial => 'show_children', object: @content.child_contents %>
33
+ <div class="form-actions">
34
+ <%= f.submit nil, :class => 'btn btn-primary' %>
35
+ <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
36
+ contents_path, :class => 'btn' %>
37
+ </div>
38
+
39
+ <% end %>
40
+
41
+ <% content_for :breadcrumb do %>
42
+ <%= content_tag :anchor, @content.ancestry %>
43
+ <% end %>
44
+
@@ -0,0 +1,34 @@
1
+ <%- model_class = Content.new.class -%>
2
+ <div class="page-header">
3
+ <h1><%=t '.title', :default => model_class.model_name.human.pluralize %></h1>
4
+ </div>
5
+ <table class="table table-striped">
6
+ <thead>
7
+ <tr>
8
+ <th><%= model_class.human_attribute_name(:slug) %></th>
9
+ <th><%= model_class.human_attribute_name(:title) %></th>
10
+ <th><%=t '.actions', :default => t("helpers.actions") %></th>
11
+ </tr>
12
+ </thead>
13
+ <tbody>
14
+ <% @contents.each do |content| %>
15
+ <tr>
16
+ <td><%= link_to content.slug, content_path(content) %></td>
17
+ <td><%= content.title %></td>
18
+ <td>
19
+ <%= link_to t('.edit', :default => t("helpers.links.edit")),
20
+ edit_content_path(content), :class => 'btn btn-mini' %>
21
+ <%= link_to t('.destroy', :default => t("helpers.links.destroy")),
22
+ content_path(content),
23
+ :method => :delete,
24
+ :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')),
25
+ :class => 'btn btn-mini btn-danger' %>
26
+ </td>
27
+ </tr>
28
+ <% end %>
29
+ </tbody>
30
+ </table>
31
+
32
+ <%= link_to t('.new', :default => t("helpers.links.new")),
33
+ new_content_path,
34
+ :class => 'btn btn-primary' %>
@@ -0,0 +1,5 @@
1
+ xml.contents do
2
+ @contents.each do |c|
3
+ xml << render(:partial => 'content.xml.builder', object: c)
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ <%- model_class = @content.class -%>
2
+ <div class="page-header">
3
+ <h1><%=t '.title', :default => t('helpers.titles.new', :model => model_class.model_name.human,
4
+ :default => "New #{model_class.model_name.human}") %></h1>
5
+ </div>
6
+ <%= form_for @content, :url => contents_path, :as => :content, :html => { :class => 'form-horizontal' } do |f| %>
7
+ <%= render :partial => 'fields_new', :locals => {f: f} %>
8
+ <div class="form-actions">
9
+ <%= f.submit nil, :class => 'btn btn-primary' %>
10
+ <%= link_to t('.cancel', :default => t("helpers.links.cancel")),
11
+ contents_path, :class => 'btn' %>
12
+ </div>
13
+ <% end %>
@@ -0,0 +1,25 @@
1
+ <%- model_class = @content.class -%>
2
+ <div class="page-header">
3
+ <h1><%=t '.title', :default => "#{@content.title}" %></h1>
4
+ </div>
5
+
6
+ <dl class="dl-horizontal">
7
+ <dt><strong><%= model_class.human_attribute_name(:_type) %>:</strong></dt>
8
+ <dd><%= @content._type %></dd>
9
+ <dt><strong><%= model_class.human_attribute_name(:_id) %>:</strong></dt>
10
+ <dd><%= @content._id %></dd>
11
+ <dt><strong><%= model_class.human_attribute_name(:slug) %>:</strong></dt>
12
+ <dd><%= @content.slug %></dd>
13
+ </dl>
14
+
15
+ <div class="form-actions">
16
+ <%= link_to t('.back', :default => t("helpers.links.back")),
17
+ contents_path, :class => 'btn' %>
18
+ <%= link_to t('.edit', :default => t("helpers.links.edit")),
19
+ edit_content_path(@content.ancestry), :class => 'btn' %>
20
+ <%= link_to t('.destroy', :default => t("helpers.links.destroy")),
21
+ content_path(@content),
22
+ :method => 'delete',
23
+ :confirm => t('.confirm', :default => t("helpers.links.confirm", :default => 'Are you sure?')),
24
+ :class => 'btn btn-danger' %>
25
+ </div>
@@ -0,0 +1 @@
1
+ xml << render(partial:'content.xml.builder')
@@ -0,0 +1,64 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title><%= content_for?(:title) ? yield(:title) : "Common Content" %></title>
7
+ <%= csrf_meta_tags %>
8
+
9
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
10
+ <!--[if lt IE 9]>
11
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js" type="text/javascript"></script>
12
+ <![endif]-->
13
+
14
+ <%= stylesheet_link_tag "application", :media => "all" %>
15
+
16
+ <link href="images/favicon.ico" rel="shortcut icon">
17
+ <link href="images/apple-touch-icon.png" rel="apple-touch-icon">
18
+ <link href="images/apple-touch-icon-72x72.png" rel="apple-touch-icon" sizes="72x72">
19
+ <link href="images/apple-touch-icon-114x114.png" rel="apple-touch-icon" sizes="114x114">
20
+ </head>
21
+ <body>
22
+
23
+ <div class="navbar navbar-fixed-top">
24
+ <div class="navbar-inner">
25
+ <div class="container-fluid">
26
+ <a class="btn btn-navbar" data-target=".nav-collapse" data-toggle="collapse">
27
+ <span class="icon-bar"></span>
28
+ <span class="icon-bar"></span>
29
+ <span class="icon-bar"></span>
30
+ </a>
31
+ <a class="brand" href="#">Common Content</a>
32
+ <div class="container-fluid nav-collapse">
33
+ <ul class="nav">
34
+ <li><%= link_to "Contents", "/contents" %></li>
35
+ <li><%= link_to "Admin", "/admin" %></li>
36
+ <li><%= content_for?(:breadcrumb) ? yield(:breadcrumb) : '' %></li>
37
+ </ul>
38
+ </div><!--/.nav-collapse -->
39
+ </div>
40
+ </div>
41
+ </div>
42
+
43
+ <div class="container-fluid">
44
+ <div class="row-fluid">
45
+ <div class="span12">
46
+ <%= yield %>
47
+ </div>
48
+ </div><!--/row-->
49
+
50
+ <footer>
51
+ <p>&copy; 2012</p>
52
+ <h6 style="font-size:8px">view_paths = <%= controller.view_paths.entries %></h6>
53
+ <h6 style="font-size:8px">ancestry = <%= @content.try(:ancestry) %></h6>
54
+ </footer>
55
+
56
+ </div> <!-- /container -->
57
+
58
+ <!-- Javascripts
59
+ ================================================== -->
60
+ <!-- Placed at the end of the document so the pages load faster -->
61
+ <%= javascript_include_tag "application" %>
62
+
63
+ </body>
64
+ </html>