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.
- 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>
|