spree_essential_cms 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/LICENSE +23 -0
  2. data/README.md +78 -0
  3. data/Rakefile +21 -0
  4. data/app/controllers/admin/contents_controller.rb +41 -0
  5. data/app/controllers/admin/page_images_controller.rb +37 -0
  6. data/app/controllers/admin/pages_controller.rb +38 -0
  7. data/app/controllers/page_controller.rb +19 -0
  8. data/app/controllers/pages_controller.rb +28 -0
  9. data/app/controllers/spree_base_controller_decorator.rb +11 -0
  10. data/app/models/content.rb +82 -0
  11. data/app/models/page.rb +61 -0
  12. data/app/models/page_image.rb +40 -0
  13. data/app/views/admin/contents/_form.html.erb +74 -0
  14. data/app/views/admin/contents/edit.html.erb +16 -0
  15. data/app/views/admin/contents/index.html.erb +59 -0
  16. data/app/views/admin/contents/new.html.erb +18 -0
  17. data/app/views/admin/contents/show.html.erb +11 -0
  18. data/app/views/admin/page_images/_form.html.erb +8 -0
  19. data/app/views/admin/page_images/edit.html.erb +20 -0
  20. data/app/views/admin/page_images/index.html.erb +42 -0
  21. data/app/views/admin/page_images/new.html.erb +20 -0
  22. data/app/views/admin/pages/_form.html.erb +73 -0
  23. data/app/views/admin/pages/edit.html.erb +14 -0
  24. data/app/views/admin/pages/index.html.erb +62 -0
  25. data/app/views/admin/pages/new.html.erb +16 -0
  26. data/app/views/admin/pages/show.html.erb +23 -0
  27. data/app/views/admin/shared/_page_tabs.html.erb +23 -0
  28. data/app/views/pages/home.html.erb +28 -0
  29. data/app/views/pages/show.html.erb +3 -0
  30. data/app/views/shared/_content.html.erb +33 -0
  31. data/app/views/shared/_main_menu.html.erb +7 -0
  32. data/app/views/shared/_slideshow.html.erb +8 -0
  33. data/config/locales/en.yml +55 -0
  34. data/config/routes.rb +38 -0
  35. data/lib/dummy_hooks/after_migrate.rb +1 -0
  36. data/lib/dummy_hooks/after_migrate.rb.sample +1 -0
  37. data/lib/dummy_hooks/before_migrate.rb +6 -0
  38. data/lib/generators/essentials_base.rb +23 -0
  39. data/lib/generators/spree_essentials/cms_generator.rb +17 -0
  40. data/lib/generators/templates/db/migrate/create_contents.rb +27 -0
  41. data/lib/generators/templates/db/migrate/create_pages.rb +24 -0
  42. data/lib/spree_essential_cms/version.rb +3 -0
  43. data/lib/spree_essential_cms.rb +43 -0
  44. metadata +236 -0
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Redistribution and use in source and binary forms, with or without modification,
2
+ are permitted provided that the following conditions are met:
3
+
4
+ * Redistributions of source code must retain the above copyright notice,
5
+ this list of conditions and the following disclaimer.
6
+ * Redistributions in binary form must reproduce the above copyright notice,
7
+ this list of conditions and the following disclaimer in the documentation
8
+ and/or other materials provided with the distribution.
9
+ * Neither the name of the Rails Dog LLC nor the names of its
10
+ contributors may be used to endorse or promote products derived from this
11
+ software without specific prior written permission.
12
+
13
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
21
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
22
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,78 @@
1
+ SpreeEssentialCms
2
+ =================
3
+
4
+ SpreeEssentialCms is a full featured CMS for managing pages and content on your [Spree](http://spreecommerce.com) site.
5
+
6
+
7
+ Installation
8
+ ------------
9
+
10
+ If you don't already have an existing Spree site, [click here](https://gist.github.com/946719) then come back later... You can also read the Spree docs [here](http://spreecommerce.com/documentation/getting_started.html)...
11
+
12
+ Otherwise, follow these steps to get up and running with SpreeEssentialCms:
13
+
14
+ Add the necessary gems to your Gemfile... they haven't been released to Rubygems yet so we'll grab them from git.
15
+
16
+ gem 'spree_essentials', :git => 'git://github.com/citrus/spree_essentials.git'
17
+ gem 'spree_essential_cms', :git => 'git://github.com/citrus/spree_essential_cms.git'
18
+
19
+ Run the generators to create the migration files.
20
+
21
+ rails g spree_essentials:install
22
+ rails g spree_essentials:cms
23
+
24
+ Now migrate your database...
25
+
26
+ rake db:migrate
27
+
28
+ Boot your server and checkout the admin!
29
+
30
+ rails s
31
+
32
+
33
+ Demo
34
+ ----
35
+
36
+ You can easily use the test/dummy app as a demo of spree_essential_cms. Just `cd` to where you develop and run:
37
+
38
+ git clone git://github.com/citrus/spree_essential_cms.git
39
+ cd spree_essential_cms
40
+ mv lib/dummy_hooks/after_migrate.rb.sample lib/dummy_hooks/after_migrate.rb
41
+ bundle install
42
+ bundle exec dummier
43
+ cd test/dummy
44
+ rails s
45
+
46
+
47
+ Change Log
48
+ ----------
49
+
50
+ **2011/4/26**
51
+
52
+ * Extracted from the Spree Essentials core.
53
+
54
+
55
+ To Do
56
+ -----
57
+
58
+ * more tests... many many more.
59
+ * A 'create translation' button that clones the current page's contents into another language
60
+ * add widgets that you can drop into any page
61
+ * page and menu caching/sweeping
62
+ * nested set for pages
63
+ * 0.30 and 0.40 compatibility
64
+ * create wiki pages
65
+
66
+
67
+ Contributors
68
+ ------------
69
+
70
+ So far it's just me; Spencer Steffen.
71
+
72
+ If you'd like to help out feel free to fork and send me pull requests!
73
+
74
+
75
+ License
76
+ -------
77
+
78
+ Copyright (c) 2011 Spencer Steffen, released under the New BSD License All rights reserved.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must run `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rake'
10
+ require 'rake/testtask'
11
+
12
+ Bundler::GemHelper.install_tasks
13
+
14
+ Rake::TestTask.new(:test) do |t|
15
+ t.libs << 'lib'
16
+ t.libs << 'test'
17
+ t.pattern = 'test/**/*_test.rb'
18
+ t.verbose = false
19
+ end
20
+
21
+ task :default => :test
@@ -0,0 +1,41 @@
1
+ class Admin::ContentsController < Admin::BaseController
2
+
3
+ resource_controller
4
+ belongs_to :page
5
+
6
+ create.response do |wants|
7
+ wants.html { redirect_to collection_url }
8
+ end
9
+
10
+ update.response do |wants|
11
+ wants.html { redirect_to collection_url }
12
+ end
13
+
14
+ def update_positions
15
+ @page = parent_object
16
+ params[:positions].each do |id, index|
17
+ @page.contents.update_all(['position=?', index], ['id=?', id])
18
+ end
19
+
20
+ respond_to do |format|
21
+ format.html { redirect_to admin_page_contents_url(@oage) }
22
+ format.js { render :text => 'Ok' }
23
+ end
24
+ end
25
+
26
+ destroy.success.wants.js { render_js_for_destroy }
27
+
28
+ private
29
+
30
+ def parent_object
31
+ @page ||= Page.find_by_path(params[:page_id])
32
+ end
33
+
34
+ def collection
35
+ params[:search] ||= {}
36
+ params[:search][:meta_sort] ||= "page.asc"
37
+ @search = end_of_association_chain.metasearch(params[:search])
38
+ @collection = @search.paginate(:per_page => Spree::Config[:orders_per_page], :page => params[:page])
39
+ end
40
+
41
+ end
@@ -0,0 +1,37 @@
1
+ class Admin::PageImagesController < Admin::ResourceController
2
+
3
+ before_filter :load_data
4
+
5
+ create.before :set_viewable
6
+ update.before :set_viewable
7
+ destroy.before :destroy_before
8
+
9
+ def update_positions
10
+ params[:positions].each do |id, index|
11
+ PageImage.update_all(['position=?', index], ['id=?', id])
12
+ end
13
+
14
+ respond_to do |format|
15
+ format.js { render :text => 'Ok' }
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def location_after_save
22
+ admin_page_images_url(@page)
23
+ end
24
+
25
+ def load_data
26
+ @page = Page.find_by_path(params[:page_id])
27
+ end
28
+
29
+ def set_viewable
30
+ @page_image.viewable = @page
31
+ end
32
+
33
+ def destroy_before
34
+ @viewable = @page_image.viewable
35
+ end
36
+
37
+ end
@@ -0,0 +1,38 @@
1
+ class Admin::PagesController < Admin::BaseController
2
+ resource_controller
3
+
4
+ create.response do |wants|
5
+ wants.html { redirect_to edit_admin_page_content_path(@page, @page.contents.first) }
6
+ end
7
+
8
+ update.response do |wants|
9
+ wants.html { redirect_to object_url }
10
+ end
11
+
12
+ destroy.success.wants.js { render_js_for_destroy }
13
+
14
+ def update_positions
15
+ params[:positions].each do |id, index|
16
+ Page.update_all(['position=?', index], ['id=?', id])
17
+ end
18
+
19
+ respond_to do |format|
20
+ format.html { redirect_to admin_pages_url }
21
+ format.js { render :text => 'Ok' }
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def object
28
+ @object ||= Page.find_by_path(params[:id])
29
+ end
30
+
31
+ def collection
32
+ params[:search] ||= {}
33
+ params[:search][:meta_sort] ||= "page.asc"
34
+ @search = end_of_association_chain.metasearch(params[:search])
35
+ @collection = @search.order(:position).paginate(:per_page => Spree::Config[:orders_per_page], :page => params[:page])
36
+ end
37
+
38
+ end
@@ -0,0 +1,19 @@
1
+ class PageController < ApplicationController
2
+
3
+ before_filter :get_page, :only => :index
4
+
5
+ def show
6
+ end
7
+
8
+ private
9
+
10
+ def get_page
11
+ @page = Page.active.find_by_path(page_path)
12
+ return raise ActionController::RoutingError.new(page_path) unless @page
13
+ end
14
+
15
+ def page_path
16
+ params[:path] || "/"
17
+ end
18
+
19
+ end
@@ -0,0 +1,28 @@
1
+ class PagesController < ApplicationController
2
+
3
+ before_filter :get_page, :only => :show
4
+
5
+ def show
6
+ if @page.root?
7
+ @posts = Post.live.limit(5) if SpreeEssentials.has?(:blog)
8
+ @articles = Article.live.limit(5) if SpreeEssentials.has?(:news)
9
+ render :template => 'pages/home'
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def get_page
16
+ @page = Page.active.find_by_path(page_path) rescue nil
17
+ return raise ActionController::RoutingError.new(page_path) unless @page
18
+ end
19
+
20
+ def page_path
21
+ params[:page_path] || "/"
22
+ end
23
+
24
+ def accurate_title
25
+ @page.meta_title
26
+ end
27
+
28
+ end
@@ -0,0 +1,11 @@
1
+ Spree::BaseController.class_eval do
2
+
3
+ before_filter :get_pages
4
+
5
+ def get_pages
6
+ @page = Page.find_by_path(request.path) rescue nil
7
+ scope = request.path =~ /^\/admin/ ? Page.scoped : Page.visible
8
+ @pages = scope.order(:position).all
9
+ end
10
+
11
+ end
@@ -0,0 +1,82 @@
1
+ class Content < ActiveRecord::Base
2
+
3
+ belongs_to :page
4
+ validates_associated :page
5
+ validates_presence_of :title
6
+
7
+
8
+ if defined?(SpreeHeroku)
9
+ has_attached_file :attachment,
10
+ :styles => Proc.new{ |clip| clip.instance.attachment_sizes },
11
+ :default_style => :preview,
12
+ :path => "assets/contents/:id/:style/:basename.:extension",
13
+ :storage => "s3",
14
+ :s3_credentials => "#{Rails.root}/config/s3.yml"
15
+ else
16
+ has_attached_file :attachment,
17
+ :styles => Proc.new{ |clip| clip.instance.attachment_sizes },
18
+ :default_style => :preview,
19
+ :url => "/assets/contents/:id/:style/:basename.:extension",
20
+ :path => ":rails_root/public/assets/contents/:id/:style/:basename.:extension"
21
+ end
22
+
23
+
24
+ cattr_reader :per_page
25
+ @@per_page = 10
26
+
27
+
28
+ scope :for, Proc.new{|context| where(:context => context)}
29
+
30
+
31
+ [ :link_text, :link, :body ].each do |property|
32
+ define_method "has_#{property.to_s}?" do
33
+ has_value property
34
+ end
35
+ end
36
+
37
+ def has_full_link?
38
+ has_link? && has_link_text?
39
+ end
40
+
41
+ def has_image?
42
+ has_value(:attachment_file_name) && attachment_file_name.match(/gif|jpg|png/i)
43
+ end
44
+
45
+ def hide_title?
46
+ self.hide_title == true
47
+ end
48
+
49
+
50
+ def rendered_body
51
+ RDiscount.new(body.to_s).to_html.html_safe
52
+ end
53
+
54
+
55
+ def default_attachment_sizes
56
+ { :mini => '48x48>', :medium => '427x287>' }
57
+ end
58
+
59
+ def attachment_sizes
60
+ case self.context
61
+ when 'slideshow'
62
+ sizes = default_attachment_sizes.merge(:slide => '955x476#')
63
+ else
64
+ sizes = default_attachment_sizes
65
+ end
66
+ sizes
67
+ end
68
+
69
+
70
+
71
+ def context=(value)
72
+ write_attribute :context, value.to_s.parameterize
73
+ end
74
+
75
+ private
76
+
77
+ def has_value(selector)
78
+ v = self.send selector
79
+ v && !v.to_s.blank?
80
+ end
81
+
82
+ end
@@ -0,0 +1,61 @@
1
+ class Page < ActiveRecord::Base
2
+
3
+ validates_presence_of :title
4
+ validates :path, :presence => true, :uniqueness => { :case_sensitive => false }
5
+
6
+ scope :active, where(:accessible => true)
7
+ scope :visible, active.where(:visible => true)
8
+
9
+ has_many :contents, :order => :position, :dependent => :destroy
10
+ has_many :images, :as => :viewable, :class_name => 'PageImage', :order => :position, :dependent => :destroy
11
+
12
+ before_validation :set_defaults
13
+ after_create :create_default_content
14
+
15
+ def self.find_by_path(_path)
16
+ return super("/") if _path == 'home'
17
+ super(_path.to_s.sub(/^\/?/, '/').gsub('--', '/'))
18
+ end
19
+
20
+ def to_param
21
+ return 'home' if path == '/'
22
+ path.sub(/^\//, '').gsub('/', '--')
23
+ end
24
+
25
+ def meta_title
26
+ val = read_attribute(:meta_title)
27
+ val.blank? ? title : val
28
+ end
29
+
30
+ def for_context(context)
31
+ contents.where(:context => context)
32
+ end
33
+
34
+ def has_context?(context)
35
+ contents.where(:context => context).count
36
+ end
37
+
38
+ def matches?(_path)
39
+ (root? && _path == "/") || (!root? && _path.match(path))
40
+ end
41
+
42
+ def root?
43
+ self.path == "/"
44
+ end
45
+
46
+ private
47
+
48
+ def set_defaults
49
+ return if title.blank?
50
+ return errors.add(:path, "is reserved. Please use another") if path.to_s =~ /home/
51
+ self.nav_title = title if nav_title.blank?
52
+ self.path = nav_title.parameterize if path.blank?
53
+ self.path = "/" + path.sub(/^\//, '')
54
+ end
55
+
56
+ def create_default_content
57
+ self.contents.create(:title => title)
58
+ end
59
+
60
+ end
61
+
@@ -0,0 +1,40 @@
1
+ class PageImage < Image
2
+
3
+ validate :no_attachement_errors
4
+
5
+ if defined?(SpreeHeroku)
6
+ has_attached_file :attachment,
7
+ :styles => Proc.new{ |clip| clip.instance.attachment_sizes },
8
+ :default_style => :medium,
9
+ :path => "assets/posts/:id/:style/:basename.:extension",
10
+ :storage => "s3",
11
+ :s3_credentials => "#{Rails.root}/config/s3.yml"
12
+ else
13
+ has_attached_file :attachment,
14
+ :styles => Proc.new{ |clip| clip.instance.attachment_sizes },
15
+ :default_style => :medium,
16
+ :url => "/assets/posts/:id/:style/:basename.:extension",
17
+ :path => ":rails_root/public/assets/posts/:id/:style/:basename.:extension"
18
+ end
19
+
20
+ def image_content?
21
+ attachment_content_type.match(/\/(jpeg|png|gif|tiff|x-photoshop)/)
22
+ end
23
+
24
+ def attachment_sizes
25
+ sizes = {}
26
+ sizes.merge!(:mini => '48x48>', :small => '150x150>', :medium => '420x300>', :large => '900x650>') if image_content?
27
+ sizes.merge!(:slide => '950x250#') if viewable.respond_to?(:path) && viewable.path == "/"
28
+ sizes
29
+ end
30
+
31
+ def no_attachement_errors
32
+ unless attachment.errors.empty?
33
+ # uncomment this to get rid of the less-than-useful interrim messages
34
+ errors.clear
35
+ errors.add :attachment, "Paperclip returned errors for file '#{attachment_file_name}' - check ImageMagick installation or image source file."
36
+ false
37
+ end
38
+ end
39
+
40
+ end
@@ -0,0 +1,74 @@
1
+ <%= form.field_container :title do %>
2
+ <%= form.label :title, t('content.title') %><br />
3
+ <%= form.text_field :title, :class => "title" %>
4
+ <%= error_message_on :content, :title %>
5
+ <% end %>
6
+
7
+ <%= form.field_container :page do %>
8
+ <%= form.label :page_id, t('content.page') %><br />
9
+ <%= form.select :page_id, @pages.collect{|i| [i.title, i.id]} %>
10
+ <%= error_message_on :content, :page_id %>
11
+ <% end %>
12
+
13
+ <%= form.field_container :body do %>
14
+ <%= form.label :title, t('content.body') %><%= markdown_helper %><br />
15
+ <%= form.text_area :body %>
16
+ <%= error_message_on :content, :body %>
17
+ <% end %>
18
+
19
+ <p><%= link_to "Optional Fields <span>&#9650;</span>".html_safe, "#options", :id => "btn_optional" %></p>
20
+
21
+ <div class="optional" style="display: none;">
22
+
23
+ <%= form.field_container :attachment do %>
24
+ <%= form.label :attachment, t('content.attachment') %><br />
25
+ <%= form.file_field :attachment %>
26
+ <%= error_message_on :content, :attachment %>
27
+ <% end %>
28
+
29
+ <% if @content.has_image? %>
30
+ <p><%= image_tag @content.attachment.url(:mini) %></p>
31
+ <% end %>
32
+
33
+ <%= form.field_container :link do %>
34
+ <%= form.label :link, t('content.link') %><br />
35
+ <%= form.text_field :link, :class => "text" %>
36
+ <%= error_message_on :content, :link %>
37
+ <% end %>
38
+
39
+ <%= form.field_container :link_text do %>
40
+ <%= form.label :link_text, t('content.link_text') %><br />
41
+ <%= form.text_field :link_text, :class => "text" %>
42
+ <%= error_message_on :content, :link_text %>
43
+ <% end %>
44
+
45
+ <%= form.field_container :context do %>
46
+ <%= form.label :context, t('content.context') %><br />
47
+ <%= form.text_field :context, :class => "text" %>
48
+ <%= error_message_on :content, :context %>
49
+ <% end %>
50
+
51
+ <%= form.field_container :hide_title do %>
52
+ <%= form.check_box :hide_title, :class => "checkbox" %>
53
+ <%= form.label :hide_title, t('content.hide_title') %><br />
54
+ <%= error_message_on :content, :hide_title %>
55
+ <% end %>
56
+
57
+ </div>
58
+
59
+ <% content_for :head do %>
60
+ <%= stylesheet_link_tag "markitup.css" %>
61
+ <%= javascript_include_tag 'jquery.markitup.js', 'markdown.set.js' %>
62
+ <script type="text/javascript">
63
+ //<![CDATA[
64
+ $(document).ready(function() {
65
+ $('#content_body').markItUp(markdownSettings);
66
+ $('#btn_optional').click(function(evt) {
67
+ evt.preventDefault();
68
+ var vis = $('.optional').toggle().css('display') == 'block';
69
+ $(this).find('span').html(vis ? '&#9660;' : '&#9650;');
70
+ });
71
+ });
72
+ //]]>
73
+ </script>
74
+ <% end %>
@@ -0,0 +1,16 @@
1
+ <%= render :partial => 'admin/shared/contents_sub_menu' %>
2
+
3
+ <%= render :partial => 'admin/shared/page_tabs', :locals => {:current => 'Contents'} %>
4
+
5
+ <% if @content.try(:errors).present? %>
6
+ <%= render 'shared/error_messages', :target => @content %>
7
+ <% end %>
8
+
9
+ <h2><%= t('.edit_content') %></h2>
10
+
11
+ <%= form_for([:admin, @page, @content], :html => { :multipart => true }) do |f| %>
12
+ <%= render "form", :form => f %>
13
+ <p class="form-buttons">
14
+ <%= button t("update") %> <%= t('or') %> <%= link_to t('cancel'), collection_url %>
15
+ </p>
16
+ <% end %>
@@ -0,0 +1,59 @@
1
+ <%= render :partial => 'admin/shared/contents_sub_menu' %>
2
+
3
+ <div class='toolbar'>
4
+ <ul class='actions'>
5
+ <li>
6
+ <p><%= button_link_to t('.new_content'), new_object_url, :icon => 'add' %></p>
7
+ </li>
8
+ </ul>
9
+ <br class='clear' />
10
+ </div>
11
+
12
+ <%= render :partial => 'admin/shared/page_tabs', :locals => {:current => 'Contents'} %>
13
+
14
+ <h2><%= t('.listing_contents') %></h2>
15
+
16
+ <table class="index sortable">
17
+ <thead>
18
+ <tr>
19
+ <th><%= sort_link @search, :title, t("content.title") %></th>
20
+ <th><%= sort_link @search, :context, t("content.context") %></th>
21
+ <th><%= t("action") %></th>
22
+ </tr>
23
+ </thead>
24
+ <tbody>
25
+ <%- @collection.each do |content|%>
26
+ <tr id="<%= dom_id content %>">
27
+ <td><span class="handle">&nbsp;</span>&nbsp; <%= link_to content.title, object_url(content) %></td>
28
+ <td><%= content.context %>
29
+ <td>
30
+ <%= link_to_edit content %> &nbsp;
31
+ <%= link_to_delete content %>
32
+ </td>
33
+ </tr>
34
+ <% end %>
35
+ </tbody>
36
+ </table>
37
+
38
+ <%= will_paginate(@contents, :prev => "&#171; #{t('previous')}", :next => "#{t('next')} &#187;") %>
39
+
40
+ <% content_for :sidebar do %>
41
+
42
+ <div class="box">
43
+ <h3><%= t(:search) %></h3>
44
+
45
+ <% @content = Content.metasearch %>
46
+ <%= form_for [:admin, @page, @content] do |f| %>
47
+ <%- locals = {:f => f} %>
48
+ <%= hook :admin_contents_index_search, locals do %>
49
+ <p>
50
+ <label><%= t('content.title') %></label><br />
51
+ <%= f.text_field :title_like, :size => 25 %>
52
+ </p>
53
+ <% end %>
54
+ <%= hook :admin_contents_index_search_buttons, locals do %>
55
+ <p><%= button t("search") %></p>
56
+ <% end %>
57
+ <% end %>
58
+ </div>
59
+ <% end %>
@@ -0,0 +1,18 @@
1
+ <%= render :partial => 'admin/shared/contents_sub_menu' %>
2
+
3
+ <%= render :partial => 'admin/shared/page_tabs', :locals => {:current => 'Contents'} %>
4
+
5
+ <% if @content.try(:errors).present? %>
6
+ <%= render 'shared/error_messages', :target => @content %>
7
+ <% end %>
8
+
9
+ <h2><%= t('.new_content') %></h2>
10
+
11
+ <% form_for([:admin, @page, @content], :html => { :multipart => true }) do |f| %>
12
+ <%= render "form", :form => f %>
13
+
14
+ <p class="form-buttons">
15
+ <%= button t("create") %> <%= t('or') %> <%= link_to t('cancel'), collection_url %>
16
+ </p>
17
+ <% end %>
18
+
@@ -0,0 +1,11 @@
1
+ <%= render :partial => 'admin/shared/contents_sub_menu' %>
2
+ <%= render :partial => 'admin/shared/page_tabs', :locals => {:current => 'Contents'} %>
3
+
4
+ <h2><%= h @content.title %></h2>
5
+
6
+ <%= RDiscount.new(@content.body).to_html.html_safe %>
7
+
8
+ <p>
9
+ <%= link_to_edit @user %> &nbsp;
10
+ <%= link_to t('back'), collection_url %>
11
+ </p>
@@ -0,0 +1,8 @@
1
+ <p>
2
+ <%= form.label :attachment %>:<br/>
3
+ <%= form.file_field :attachment %>
4
+ </p>
5
+ <p>
6
+ <%= form.label :alt %>:<br/>
7
+ <%= form.text_field :alt %>
8
+ </p>