common-content 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.textile +55 -0
- data/Rakefile +29 -0
- data/app/assets/javascripts/application.js +15 -0
- data/app/assets/javascripts/bootstrap.js.coffee +0 -0
- data/app/assets/javascripts/contents.js.coffee +16 -0
- data/app/assets/javascripts/jquery-ui-1.8.21.custom.min.js +125 -0
- data/app/assets/stylesheets/application.css +7 -0
- data/app/assets/stylesheets/bootstrap_and_overrides.css.less +29 -0
- data/app/assets/stylesheets/contents.css.less +11 -0
- data/app/assets/stylesheets/scaffolds.css.less +62 -0
- data/app/controllers/contents_controller.rb +99 -0
- data/app/helpers/contents_helper.rb +29 -0
- data/app/models/content.rb +49 -0
- data/app/models/resource.rb +10 -0
- data/app/models/seo.rb +11 -0
- data/app/models/textile.rb +16 -0
- data/app/views/contents/_array_form.html.erb +14 -0
- data/app/views/contents/_child_content_fields.html.erb +14 -0
- data/app/views/contents/_content.xml.builder +4 -0
- data/app/views/contents/_fields_edit.html.erb +7 -0
- data/app/views/contents/_fields_new.html.erb +14 -0
- data/app/views/contents/_resource_fields.html.erb +21 -0
- data/app/views/contents/_seo_fields.html.erb +21 -0
- data/app/views/contents/_show_children.html.erb +10 -0
- data/app/views/contents/_textile_form.html.erb +1 -0
- data/app/views/contents/edit.html.erb +44 -0
- data/app/views/contents/index.html.erb +34 -0
- data/app/views/contents/index.xml.builder +5 -0
- data/app/views/contents/new.html.erb +13 -0
- data/app/views/contents/show.html.erb +25 -0
- data/app/views/contents/show.xml.builder +1 -0
- data/app/views/layouts/application.html.erb +64 -0
- data/config/routes.rb +9 -0
- data/lib/common-content.rb +4 -0
- data/lib/common-content/engine.rb +7 -0
- data/lib/common-content/version.rb +3 -0
- data/lib/tasks/common-content_tasks.rake +4 -0
- 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
|
data/app/models/seo.rb
ADDED
@@ -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,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,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>© 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>
|